以下转载自安富莱电子: http://forum.armfly.com/forum.php

本章节为大家介绍 FreeRTOS 的调试方法,这里的调试方法主要是教会大家如何获取任务的执行情况,通过获取的任务信息,可以进一步的配置和优化工程,这种方法非常实用,建议初学者必须掌握。 
串口打印调试说明
很多时候,我们需要了解任务的执行状态,任务栈的使用情况以及各个任务的 CPU 使用率,这时就
需要用到官方提供的两个函数 vTaskListvTaskGetRunTimeStats。用户就可以通过这两个函数获得任
务的执行情况。
获取了任务执行情况后,可以通过串口将其打印出来,当然,也可以通过任何其它方式将其显示出来。
本教程配套的例子统一采用串口打印的方式显示任务的执行情况。另外有一点要特别注意,这种调试方式
仅限测试目的,实际项目中不要使用,这种测试方式比较影响系统实时性。

为了获取 FreeRTOS 的任务信息,需要创建一个定时器,这个定时器的时间基准精度要高于系统时钟
节拍,这样得到的任务信息才准确。这里提供的函数仅用于测试目的,切不可将其用于实际项目,原因有两点:

1. FreeRTOS 的系统内核没有对总的计数时间做溢出保护。
2. 定时器中断是 50us 进入一次,比较影响系统性能。
这里使用的是 32 位变量来保存 50us 一次的计数值,最大支持计数时间:2^32 * 50us / 3600s =
59.6 分钟。 运行时间超过了 59.6 分钟将不准确。
具体在 FreeRTOS 的工程中如何做才可以实现任务信息获取呢? 
使能相关宏定义
需要在 FreeRTOSConfig.h 文件中使能如下宏定义:

/***freertosconfig.h***/

extern volatile uint32_t ulHighFrequencyTimerTicks ;
/* Run time and task stats gathering related definitions. */
#define configUSE_TRACE_FACILITY 1
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks = 0ul)
#define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks

之前的博客:

使能了宏定义之后,必要完成portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()和portGET_RUN_TIME_COUNTER_VALUE()的定义,那么我们究竟应该如何定义并使用它们呢?

freertos官方网站给了提示(点击这里查看更多):

本次实验采用上面的做法,下面还有一个例子,但是没有上面好用:

现在我使用第一种方式,STM32F429,TIM6基本定时器,产生一个50us周期的中断,进一次中断,计数器的值加1:

由于在进入

/* 第三步:启动FreeRTOS,开始多任务调度,启动成功则不返回 */
vTaskStartScheduler();(在这个函数中调用了portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() )

这个函数之前,定时器计数已经执行计数功能很多次了,为了保证我们的基石相对准确,我们在启动freertos的API函数中将其置零,这也就是为什么那个宏#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 要这样操作这个计数器ulHighFrequencyTimerTicks=0UL;这样从任务开启时,计数器从零开始计数,而portGET_RUN_TIME_COUNTER_VALUE()是为了得到最后的计数值,可以是一个函数,返回之前用户自定义的计数器的值,也可以直接把那个计数器的值进行宏替换,在uxTaskGetSystemState()函数调用形式如下:

可以知道,我们只是需要这个计数器的值作为右值最后打印显示。(一个比较好的参考,点击这里)-(stack overflow参考)-(博客参考)。

有了前面的铺垫之后,再来说说我们的验证试验:

功能描述:按下K1按键,打印出任务信息,函数如下:

static void vTaskWork(void *pvParameters)
{ uint8_t pcWriteBuffer[]; while()
{ if (key1_flag==)
{
key1_flag=;
/* K1键按下 打印任务执行情况 */ printf("=======================================================\r\n");
printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
vTaskList((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer); printf("\r\n任务名 运行计数 使用率\r\n");
vTaskGetRunTimeStats((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer); /* 其他的键值不处理 */ } vTaskDelay();
}
}

任务一,执行打印,任务二,LED闪烁,任务三,蜂鸣器

static void AppTaskCreate(void)
{ xTaskCreate(vTaskWork, /* 任务函数 */
"vTaskWork", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskWork ); /* 任务句柄 */ xTaskCreate( vTaskLed1, /* 任务函数 */
"vTaskLed1", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskLED1); /* 任务句柄 */ xTaskCreate( vTaskBeep, /* 任务函数 */
"vTaskBeep", /* 任务名 */
, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
, /* 任务优先级*/
&xHandleTaskBeep ); /* 任务句柄 */ }
void vTaskLed1(void *pvParameters)
{
/* 任务都是一个无限,不能返回 */
while()
{
LED3_ON;
/* 阻塞延时,单位ms */
vTaskDelay( );
LED3_OFF;
vTaskDelay( );
}
}
void vTaskBeep(void *pvParameters)
{
/* 任务都是一个无限循环,不能返回 */
while()
{
BEEP_ON;
/* 阻塞延时,单位ms */
vTaskDelay( );
BEEP_OFF;
vTaskDelay( );
}
}

基本硬件初始化:

static void BSP_Init(void)
{
/*
* STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
* 都统一用这个优先级分组,千万不要再分组,切忌。
*/
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); /* LED 初始化 */
LED_GPIO_Config();
/*串口初始化*/
Debug_USART_Config();
/*按键初始化*/
EXTI_Key_Config();
/*定时器6初始化*/
TIMx_Configuration();
/* 蜂鸣器初始化 */
Beep_GPIO_Config();
}

关于裸机部分的外设初始化配置不再赘述。这样,下载程序之后,LED灯闪烁并且蜂鸣器鸣叫,在按下k1按键时,串口输出如下:

有了这个可以知道,我们512字的任务栈空间实在有点浪费,最后的剩余栈单位也是字。

最后,关于vTaskList((char *)&pcWriteBuffer);vTaskGetRunTimeStats((char *)&pcWriteBuffer);这个缓冲区的大小,官网说的,一个任务,大约40个字节足够,我们取50字节,所以定义的缓冲区大小uint8_t pcWriteBuffer[500];可以足够打印10个任务状态。

FreeRTOS 调试方法(printf---打印任务执行情况)的更多相关文章

  1. 【RTOS】基于V7开发板的最新版FreeRTOS V10.2.0程序模板,含MDK和IAR,支持串口打印任务执行情况

    模板下载: 链接:https://pan.baidu.com/s/1N32Hx7cTbDoRinuzTUB3zw   提取码:6aox 1.MDK使用MDK5.26及其以上版本. 2.IAR使用IAR ...

  2. 【安富莱专题教程第7期】终极调试组件Event Recorder,各种Link通吃,支持时间和功耗测量,printf打印,RTX5及中间件调试

    说明:1.继前面的专题教程推出SEGGER的RTT,JScope,Micrium的uC/Probe之后,再出一期终极调试方案Event Recoder,之所以叫终极解决方案,是因为所有Link通吃.  ...

  3. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

  4. 【转】Linux内核调试方法总结

    目录[-] 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2  dump_sta ...

  5. linux设备驱动程序第四部分:从如何定位oops对代码的调试方法,驱动线

    在一个我们谈到了如何编写一个简单的字符设备驱动程序,我们不是神,编写肯定会失败的代码,在这个过程中,我们需要继续写代码调试.在普通c应用.我们经常使用printf输出信息.或者使用gdb要调试程序,然 ...

  6. Perl的调试方法

    来源: http://my.oschina.net/alphajay/blog/52172 http://www.cnblogs.com/baiyanhuang/archive/2009/11/09/ ...

  7. VxWorks操作系统shell命令与调试方法总结

    VxWorks下的调试手段 主要介绍在Tornado集成开发环境下的调试方法,和利用支撑定位问题的步骤.思路. 1         Tornado的调试工具 嵌入式实时操作系统VxWorks和集成开发 ...

  8. 【安富莱】【RL-TCPnet网络教程】第11章 RL-TCPnet调试方法

    第11章      RL-TCPnet调试方法 本章节为大家讲解RL-TCPnet的调试方法,RL-TCPnet的调试功能其实就是通过串口打印实时监控运行状态.而且RL-TCPnet的调试设置比较简单 ...

  9. Linux内核调试方法总结

    Linux内核调试方法总结 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2   ...

随机推荐

  1. [Todo] Redis里面队列的两种模式,以及抢红包在Redis中的实现

    两种队列模式: 一种是利用list的lpush/rpop等 另一种是redis自带的发布者/订阅者模式 http://www.cnblogs.com/alazalazalaz/p/5512258.ht ...

  2. Trie树统计单词前缀

    输入 输入的第一行为一个正整数n.表示词典的大小,其后n行,每一行一个单词(不保证是英文单词,也有可能是火星文单词哦).单词由不超过10个的小写英文字母组成,可能存在同样的单词.此时应将其视作不同的单 ...

  3. [AngularJS] $scope.$warchCollection

    For the $watch in last article, we watch 'user.password', actually it is a string. If you watch 'use ...

  4. Linux下显示硬盘空间的两个命令

    1.df -h ,用于显示目前所有文件系统的可用空间及使用情况,示例如下: [root@msg45 ~]# df -hFilesystem                    Size  Used ...

  5. Wifidog及认证过程初分析

    Wifidog初分析 一.综述 wifidog是搭建无线热点认证系统的解决方案之一,他比nocat.nodog更适合互联网营销思路.常见的使用在openwrt系统上,它实现了路由器和认证服务器的数据交 ...

  6. Rust 格式输出

    格式输出由一系列定义在 std::fmt 中的宏提供. 包含: format! : 输出格式化的字符串. print!  : 输出格式化的字符串到控制台(终端)println!: 添加一个换行,输出格 ...

  7. mysql.sock文件的作用

    mysql.sock应该mysql的主机和客户机在同一host上的时候,使用unix domain socket做为通讯协议的载体,它比tcp快.Mysql有两种连接方式: (1)TCP/IP  (2 ...

  8. webpack 编译less/scss文件

    1.安装插件 处理less: npm install less-loader --save-dev 处理sass: npm install sass-loader --save-dev 2.项目目录: ...

  9. 【Excle数据透视】多列分别分类计数

    需求 今天碰到一个很特殊的需求,如下(分别对每一列的值去重并统计个数): 预期结果 实现方法 推荐使用第三种方案,因为不用写公式,比较简单! 方法一:使用countif函数 在单元格J2输入公式COU ...

  10. 【微信公众号】微信关于网页授权access_token和普通access_token的区别及两种不同方式授权

    微信官网网址:https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E9.99.84.EF.BC.9A.E6. ...