你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

NUCLEO-WBA65RI移植FreeRTOS CLI

[复制链接]
EPTmachine 发布时间:2025-7-3 23:09

FreeRTOS提供有不同的组件为用户提供不同的功能,本文移植其中的FreeRTOS-CLI命令行工具到NUCELO-WBA65RI开发板上。

1、STM32CubeMX配置

参考【NUCLEO-WBA65RI硬件资源、LED和串口打印】(https://shequ.stmicroelectronics.cn/thread-792019-1-1.html)

完成USART1和LED引脚的外设配置,使能USART1的中断。

Enable_USART1_Interrupt.png

在"Middleware and Software Packs"中选择X-Cube-FreeRTOS组件。

XCube_FreeRTOS_Set.png

在其中添加用于处理命令行的任务。

FreeRTOS_Task.png

配置完成后,保存生成代码。

2、移植FreeRTOS_CLI

在FreeRTOS仓库的FreeRTOS-Plus/Source/FreeRTOS-Plus-CLI路径中有FreeRTOS_CLI的源代码。

FreeRTOS_CLI_Path.png

在工程目录中添加Drivers文件夹用于存放FreeRTOS CLI和cli应用的代码,文件夹的结构如下图所示。

FreeRTOS_CLI_Code.png

FreeRTOSConfig.h中添加以下宏定义

#define configCOMMAND_INT_MAX_OUTPUT_SIZE 200

cli_app.h中声明几个用户应用的函数以及命令行处理函数,并在“app_freertos.c”中添加该头文件的引用

#ifndef INC_CLI_APP_H_
#define INC_CLI_APP_H_

#include "stdint.h"

void processRxedChar(uint8_t rxChar);
void handleNewline(const char *const pcInputString, char *cOutputBuffer, uint8_t *cInputIndex);
void handleCharacterInput(uint8_t *cInputIndex, char *pcInputString);
void vRegisterCLICommands(void);
void vCommandConsoleTask(void *pvParameters);

#endif /* INC_CLI_APP_H_ */

cli_app.c中实现FreeRTOS_CLI移植的主要工作,添加必要的头文件

#include "main.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"

#include "FreeRTOS_CLI.h"
#include "cli_app.h"

#include "stdbool.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"

#define MAX_INPUT_LENGTH 50
#define USING_VS_CODE_TERMINAL 0
#define USING_OTHER_TERMINAL 1 // e.g. Putty, TerraTerm

定义用于缓存数据的变量以及命令行常量

uint8_t cli_recv;
char cOutputBuffer[configCOMMAND_INT_MAX_OUTPUT_SIZE], pcInputString[MAX_INPUT_LENGTH];

int8_t cRxedChar;
const char * cli_prompt = "\r\ncli> ";
/* CLI escape sequences*/
uint8_t backspace[] = "\b \b";
uint8_t backspace_tt[] = " \b";

重定义_write函数,用于printf函数重定向

int _write(int file, char *data, int len)
{
    UNUSED(file);
    // Transmit data using UART2
    for (int i = 0; i < len; i++)
    {
        // Send the character
        USART1->TDR = (uint16_t)data[i];
        // Wait for the transmit buffer to be empty
        while (!(USART1->ISR & USART_ISR_TXE));
    }
    return len;
}

定义CLI命令函数和命令数组以及相关的注册函数,实现控制台清屏、加法以及控制开发板LED灯亮灭的功能。

//*****************************************************************************
BaseType_t cmd_add(char *pcWriteBuffer, size_t xWriteBufferLen,
                                 const char *pcCommandString)
{
    char *pcParameter1, *pcParameter2;
    BaseType_t xParameter1StringLength, xParameter2StringLength;

    /* Obtain the name of the source file, and the length of its name, from
    the command string. The name of the source file is the first parameter. */
    pcParameter1 = FreeRTOS_CLIGetParameter
                        (
                          /* The command string itself. */
                          pcCommandString,
                          /* Return the first parameter. */
                          1,
                          /* Store the parameter string length. */
                          &xParameter1StringLength
                        );
    pcParameter2 = FreeRTOS_CLIGetParameter
                        (
                          /* The command string itself. */
                          pcCommandString,
                          /* Return the first parameter. */
                          2,
                          /* Store the parameter string length. */
                          &xParameter2StringLength
                        );
    // convert the string to a number
    int32_t xValue1 = strtol(pcParameter1, NULL, 10);
    int32_t xValue2 = strtol(pcParameter2, NULL, 10);
    // add the two numbers
    int32_t xResultValue = xValue1 + xValue2;
    // convert the result to a string
    char cResultString[10];
    itoa(xResultValue, cResultString, 10);
    // copy the result to the write buffer
    strcpy(pcWriteBuffer, cResultString);

    return pdFALSE;
}

//*****************************************************************************
BaseType_t cmd_toggle(char *pcWriteBuffer, size_t xWriteBufferLen,
                                 const char *pcCommandString)
{
    (void)pcCommandString;
    (void)xWriteBufferLen;
    memset(pcWriteBuffer, 0x00, xWriteBufferLen);
    HAL_GPIO_TogglePin(LD1_GPIO_PORT, LD1_PIN);
    HAL_GPIO_TogglePin(LD2_GPIO_PORT, LD2_PIN);
    HAL_GPIO_TogglePin(LD3_GPIO_PORT, LD3_PIN);
    return pdFALSE;
}
const CLI_Command_Definition_t xCommandList[] = {
    {
        .pcCommand = "cls", /* The command string to type. */
        .pcHelpString = "cls:\r\n Clears screen\r\n\r\n",
        .pxCommandInterpreter = cmd_clearScreen, /* The function to run. */
        .cExpectedNumberOfParameters = 0 /* No parameters are expected. */
    },
    {
        .pcCommand = "add", /* The command string to type. */
        .pcHelpString = "add a b:\r\n add two numbers\r\n\r\n",
        .pxCommandInterpreter = cmd_add, /* The function to run. */
        .cExpectedNumberOfParameters = 2 /* 2 parameters are expected. */
    },
    {
        .pcCommand = "toggle", /* The command string to type. */
        .pcHelpString = "toggle :\r\n Toggle All Leds\r\n\r\n",
        .pxCommandInterpreter = cmd_toggle, /* The function to run. */
        .cExpectedNumberOfParameters = 0 /* No parameters are expected. */
    },
    {
        .pcCommand = NULL /* simply used as delimeter for end of array*/
    }
};

void vRegisterCLICommands(void){
    //itterate thourgh the list of commands and register them
    for (int i = 0; xCommandList[i].pcCommand != NULL; i++)
    {
        FreeRTOS_CLIRegisterCommand(&xCommandList[i]);
    }
}

封装prinf函数,定义处理输入字符串中的换行符、空格以及其他字符的处理函数

/*************************************************************************************************/
void cliWrite(const char *str)
{
   printf("%s", str);
   // flush stdout
   fflush(stdout);
}
/*************************************************************************************************/
void handleNewline(const char *const pcInputString, char *cOutputBuffer, uint8_t *cInputIndex)
{
    cliWrite("\r\n");

    BaseType_t xMoreDataToFollow;
    do
    {
        xMoreDataToFollow = FreeRTOS_CLIProcessCommand(pcInputString, cOutputBuffer, configCOMMAND_INT_MAX_OUTPUT_SIZE);
        cliWrite(cOutputBuffer);
    } while (xMoreDataToFollow != pdFALSE);

    cliWrite(cli_prompt);
    *cInputIndex = 0;
    memset((void*)pcInputString, 0x00, MAX_INPUT_LENGTH);
}
/*************************************************************************************************/
void handleBackspace(uint8_t *cInputIndex, char *pcInputString)
{
    if (*cInputIndex > 0)
    {
        (*cInputIndex)--;
        pcInputString[*cInputIndex] = '\0';

#if USING_VS_CODE_TERMINAL
        cliWrite((char *)backspace);
#elif USING_OTHER_TERMINAL
        cliWrite((char *)backspace_tt);
#endif
    }
    else
    {
#if USING_OTHER_TERMINAL
        uint8_t right[] = "\x1b\x5b\x43";
        cliWrite((char *)right);
#endif
    }
}
/*************************************************************************************************/
void handleCharacterInput(uint8_t *cInputIndex, char *pcInputString)
{
    if (cRxedChar == '\r')
    {
        return;
    }
    else if (cRxedChar == (uint8_t)0x08 || cRxedChar == (uint8_t)0x7F)
    {
        handleBackspace(cInputIndex, pcInputString);
    }
    else
    {
        if (*cInputIndex < MAX_INPUT_LENGTH)
        {
            pcInputString[*cInputIndex] = cRxedChar;
            (*cInputIndex)++;
        }
    }
}

实现vCommandConsoleTask函数,实现对命令行解析和执行的功能

void vCommandConsoleTask(void *pvParameters)
{
    uint8_t cInputIndex = 0; // simply used to keep track of the index of the input string
    uint32_t receivedValue; // used to store the received value from the notification
    //printf("vCommandConsole print\r\n");
    UNUSED(pvParameters);
    HAL_UART_Receive_IT(&huart1,&cli_recv, 1);
    vRegisterCLICommands();

    for (;;)
    {
        xTaskNotifyWait(pdFALSE,    // Don't clear bits on entry
                                  0,  // Clear all bits on exit
                                  &receivedValue, // Receives the notification value
                                  portMAX_DELAY); // Wait indefinitely
        //echo recevied char
        cRxedChar = receivedValue & 0xFF;
        cliWrite((char *)&cRxedChar);
        if (cRxedChar == '\r' || cRxedChar == '\n')
        {
            // user pressed enter, process the command
            handleNewline(pcInputString, cOutputBuffer, &cInputIndex);
        }
        else
        {
            // user pressed a character add it to the input string
            handleCharacterInput(&cInputIndex, pcInputString);
        }
    }
}

stm32wbaxx_it中添加串口接收处理函数

#include "cmsis_os.h"

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  //get ready to receive another char
  HAL_UART_Receive_IT(&huart1, &cli_recv, 1);
  //send the char to the command line task
  xTaskNotifyFromISR(cmdLineTaskHandle, (uint32_t)cli_recv, eSetValueWithOverwrite , NULL);
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_UART_RxCpltCallback could be implemented in the user file
   */
}

在"main.h"中添加用于交换数据的外部变量声明

#include "cmsis_os.h"

extern osThreadId_t cmdLineTaskHandle;
extern uint8_t cli_recv;

完成上述代码添加后编译下载到开发板,程序的运行效果如下。

03_CLI.gif

03_CLI_2.gif

3、总结

CLI命令行功能提供通过串口控制台调试开发板的功能,作为嵌入式开发的一种辅助手段。

收藏 评论0 发布时间:2025-7-3 23:09

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版