论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514
第8章 ThreadX调试方法(串口和RTT两种方式打印任务执行情况)
本章节为大家介绍ThreadX的调试方法,这里的调试方法主要是教会大家如何获取任务的执行情况,通过获取的任务信息,可以进一步的配置和优化工程,这种方法非常实用,建议初学者必须掌握。
8.1 初学者重要提示
8.1 串口或RTT打印调试说明
8.2 ThreadX实现串口或者RTT打印任务执行情况
8.3 ThreadX的CPU利用率实现方法
8.4 总结
8.1 初学者重要提示。
- RTT打印相关基础知识可以看此贴:
【专题教程第5期】工程调试利器RTT实时数据传输组件,替代串口调试,速度飞快,可以在中断和多任务中随意调用
http://www.armbbs.cn/forum.php?mod=viewthread&tid=86177 。
8.2 串口或RTT打印调试说明
很多时候我们需要了解任务的执行状态,任务栈的使用情况以及各个任务的CPU使用率。对此,我们这里封装了一个函数。
获取了任务执行情况后,可以通过串口或者RTT将其打印出来,当然,也可以通过任何其它方式将其显示出来。本教程配套的例子配套了串口和RTT两种打印方式显示任务的执行情况。另外有一点要特别注意,这种调试方式仅限测试目的,实际项目中不要使用。
8.3 ThreadX实现串口或者RTT打印任务执行情况
我们这里分串口和RTT两种打印方式为大家做个说明。
8.3.1 串口打印
串口打印主要用于MDK AC5,MDK AC6或者IAR创建的工程。通过下面函数实现任务执行情况信息获取:
/* ********************************************************************************************************* * 函 数 名: DispTaskInfo * 功能说明: 将ThreadX任务信息通过串口打印出来 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ static void DispTaskInfo(void) { TX_THREAD *p_tcb; /* 定义一个任务控制块指针 */ p_tcb = &AppTaskStartTCB; /* 打印标题 */ App_Printf("=============================================================== "); App_Printf("OS CPU Usage = %5.2f%% ", OSCPUUsage); App_Printf("=============================================================== "); App_Printf(" 任务优先级 任务栈大小 当前使用栈 最大栈使用 任务名 "); App_Printf(" Prio StackSize CurStack MaxStack Taskname "); /* 遍历任务控制块列表(TCB list),打印所有的任务的优先级和名称 */ while (p_tcb != (TX_THREAD *)0) { App_Printf(" %2d %5d %5d %5d %s ", p_tcb->tx_thread_priority, p_tcb->tx_thread_stack_size, (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_ptr, (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_highest_ptr, p_tcb->tx_thread_name); p_tcb = p_tcb->tx_thread_created_next; if(p_tcb == &AppTaskStartTCB) break; } }
- 函数App_Printf专门封装了一个线程安全的printf方式
- 这个函数的关键是通过任务控制列表检索所有创建的任务,并将相关信息打印出来。
打印效果如下:
8.3.2 RTT打印
本章节配套的例子对RTT打印方式也做了支持,对于MDK AC5,MDK AC6或者IAR,使能bsp.h文件中的宏定义为1即可
#define Enable_RTTViewer 1
实现方法和串口打印是一样的,只是换了一种打印方式。效果如下(也可以用SEGGER的 RTT Viewer):
使用Embedded Studio的话,不要使能宏定义,它可以直接调试状态在IDE上展示:
由于Embedded Studio不支持中文,所以中文部分显示乱码,不用管。
8.4 ThreadX的CPU利用率实现方法
ThreadX的CPU利用率主要是通过创建一个统计任务和一个空闲任务来实现:
/* ********************************************************************************************************* * 函 数 名: AppTaskStatistic * 功能说明: 统计任务,用于实现CPU利用率的统计。为了测试更加准确,可以开启注释调用的全局中断开关 * 形 参: thread_input 创建该任务时传递的形参 * 返 回 值: 无 * 优 先 级: 30 ********************************************************************************************************* */ void OSStatInit (void) { OSStatRdy = FALSE; tx_thread_sleep(2u); /* 时钟同步 */ //__disable_irq(); OSIdleCtr = 0uL; /* 清空闲计数 */ //__enable_irq(); tx_thread_sleep(100); /* 统计100ms内,最大空闲计数 */ //__disable_irq(); OSIdleCtrMax = OSIdleCtr; /* 保存最大空闲计数 */ OSStatRdy = TRUE; //__enable_irq(); } static void AppTaskStat(ULONG thread_input) { (void)thread_input; while (OSStatRdy == FALSE) { tx_thread_sleep(200); /* 等待统计任务就绪 */ } OSIdleCtrMax /= 100uL; if (OSIdleCtrMax == 0uL) { OSCPUUsage = 0u; } //__disable_irq(); OSIdleCtr = OSIdleCtrMax * 100uL; /* 设置初始CPU利用率 0% */ //__enable_irq(); for (;;) { // __disable_irq(); OSIdleCtrRun = OSIdleCtr; /* 获得100ms内空闲计数 */ OSIdleCtr = 0uL; /* 复位空闲计数 */ // __enable_irq(); /* 计算100ms内的CPU利用率 */ OSCPUUsage = (100uL - (float)OSIdleCtrRun / OSIdleCtrMax); tx_thread_sleep(100); /* 每100ms统计一次 */ } } /* ********************************************************************************************************* * 函 数 名: AppTaskIDLE * 功能说明: 空闲任务 * 形 参: thread_input 创建该任务时传递的形参 * 返 回 值: 无 优 先 级: 31 ********************************************************************************************************* */ static void AppTaskIDLE(ULONG thread_input) { TX_INTERRUPT_SAVE_AREA (void)thread_input; while(1) { TX_DISABLE OSIdleCtr++; TX_RESTORE } }
实现步骤如下:
- 进入到启动任务后,其它任何任务都不要创建,先创建一个统计任务,不让执行。
- 启动任务延迟100ms,延迟的这100ms时间基本都是空闲任务在执行,在空闲任务里面做32变量加1计算。我们就以这100ms,变量计数的最大值作为CPU利用率的分母。
- 然后开启统计任务的执行,每100ms执行一次,统计即可。空闲任务此时的计数值作为分子。通过这种方式就实现了CPU利用率的统计。
8.5 实验例程
本章节配套了例子:
- V7-3003_ThreadX Task Debug Info
含有GCC,IAR,MDK AC5和AC6四个版本工程。
通过按键K1打印任务的执行情况,工程默认是通过串口打印的,如果使用RTT打印的话,使用bsp.h中的宏定义为1即可。
#define Enable_RTTViewer 1
使用Embedded Studio的话,不要使能宏定义,它可以直接调试状态在IDE上展示。
8.6 总结
本章节主要是指导大家如何获取任务的执行情况,非常的实用,建议初学者务必掌握。