风雨同舟 · 1 天前

【Mini-F5375-OB开发板评测】FreeRTOS的命令行接口(CLI)组件移植到开发板

1.前言

参考:https://blog.csdn.net/sinat_3... ,本文详细介绍了如何将FreeRTOS的命令行接口(CLI)组件移植到Mini-F5375-OB开发板上,通过串口中断实现命令交互。内容包括下载参考源码、移植CLI组件、实现串口初始化及中断,到注册并执行自定义命令(如hello、led控制和sum计算)的全过程。CLI的使用大大方便了单片机的调试和维护。

2. 下载参考代码

为了实现类似RT-Thread类似的控制台功能,在FreeRTOS下有一个cli组件,根据参考文献是移植到GD32F107单片机上,本文直接将从https://gitee.com/yvany/gd_fr...下载源码,直接复制cli目录下的几个文件,在此基础上进行cli组件的移植。
image.png

将上述文件下载下来,放到上一篇帖子提到的FreeRTOS_Blinky工程下,新建一个cli目录,将6个文件放入该文件夹。在MDK下增加组,更名为cli.
image.png
然后将cli目录下的源文件添加到工程中。
image.png

3.移植代码

打开serial.c,修改其中的与串口相关代码。修改xSerialPortInitMinimal函数,使用开发板上的USART3串口。并开启接收中断。修改后的代码如下:

xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
{
xComPortHandle xReturn;


    /* Create the queues used to hold Rx/Tx characters. */
    xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
    xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
    
    /* If the queue/semaphore was created correctly then setup the serial port
    hardware. */
    if( ( xRxedChars != serINVALID_QUEUE ) && ( xCharsForTx != serINVALID_QUEUE ) )
    {
        /* Enable USART3 */
        GPIO_InitTypeDef GPIO_InitStruct;
        NVIC_InitTypeDef  NVIC_InitStruct;
        USART_InitTypeDef USART_InitStruct;

        // 1. 先使能GPIO时钟 (AHB总线)
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
        
        // 2. 配置TX引脚(PC10)
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_7);  // PC10复用为UART3_TX
        GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_10;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
        GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;         // 复用推挽输出
        GPIO_Init(GPIOC, &GPIO_InitStruct);

        // 3. 配置RX引脚(PC11)
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_7);  // PC11复用为UART3_RX
        GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_11;
        GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_FLOATING;       // 复用输入模式
        GPIO_Init(GPIOC, &GPIO_InitStruct);
        
            // 4. 使能UART3时钟 (APB1总线)
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

        USART_StructInit(&USART_InitStruct);
        USART_InitStruct.USART_BaudRate   = 115200;
        USART_InitStruct.USART_WordLength = USART_WordLength_8b;
        USART_InitStruct.USART_StopBits   = USART_StopBits_1;
        USART_InitStruct.USART_Parity     = USART_Parity_No;
        USART_InitStruct.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;
        USART_Init(USART3, &USART_InitStruct);
        
        // 配置USART3中断优先级
        NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);

        // 只使能USART3接收中断,不使能发送中断
        USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
        // USART_ITConfig(USART3, USART_IT_TXE, ENABLE); // 不使能发送中断
    }
    else
    {
        xReturn = ( xComPortHandle ) 0;
    }

    /* This demo file only supports a single port but we have to return
    something to comply with the standard demo header file. */
    return xReturn;
}
然后修改USART3串口中断函数,处理接收中断

void USART3_IRQHandler( void )
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    uint8_t RxData = 0;

    // 处理接收中断
    if (RESET != USART_GetITStatus(USART3, USART_IT_RXNE))
    {
        RxData = USART_ReceiveData(USART3);
        xQueueSendFromISR(xRxedChars, &RxData, &xHigherPriorityTaskWoken);
        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
    }

}

同时,也需要修改串口发送函数为使用USART3

signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime )
{
signed portBASE_TYPE xReturn;

    if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) == pdPASS )
    {
        xReturn = pdPASS;
        
        uint8_t cChar;
        
    /*修改:发送队列中有数据,通过轮询方式发送出去 */
    if(xQueueReceive(xCharsForTx, &cChar, 0) == pdTRUE) {
            USART_SendData(USART3, (uint8_t)cChar);
            while (RESET == USART_GetFlagStatus(USART3, USART_FLAG_TC));        
        }
    }
    else
    {
        xReturn = pdFAIL;
    }

    return xReturn;
}

修改后,编译代码
image.png

4. 增加通过命令行开关LED的命令

在Sample-CLI-command.c中,有2个控制led的外部函数,需要修改为对应开发板上的LED控制
image.png

打开platform.c,在其中增加2个函数,并在platform.h中进行声明
image.png

编译通过后,下载到开发板。打开串口中断MobaXterm,选择对应串口,可以看到FreeRTOS的Clit提示信息,输入help回车,会打印已有命令。
image.png

输入led on 回车,可以看到2个LED同时亮起,输入led off 回车,2个LED同时熄灭
20250619_155137.gif

  1. 增加TAB键显示帮助的功能
    仿照RT-Thread控制台,按下Tab键后可以显示帮助信息,显示当前可用命令的方式,添加功能。打开UARTCommandConsole.c,在prvUARTCommandConsoleTask的代码中增加对Tab键的处理:

    else if( cRxedChar == '\t' )
                 {
                     /* 按下Tab时,回显help与>在同一行,tab键本身不显示 */
                     vSerialPutString( xPort, "\bhelp", 5 );
                     strcpy(cInputString, "help");
                     ucInputIndex = strlen("help");
                     BaseType_t xReturnedTab;
                     do
                     {
                         xReturnedTab = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
                         vSerialPutString( xPort, pcOutputString, ( unsigned short ) strlen( pcOutputString ) );
                     } while( xReturnedTab != pdFALSE );
                     strcpy( cLastInputString, cInputString );
                     ucInputIndex = 0;
                     memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
                     vSerialPutString( xPort, pcEndOfOutputMessage, ( unsigned short ) strlen( pcEndOfOutputMessage ) );
                 }

    编译重新下载,通过控制台测试tab键功能。

    6. 结束语

    通过参考网络资料,移植了FreeRTOS的cli命令行处理组件到Mini-F5375-OB开发板,测试控制led开关的命令,增加了Tab键显示帮助的命令。通过命令行控制台,可以帮助我们更好的调试代码,增加软件灵活性。

推荐阅读
关注数
0
文章数
2
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息