FreeRTOS+CLI 是一个可扩展的框架,允许应用程序编写器定义和注册自己的命令行输入命令,相当于RTOS的命令解析器,在实际项目中很有用。本文介绍如何移植CLI。 FreeRTOS+ CLI(命令行界面)提供了一种简单,小巧,可扩展且RAM高效的方法,使您的FreeRTOS应用程序能够处理命令行输入。
硬件平台:stm32f407zgt6 软件库:HAL
本文测试工程下载链接:https://download.csdn.net/download/qq_26972441/85351855 包括了Free RTOS源码
一. 需要准备FreeRTOS源码,并且找到以下文件放到一个文件夹下
二. 将文件夹下的c文件添加到keil目录
三. 使能串口空闲中断和DMA接收
void bsp_usart_USART2_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2, usart2_rx_buffer.data, USART_RX_BUFFER_SIZE);
}
四. 修改serial.c 的xSerialPortInitMinimal函数调用串口初始化函数
xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
{
xComPortHandle xReturn;
xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
if( ( xRxedChars != serINVALID_QUEUE ) && ( xCharsForTx != serINVALID_QUEUE ) )
{
bsp_usart_USART2_Init();
}
else
{
xReturn = ( xComPortHandle ) 0;
}
return xReturn;
}
五. 修改serial.c 的xSerialPutChar函数为轮询方式
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) {
if((HAL_UART_GetState(&huart2) & HAL_UART_STATE_BUSY_TX) != HAL_UART_STATE_BUSY_TX) {
HAL_UART_Transmit(&huart2, &cChar, 1, 1000);
}
}
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
六. FreeRTOSConfig.h 增加宏定义
#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1024
七. 完善串口中断服务函数
void USART2_IRQHandler(void)
{
BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET) {
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
HAL_UART_DMAStop(&huart2);
usart2_rx_buffer.finish_flag = 1;
usart2_rx_buffer.len = USART_RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart2.hdmarx);
for(uint16_t i = 0; i < usart2_rx_buffer.len; ++i) {
xQueueSendFromISR(xRxedChars, &usart2_rx_buffer.data[i], &pxHigherPriorityTaskWoken);
}
HAL_UART_Receive_DMA(&huart2, usart2_rx_buffer.data, USART_RX_BUFFER_SIZE);
}
HAL_UART_IRQHandler(&huart2);
portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
}
八 . 主函数调用如下函数
vRegisterSampleCLICommands();
vUARTCommandConsoleStart( 512, 1 );
九 . 注册测试函数
void vRegisterSampleCLICommands( void )
{
FreeRTOS_CLIRegisterCommand( &xTaskStats );
FreeRTOS_CLIRegisterCommand( &xThreeParameterEcho );
FreeRTOS_CLIRegisterCommand( &xParameterEcho );
FreeRTOS_CLIRegisterCommand( &xTestEcho );
#if( configGENERATE_RUN_TIME_STATS == 1 )
{
FreeRTOS_CLIRegisterCommand( &xRunTimeStats );
}
#endif
#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 )
{
FreeRTOS_CLIRegisterCommand( &xQueryHeap );
}
#endif
#if( configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 )
{
FreeRTOS_CLIRegisterCommand( &xStartStopTrace );
}
#endif
}
static const CLI_Command_Definition_t xTestEcho =
{
"task-test",
"\r\ntask-test:\r\n Test Function\r\n",
prvEchoTestCommand,
-1
};
十 .函数指针指向的回调函数
static int test[5] = {1, 2, 3, 4 ,5};
static BaseType_t prvEchoTestCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char * const pcHeader = " Test data (uint: mm) \r\n****************************************\r\n";
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
strcpy( pcWriteBuffer, pcHeader );
pcWriteBuffer += strlen( pcWriteBuffer );
for(uint8_t i = 0; i < 5; ++i) {
sprintf( pcWriteBuffer, "test[%d] distance: %d\t\t\r\n", i, test[i]);
pcWriteBuffer += strlen( pcWriteBuffer );
}
return pdFALSE;
}
十一. 创建CLI任务
void vUARTCommandConsoleStart( uint16_t usStackSize, UBaseType_t uxPriority )
{
xTxMutex = xSemaphoreCreateMutex();
configASSERT( xTxMutex );
xTaskCreate( prvUARTCommandConsoleTask,
"CLI",
usStackSize,
NULL,
uxPriority,
NULL );
}
十二. CLI任务具体内容及实现过程
static void prvUARTCommandConsoleTask( void *pvParameters )
{
signed char cRxedChar;
uint8_t ucInputIndex = 0;
char *pcOutputString;
static char cInputString[ cmdMAX_INPUT_SIZE ], cLastInputString[ cmdMAX_INPUT_SIZE ];
BaseType_t xReturned;
xComPortHandle xPort;
( void ) pvParameters;
pcOutputString = FreeRTOS_CLIGetOutputBuffer();
xPort = xSerialPortInitMinimal( configCLI_BAUD_RATE, cmdQUEUE_LENGTH );
vSerialPutString( xPort, ( signed char * ) pcWelcomeMessage, ( unsigned short ) strlen( pcWelcomeMessage ) );
for( ;; )
{
while( xSerialGetChar( xPort, &cRxedChar, portMAX_DELAY ) != pdPASS );
if( xSemaphoreTake( xTxMutex, cmdMAX_MUTEX_WAIT ) == pdPASS )
{
xSerialPutChar( xPort, cRxedChar, portMAX_DELAY );
if( cRxedChar == '\n' || cRxedChar == '\r' )
{
vSerialPutString( xPort, ( signed char * ) pcNewLine, ( unsigned short ) strlen( pcNewLine ) );
if( ucInputIndex == 0 )
{
strcpy( cInputString, cLastInputString );
}
do
{
xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
vSerialPutString( xPort, ( signed char * ) pcOutputString, ( unsigned short ) strlen( pcOutputString ) );
} while( xReturned != pdFALSE );
strncpy(cLastInputString, cInputString, cmdMAX_INPUT_SIZE);
ucInputIndex = 0;
memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
vSerialPutString( xPort, ( signed char * ) pcEndOfOutputMessage, ( unsigned short ) strlen( pcEndOfOutputMessage ) );
}
else
{
if( cRxedChar == '\r' )
{
}
else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) )
{
if( ucInputIndex > 0 )
{
ucInputIndex--;
cInputString[ ucInputIndex ] = '\0';
}
}
else
{
if( ( cRxedChar >= ' ' ) && ( cRxedChar <= '~' ) )
{
if( ucInputIndex < cmdMAX_INPUT_SIZE )
{
cInputString[ ucInputIndex ] = cRxedChar;
ucInputIndex++;
}
}
}
}
xSemaphoreGive( xTxMutex );
}
}
}
原理: 1、通过结构体构建回调函数 2、将实体函数通过函数指针注册 3、将CLI命令结构体添加到任务队列 4、通过CLI任务进行命令匹配
十三. 测试效果
1、输入help会将所添加的command列出来。 2、输入task-stats 会将RTOS所有任务列出来。 3、输入我们自己创建的command task-test 会将结果返回。
|