这是FreeRTOS带有的命令行形式的操作。
使用HAL库的串口传输。在CubeMX里打开串口的中断,打开FreeRTOS的USE_TRACE_FACILITY和USE_STATS_FORMATTING_FUNCTIONS,这两个用于任务基本信息查询,Sample-CLI-commands里的一个命令示例函数需要用到。
从源码中得到以下6个文件:
FreeRTOSv10.2.1\FreeRTOS\Demo\CORTEX_STM32F103_Keil\serial\serial.c
FreeRTOSv10.2.1\FreeRTOS\Demo\Common\include\serial.h
FreeRTOSv10.2.1\FreeRTOS-Plus\Source\FreeRTOS-Plus-CLI\FreeRTOS_CLI.c和FreeRTOS_CLI.h
FreeRTOSv10.2.1\FreeRTOS-Plus\Demo\Common\FreeRTOS_Plus_CLI_Demos\UARTCommandConsole.c和Sample-CLI-commands.c
1、在FreeRTOS_CLI头文件里加上#define configCOMMAND_INT_MAX_OUTPUT_SIZE 500,这是用来定义输出缓存的大小,命令会将数据一次性全部复制到这里面,300起步。太小会因为数组不够导致只能回显一部分。
2、
(1)、在serial源文件里添加:
#include "main.h"
extern UART_HandleTypeDef huart1;
uint8_t aRxBuffer;
(2)、将xSerialPortInitMinimal函数里的开头的部分结构体定义删掉。再把if ((xRxedChars != serINVALID_QUEUE) && (xCharsForTx != serINVALID_QUEUE)){}里的内容替换为HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1);,因为串口初始化已经自动被CubeMX配置好了,这条函数的作用是当接收到1字节后就调用HAL_UART_RxCpltCallback函数。
(3)、将xSerialPutChar函数里的if (xQueueSend(xCharsForTx, &cOutChar, xBlockTime) == pdPASS){}里的内容替换为:
xReturn = pdPASS;
uint8_t cChar;
if (xQueueReceive(xCharsForTx, &cChar, 0) == pdTRUE) { while(HAL_UART_Transmit_IT(&huart1, &cChar, 1) != HAL_OK); }。这里不能用阻塞式的函数,否则在回显的时候有问题,还导致接收也有问题。很可能是HAL库的问题,有看到过讨论这种问题的文章,可能和__HAL_LOCK有关。
(4)、删掉vUARTInterruptHandler函数。再添加:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(xRxedChars, &aRxBuffer, &xHigherPriorityTaskWoken);
HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1);
}
}
3、在UARTCommandConsole源文件里,将
static void prvUARTCommandConsoleTask( void *pvParameters );
void vUARTCommandConsoleStart( uint16_t usStackSize, UBaseType_t uxPriority );这两条函数声明去掉。
添加extern void vRegisterSampleCLICommands( void );,这个用于添加cli的命令。
注:extern "C"的作用是将函数从C++接口改为C接口,只用C就就只要添加extern void vRegisterSampleCLICommands( void );。
将vUARTCommandConsoleStart函数里的:
xTxMutex = xSemaphoreCreateMutex();
configASSERT( xTxMutex );
移到下面的prvUARTCommandConsoleTask函数里面的for( ;; )的前面,再删掉vUARTCommandConsoleStart函数。
把vRegisterSampleCLICommands函数放到prvUARTCommandConsoleTask的for( ;; )前面。
4、在main源文件里添加extern void prvUARTCommandConsoleTask( void *pvParameters );,再将该函数作为任务函数来配置,栈用128 * 8的大小。
现在在单片机每次开机就会从串口输出一段话。\n和\r都可以作为回车。发送help\n,会将已经添加的命令都发送回来。
注:在Sample-CLI-commands源文件里有两处strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ));,这个函数不对,需要在strlen( "\r\n" )后面写+1,因为需要将最后面的空字符也拼接上去。即使不改,在使时也没发现有问题。
扩展:
说明:打开Sample-CLI-commands源文件的prvRunTimeStatsCommand函数,这样可以查询每个任务的运行时间的占空比。
方法:在CubeMX里打开FreeRTOS的USE_TRACE_FACILITY、USE_STATS_FORMATTING_FUNCTIONS和GENERATE_RUN_TIME_STATS。
在FreeRTOSConfig头文件里的最下面有两个宏定义:
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS configureTimerForRunTimeStats
#define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue
这两个都是函数名,是自带的弱函数。configureTimerForRunTimeStats函数是一个用于初始化的函数,可以不用。getRunTimeCounterValue函数则是关键,它返回一个值,这个值必须是不断累加的,用于计算任务执行时间的占比。例:
unsigned long getRunTimeCounterValue(void)
{
return xTaskGetTickCount(); //返回当前滴答数
}。在任意文件的任意位置定义这个函数即可。