千家信息网

FreeRTOS实时操作系统之可视化追踪调试的方法

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"FreeRTOS实时操作系统之可视化追踪调试的方法",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"FreeRTOS实时操作系统之可视
千家信息网最后更新 2026年11月03日FreeRTOS实时操作系统之可视化追踪调试的方法

这篇文章主要讲解了"FreeRTOS实时操作系统之可视化追踪调试的方法",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"FreeRTOS实时操作系统之可视化追踪调试的方法"吧!

前言

用RTOS编程,为每个任务分配多大的堆栈空间就成了一项技术活:分配多了浪费系统资源,分配少了又恐怕会发生堆栈溢出。由于中断和抢占式调度器的存在,我们要估算出一个任务需要多少堆栈是非常困难的,今天我们就介绍一种方法,来获取每个任务的剩余堆栈空间。本文以NXP LPC177x_8x系列微控制器为例。

我们将这个功能做成一个命令,添加到FreeRTOS使用任务通知实现命令行解释器一文介绍的命令解释列表中。当程序运行一段时间后,我们在SecureCRT软件中输入命令"task"后回车,能看到如图1-1所示的任务信息。这里只有两个任务,其中堆栈一列中的数字,代表对应任务剩余的堆栈空间,单位是StackType_t类型,这个类型在移植层定义,一般定义为4字节。

图1-1:任务信息

1.使能可视化追踪和运行时间统计功能

如图1-1所示,要实现堆栈使用量信息以及CPU使用率信息,必须将FreeRTOSConfig.h文件中的两个宏设置为1:

         #define configUSE_TRACE_FACILITY          1               #define configGENERATE_RUN_TIME_STATS 1

第一个宏用来使能可视化追踪功能,第二个宏用来使能运行时间统计功能。如果第二个宏设置为1,则下面两个宏必须被定义:

portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():

用户程序需要提供一个基准时钟函数,函数完成初始化基准时钟功能,这个函数要被define到宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()上。

这是因为运行时间统计需要一个比系统节拍中断频率还要高分辨率的基准定时器,否则,统计可能不精确。

基准定时器中断频率要比统节拍中断快10~100倍。基准定时器中断频率越快,统计越精准,但能统计的运行时间也越短(比如,基准定时器10ms中断一次,8位无符号整形变量可以计到2.55秒,但如果是1秒中断一次,8位无符号整形变量可以统计到255秒)。

portGET_RUN_TIME_COUNTER_VALUE():

用户程序需要提供一个返回基准时钟当前"时间"的函数,这个函数要被define到宏portGET_RUN_TIME_COUNTER_VALUE()上。

我们使用定时器1来产生基准时钟,定时器1初始化函数为:

/*** 初始化计时定时器1,用于OS任务运行时间统计*/void init_timer1_for_runtime_state(void){    TIM_TIMERCFG_Type Timer0CfgType;    Timer0CfgType.PrescaleOption=TIM_PRESCALE_USVAL;        //预分频的单位是微秒    Timer0CfgType.PrescaleValue=500;                        //预分频后为500微秒,    TIM_Init(LPC_TIM1,TIM_TIMER_MODE,&Timer0CfgType);    LPC_TIM1->TCR=0x01;}

定时器1被配置成每隔500微秒,TC寄存器值增一。我们将定时器1的 TC寄存器值作为基准时钟当前时间。当TC寄存器值溢出时,大概要经过24.8天,这对于我们这个应用是足够的。

在FreeRTOSConfig.h中,定义初始化基准定时器宏和获取当前时间宏:

extern void init_timer1_for_runtime_state(void);#define TIMER1_TC         ( * ( ( volatile uint32_t * )0x40008008 ) )#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() init_timer1_for_runtime_state()#define portGET_RUN_TIME_COUNTER_VALUE() TIMER1_TC

2.获取任务信息并格式化

获取每个任务的状态信息使用的是API函数uxTaskGetSystemState(),该函数定义为:

UBaseType_tuxTaskGetSystemState(                       TaskStatus_t * constpxTaskStatusArray,                       const UBaseType_tuxArraySize,                       unsigned long * constpulTotalRunTime );

函数uxTaskGetSystemState()向TaskStatus_t结构体填充相关信息,系统中每一个任务的信息都可以填充到TaskStatus_t结构体数组中,数组大小由uxArraySize指定。结构体TaskStatus_t定义如下:

typedef struct xTASK_STATUS{   /* 任务句柄*/   TaskHandle_t xHandle;   /* 指针,指向任务名*/   const signed char *pcTaskName;   /*任务ID,是一个独一无二的数字*/   UBaseType_t xTaskNumber;   /*填充结构体时,任务当前的状态(运行、就绪、挂起等等)*/   eTaskState eCurrentState;   /*填充结构体时,任务运行(或继承)的优先级。*/   UBaseType_t uxCurrentPriority;   /* 当任务因继承而改变优先级时,该变量保存任务最初的优先级。仅当configUSE_MUTEXES定义为1有效。*/   UBaseType_t uxBasePriority;   /* 分配给任务的总运行时间。仅当宏configGENERATE_RUN_TIME_STATS为1时有效。*/   unsigned long ulRunTimeCounter;   /* 从任务创建起,堆栈剩余的最小数量,这个值越接近0,堆栈溢出的可能越大。 */   unsigned short usStackHighWaterMark;}TaskStatus_t;

注意,这个函数仅用来调试用,调用此函数会挂起所有任务,直到函数结束后才恢复挂起的任务,因此任务可能被挂起很长时间。在文件FreeRTOSConfig.h中,宏configUSE_TRACE_FACILITY必须设置为1,此函数才有效。

由于我们不使用动态内存分配策略,所以实现定义了最大任务个数并预先分配好了存储任务状态信息的数组:

#defineMAX_TASK_NUM        5TaskStatus_tpxTaskStatusArray[MAX_TASK_NUM];

正确调用函数uxTaskGetSystemState()后,任务的信息会被放在TaskStatus_t结构体中,我们需要将这些信息格式化为容易阅读的形式,并共通过串口打印到屏幕。完成这些功能的函数叫做get_task_state(),代码如下所示:

/*获取OS任务信息*/voidget_task_state(int32_t argc,void *cmd_arg){    const chartask_state[]={'r','R','B','S','D'};    volatile UBaseType_t uxArraySize, x;    uint32_t ulTotalRunTime,ulStatsAsPercentage;    /* 获取任务总数目 */    uxArraySize = uxTaskGetNumberOfTasks();   if(uxArraySize>MAX_TASK_NUM)    {        MY_DEBUGF(CMD_LINE_DEBUG,("当前任务数量过多!\n"));    }    /*获取每个任务的状态信息 */    uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime );    #if (configGENERATE_RUN_TIME_STATS==1)    MY_DEBUGF(CMD_LINE_DEBUG,("任务名      状态  ID    优先级  堆栈    CPU使用率\n"));     /* 避免除零错误 */    if( ulTotalRunTime > 0 )    {        /* 将获得的每一个任务状态信息部分的转化为程序员容易识别的字符串格式 */        for( x = 0; x < uxArraySize; x++ )        {            char tmp[128];            /* 计算任务运行时间与总运行时间的百分比。*/            ulStatsAsPercentage =(uint64_t)(pxTaskStatusArray[ x ].ulRunTimeCounter)*100 / ulTotalRunTime;            if( ulStatsAsPercentage > 0UL )            {               sprintf(tmp,"%-12s%-6c%-6d%-8d%-8d%d%%",pxTaskStatusArray[ x].pcTaskName,task_state[pxTaskStatusArray[ x ].eCurrentState],                                                                       pxTaskStatusArray[ x ].xTaskNumber,pxTaskStatusArray[ x].uxCurrentPriority,                                                                       pxTaskStatusArray[ x ].usStackHighWaterMark,ulStatsAsPercentage);            }            else            {                /* 任务运行时间不足总运行时间的1%*/                sprintf(tmp,"%-12s%-6c%-6d%-8d%-8dt<1%%",pxTaskStatusArray[x ].pcTaskName,task_state[pxTaskStatusArray[ x ].eCurrentState],                                                                       pxTaskStatusArray[ x ].xTaskNumber,pxTaskStatusArray[ x].uxCurrentPriority,                                                                       pxTaskStatusArray[ x ].usStackHighWaterMark);                           }           MY_DEBUGF(CMD_LINE_DEBUG,("%s\n",tmp));        }    }    MY_DEBUGF(CMD_LINE_DEBUG,("任务状态:   r-运行  R-就绪  B-阻塞  S-挂起  D-删除\n"));    #endif //#if (configGENERATE_RUN_TIME_STATS==1)}

3.添加到命令解释列表

在FreeRTOS使用任务通知实现命令行解释器一文我们讲过了命令表,这里只需要将get_task_state()函数添加到命令列表中,命令设置为"task",代码如下所示:

/*命令表*/const cmd_list_structcmd_list[]={/*   命令    参数数目    处理函数        帮助信息                                  */       {"?",       0,     handle_help,     "?                                  -打印帮助信息"},                     {"reset",   0,     handle_reset,    "reset                              -重启控制器"},    {"arg",     8,     handle_arg,      "arg  ...               -测试用,打印输入的参数"},    {"hello",   0,     printf_hello,    "hello                              -打印HelloWorld!"},    {"task",    0,     get_task_state,  "task                               -获取任务信息"},};

感谢各位的阅读,以上就是"FreeRTOS实时操作系统之可视化追踪调试的方法"的内容了,经过本文的学习后,相信大家对FreeRTOS实时操作系统之可视化追踪调试的方法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

任务 信息 函数 时间 运行 命令 基准 堆栈 定时器 统计 系统 状态 可视化 功能 结构 分配 方法 时钟 操作系统 实时 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网黑科技 湖北九亚互联网络科技有限公司 期待互联网科技 奇酷互联网科技 汇久创客互联网科技 大白互联网科技 互联网金融和金融科技 海南购全球互联网科技 成都仁贤领冠互联网科技有限公司 山东吉时兔互联网科技有限公司 青岛中康互联网医疗科技有限公司 字节跳动和互联网科技 互联网科技革命什么开始 青岛科技大学互联网大赛研究生 新兴科技互联网创新大赛颁奖典礼 科技互联网的核心竞争力 梅州GM互联网络科技有限公司 陕西彩京云互联网科技有限公司 北京瑞云互联网科技有限公司 中国主要互联网科技公司 上海卓越科技互联网 期待互联网科技 致骋互联网科技 丰台科技园 互联网公司 互联网科技创新企业排名 科技互联网的估值 互联网科技项目计划书材料类 互联网第三次科技革命特征 版纳互联网科技选哪家 互联网金融运营模式中的金融科技
0