FreeRTOS 教程:添加命令行实现
FreeRTOS不像RT-Thread那样内置了类似Finsh的命令行组件,但官方提供了CLI(Command Line Interface)示例及相关API,供需要者参考和实现。在这篇文章中,我们将介绍如何在STM32F103系列上移植FreeRTOS的CLI,并添加自定义命令行功能。
一、准备工作
- 新建项目文件夹 首先,在您的项目目录中创建一个用于存放RTOS文件的文件夹,这里命名为
rtos
。
- 下载FreeRTOS源码 从FreeRTOS的GitHub仓库下载最新的源码包,并将其中的
source
文件夹拷贝到rtos
目录下。文件结构如下:
include
: 头文件目录portable
: 硬件接口相关文件夹(包括芯片接口、内存管理等)Keil
: ARM-MDK IDE的启动文件(硬件接口)MemMang
: 内存管理相关RVDS
和GCC
: 不同编译环境的启动文件
*.c
: FreeRTOS的核心源文件
二、移植CLI命令行
-
拷贝文件 将CLI示例中的两个文件
UARTCommandConsole.c
和Sample-CLI-commands.c
拷贝到您的工程目录下。
-
处理依赖 打开
UARTCommandConsole.c
,查看其依赖关系。发现需要FreeRTOS_CLI.h
和serial.h
两个头文件。
-
拷贝serial相关文件 将
serial.h
和serial.c
文件拷贝到工程目录中。serial.h
可以在FreeRTOS/Demo/Common/include
找到,而serial.c
根据实际板子及编译器情况,可以在对应(或相近)的示例路径下找到,例如STM32F103系列的serial.c
在FreeRTOS/Demo/CORTEX_STM32F103_Keil/serial
路径下。
-
拷贝FreeRTOS_CLI相关文件 将
FreeRTOS_CLI.c
和FreeRTOS_CLI.h
文件从FreeRTOS/FreeRTOS-Plus/Source/FreeRTOS-Plus-CLI
目录下拷贝到工程目录中。
-
添加依赖 确认上述文件的依赖已添加完毕,在MDK工程中为CLI添加一个独立的Group,并将上述文件添加到Group中,同时添加头文件路径。
三、编译与调试
-
编译 进行初次编译,若报错提示
configCOMMAND_INT_MAX_OUTPUT_SIZE
未定义,则在FreeRTOS_CLI.h
头文件中添加该宏定义,或者统一在FreeRTOSConfig.h
头文件中定义。
-
修改serial.c 由于
serial.c
内的串口相关函数和宏定义为库函数版本,需要将其改造成HAL库版本。具体修改如下:-
添加头文件及串口声明
-
修改
xSerialPortInitMinimal
函数 将函数开始的结构体定义删除,并在条件判断内根据需要使用DMA或中断接收。把if( ( xRxedChars != serINVALID_QUEUE ) && ( xCharsForTx != serINVALID_QUEUE ) ){}内的内容修改为下述
DMA 接收
OR中断接收
的函数-
DMA 接收
HAL_UART_Receive_DMA(&huart2, (uint8_t*)uart2_recv_buff, sizeof(uart2_recv_buff)); // 使用DMA
-
中断接收
HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1); // 不使用DMA,使用中断接收
-
-
修改
xSerialPutChar
函数 删除USART_ITConfig
调用,改为使用HAL_UART_Transmit_IT
进行发送。具体操作是把USART_ITConfig( USART1, USART_IT_TXE, ENABLE );删掉,在同样的位置增加如下代码:uint8_t cChar; if (xQueueReceive(xCharsForTx, &cChar, 0) == pdTRUE) { while(HAL_UART_Transmit_IT(&huart2, &cChar, 1) != HAL_OK); }
主要是函数声明类型跟INIT_xxx_EXPORT要求的不一样,将函数返回值由void修改为int即可,当然函数内亦需要按实际情况return一个值。
-
添加空闲中断接收 删除(或注释掉)原有中断服务函数
vUARTInterruptHandler
,添加空闲中断接收一整帧数据的函数:uint8_t buff_index = 0; uint8_t data_len = 0; void UART2_IDLECallback(UART_HandleTypeDef* huart) { HAL_UART_DMAStop(&huart2); // 停止本次DMA传输 data_len = RECV_BUFF_MAX - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx); // 计算接收到的数据长度 uart2_recv_buff[data_len] = '/0'; portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; for (uint8_t i = 0; i < data_len; i++) { xQueueSendFromISR(xRxedChars, &uart2_recv_buff[i], &xHigherPriorityTaskWoken); xHigherPriorityTaskWoken = pdFALSE; } HAL_UART_Receive_DMA(&huart2, (uint8_t*)uart2_recv_buff, sizeof(uart2_recv_buff)); // 重启开始DMA传输 每次255字节数据 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); }
-
-
继续编译 若编译后没有报serial相关的错误,但提示未定义错误,找到
vTaskList
函数定义,发现受控于两个宏定义。将这些宏定义添加到FreeRTOSConfig.h
中:
-
添加宏定义 全局搜索找到
xQueueCreateMutex
的定义,发现受控于两个宏,其中configSUPPORT_DYNAMIC_ALLOCATION
默认已开启:
将configUSE_MUTEXES
宏定义添加到FreeRTOSConfig.h
中:
四、注册命令与验证
-
注册命令 在
main.h
头文件中增加相关宏定义,并在main.c
中注册命令行命令。引入注册命令行函数和创建命令控制台函数,创建命令控制台任务。
-
编译通过 编译通过后,烧写到设备中进行测试。
命令行操作效果:
注:若出现串口不停打印数据的情况,可以尝试降低串口波特率。可参考 STM32 use FreeRTOS CLI - Programmer Sought
五、自定义命令
-
定义自定义命令 找到
task-stats
命令的定义,查看其结构体定义。
拷贝一份task-stats
的定义,修改为自定义命令:
-
添加回调函数 添加命令响应的回调函数
prvTaskCreateStatic
-
注册自定义命令 在命令行注册函数中,注册自定义命令:
-
编写验证自定义命令代码 将
main.c
中静态创建任务TaskCreateStatic
的调用注释,并将其声明的头文件加入到Sample-CLI-commands.c
-
编译验证 编译烧写后,验证自定义命令是否正常工作。
输入的命令必须与命令帮助说明中的名称一致才能执行(当然,CLI命令结构体中明确说明两者要一致)
六、启用更多命令
-
启用任务运行时间命令 在
FreeRTOSConfig.h
中启用相关宏定义。
-
定义宏 若编译出错提示
configGENERATE_RUN_TIME_STATS
宏定义启用,需要定义portCONFIGURE_TIMER_FOR_RUN_TIME_STATS
和portGET_RUN_TIME_COUNTER_VALUE
宏。
-
添加宏定义 将系统获取tick计数的函数赋值给这些宏定义,并进行编译。
再编译,还有宏没定义portGET_RUN_TIME_COUNTER_VALUE:
再次定义portGET_RUN_TIME_COUNTER_VALUE宏,并且该宏由定义看起来就像获取tick值的,将系统获取tick计数的函数赋值
七、最终验证
编译通过后,烧写到设备中进行验证。确保所有命令行功能正常工作。
通过上述步骤,您可以成功在STM32F103系列上移植FreeRTOS的CLI,并实现自定义命令行功能。这篇教程详细介绍了每个步骤的具体操作,希望能帮助您顺利完成移植和调试工作。如果遇到问题,可以参考相关文档或社区资源进行进一步的了解和解决。祝您在使用FreeRTOS时顺利、高效!
对应的 demo 源码, 请点击 RtosExPro at freertos_command_line
也可扫码关注博主同名公众号"不解之榬",回复 “freeRTOS” 获取