[MCU] 【HC32F460开发板测评】03.基于UART功能实现SHELL的移植与控制

xld0932   2021-4-8 23:24 楼主

本篇主要实现的是掌握USART通讯,能够实现数据的收发操作,串口的接收使用中断机制;基于USART功能添加SHELL程序,通过操作LED灯来实现一个简单的SHELL控制调用。

 

1.USART通讯

开发板上提供了USB转UART部分的硬件电路,我们只需要一根Micro USB线将开发板与电脑进行连接,WIN10系统电脑会自动识别并安装USB转串口有驱动程序,再结合MCU的USART3接口,可以实现MCU与电脑端的串口数据通讯;

image-20210408230932-1.png

USART初始化配置程序:将USART配置成115200(波特率),N(校验位),8(数据位),1(停止位),使能串口的接收和发送功能,使能接收中断功能并配置接收中断;配置GPIO引脚复用成USART功能引脚,如下程序所示:

/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void UsartRxIrqCallback(void)
{
    printf("%c", USART_RecData(M4_USART3));
    USART_FuncCmd(M4_USART3, UsartTxAndTxEmptyInt, Enable);
}


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void UsartErrIrqCallback(void)
{
    if(USART_GetStatus(M4_USART3, UsartFrameErr)   != Reset)
    {
        USART_ClearStatus(M4_USART3, UsartFrameErr);
    }

    if(USART_GetStatus(M4_USART3, UsartParityErr)  != Reset)
    {
        USART_ClearStatus(M4_USART3, UsartParityErr);
    }

    if(USART_GetStatus(M4_USART3, UsartOverrunErr) != Reset)
    {
        USART_ClearStatus(M4_USART3, UsartOverrunErr);
    }
}


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void USART3_Configure(void)
{
    stc_irq_regi_conf_t stcIrqRegiCfg;

    const stc_usart_uart_init_t stcInitCfg =
    {
        UsartIntClkCkNoOutput,
        UsartClkDiv_1,
        UsartDataBits8,
        UsartDataLsbFirst,
        UsartOneStopBit,
        UsartParityNone,
        UsartSamleBit8,
        UsartStartBitFallEdge,
        UsartRtsEnable,
    };

    /* Enable peripheral clock */
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USART3, Enable);

    /* Initialize USART IO */
    PORT_SetFunc(PortE, Pin04, Func_Usart3_Rx, Disable);
    PORT_SetFunc(PortE, Pin05, Func_Usart3_Tx, Disable);

    /* Initialize UART */
    if(USART_UART_Init(M4_USART3, &stcInitCfg) != Ok)
    {
        while(1);
    }

    /* Set baudrate */
    if(USART_SetBaudrate(M4_USART3, 115200) != Ok)
    {
        while(1);
    }

    /* Set USART RX IRQ */
    stcIrqRegiCfg.enIRQn      = Int000_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartRxIrqCallback;
    stcIrqRegiCfg.enIntSrc    = INT_USART3_RI;
    enIrqRegistration(&stcIrqRegiCfg);

    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /* Set USART RX error IRQ */
    stcIrqRegiCfg.enIRQn      = Int001_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartErrIrqCallback;
    stcIrqRegiCfg.enIntSrc    = INT_USART3_EI;
    enIrqRegistration(&stcIrqRegiCfg);

    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /*Enable RX && RX interupt && TX function*/
    USART_FuncCmd(M4_USART3, UsartRx,    Enable);
    USART_FuncCmd(M4_USART3, UsartRxInt, Enable);
    USART_FuncCmd(M4_USART3, UsartTx,    Enable);
}


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
int fputc(int ch, FILE *f)
{
    USART_SendData(M4_USART3, (uint8_t)ch);
    while(Reset == USART_GetStatus(M4_USART3, UsartTxEmpty));

    return ch;
}

 

通过上面的程序,我们可以看到在接收中断函数中,接收到的数据又通过printf函数再次打印出来,printf函数是通过USART发送功能重载fputc这个函数来实现的, 运行结果如下图所示:

image-20210408231242-2.png

我们在控制LED闪烁的时候使用了Ddl_Delay1ms这个函数,这个是在ddl.config.h文件中通过配置DDL_UTILITY_ENABLE宏为DDL_ON才可以使用的;在使能DDL_UTILITY_ENABLE这个宏之后,在hc32f46x_utility.h 文件中默认定义了UART_DEBUG_PRINTF这个宏,所以导致在我们重载fputc这个函数的时候会报错,所以我样在hc32f46x_utility.h文件中把这个宏注释掉就可以了。

 

2.移植SHELL

下载SHELL开源源代码:https://github.com/NevermindZZT/letter-shell,最新的版本是3.0的,程序中使用的是2.x的版本;在官网上有详细的功能、移植、配置,以及相应的应用说明,大家可以去深入了解,我们这边还是结合HC32F460来实现应用移植;在工程中添加letter shell 2.x的源文件,添加自定义的shell_port.c和shell_port.h这两个文件,将之前的串口初始化程序移动到这个.c文件中来实现;移植过程如下:

  • 定义一个shell结构体对象;
  • 实现这个结构体中write的实现,即通过串口打印输出一个字节数据;
  • 调用shellInit函数进行初始化;
  • 在串口接收中断回调函数中调用shellHandler函数,将串口接收到的数据传递到这个函数中进行解析处理;

这样我们最单的SHELL框架就移植完成了;尝试编译运行一下,如下图所示:

image.png

具体的代码实现可以参考最后的附件工程源代码部分。

 

3.SHELL控制

结合上篇的LED闪烁的实验,我们通过调用SHELL自定义的命令来控制LED闪烁的起停动作,具体实现如下程序:

/* Private variables ---------------------------------------------------------*/
uint8_t LED_ToggleEnable = 1;


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void LED_Toggle(void)
{
    if(LED_ToggleEnable)
    {
        LED0_TOGGLE();  Ddl_Delay1ms(100);
        LED1_TOGGLE();  Ddl_Delay1ms(100);
        LED2_TOGGLE();  Ddl_Delay1ms(100);
        LED3_TOGGLE();  Ddl_Delay1ms(100);
    }
}


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void LED_StartToggle(void)
{
    LED_ToggleEnable = 1;
}
SHELL_EXPORT_CMD(start, LED_StartToggle, led start toggle);


/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void LED_StopToggle(void)
{
    LED_ToggleEnable = 0;
}
SHELL_EXPORT_CMD(stop, LED_StopToggle, led stop  toggle);


 

4.运行结果


 

 

5.工程源代码

Project_USART_SHELL.zip (820.79 KB)
(下载次数: 38, 2021-4-8 23:19 上传)

 

 

本帖最后由 xld0932 于 2021-4-8 23:32 编辑
We are a team and we work as a team !

回复评论 (5)

厉害了!还没尝试过shell的移植,有机会试一下!!!感谢分享!

点赞  2021-4-10 16:36

谢谢分享,freertos搞的全家桶也有个freertos-cli的组件。

默认摸鱼,再摸鱼。2022、9、28
点赞  2021-4-12 22:46

厉害了,感谢分享

点赞  2021-6-21 20:29
求加好友,我正在使用华大mcu,目前有一些困惑。
点赞  2021-11-16 16:53
我自己也使用usart1实现了类似shell命令行的功能
点赞  2021-11-16 16:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复