【STM32H7】第12章 ThreadX任务优先级修改及其分配方案

论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514

第12章       ThreadX任务优先级修改及其分配方案

本章节主要为大家讲解ThreadX任务优先级设置的注意事项、任务优先级的分配方案及其相关的一个例子,内容相对比较简单。

12.1 任务优先级说明

12.2 任务优先级分配方案

12.3 中断优先级和任务优先级的区别

12.4 任务优先级修改函数tx_thread_priority_change

12.5 任务优先级获取函数tx_thread_info_get

12.6 实验例程说明

12.7 总结

 

 

12.1 任务优先级说明

下面对ThreadX优先级相关的几个重要知识点进行下说明,这些知识点在以后的使用中务必要掌握牢固。

1、 ThreadX中任务的最大优先级数值是通过tx_port.h文件中的TX_MAX_PRIORITIES进行配置的,用户实际可以使用的优先级范围是0到configMAX_PRIORITIES – 1。比如我们配置此宏定义为32,那么用户可以使用的优先级号是0到31,不包含32,对于这一点,初学者要特别的注意。并且TX_MAX_PRIORITIES的宏定义设置的数值必须是32的整数倍:

#define TX_MAX_PRIORITIES    32

2、  用户配置任务的优先级数值越小,那么此任务的优先级越低(0是最高优先级任务),ThreadX没有空闲任务,如果大家创建空闲任务,需要将其设置为最低优先级。

3、  建议用户配置宏定义TX_MAX_PRIORITIES的最大值不要超过32,即用户任务可以使用的优先级范围是0到31。

  •   因为对于CM内核的移植文件,有专用的汇编指令CLZ(Count Leading Zeros),通过这些指令可以加速算法执行速度。
  •   比通用方式高效。
  •   ThreadX查找最高优先级任务是通过定义的32bit数组,

ULONG  _tx_thread_preempted_maps[TX_MAX_PRIORITIES/32];

如果TX_MAX_PRIORITIES设置为32,那么仅需一个32bit变量就可以方便记录32不同优先级任务,程序运行时查找最高优先级任务也方便。

4、  ThreadX中处于运行状态的任务永远是当前能够运行的最高优先级任务。下一章节讲解调度器,大家会对这个知识点有一个全面的认识。

12.2 任务优先级分配方案

对于初学者,有时候会纠结任务优先级设置为多少合适,因为任务优先级设置多少是没有标准的。对于这个问题,我们这里为大家推荐一个标准,任务优先级设置推荐方式如下图所示:

 

  •   IRQ任务:IRQ任务是指通过中断服务程序进行触发的任务,此类任务应该设置为所有任务里面优先级最高的。
  •   高优先级后台任务:比如按键检测,触摸检测,USB消息处理,串口消息处理等,都可以归为这一类任务。
  •   低优先级的时间片调度任务:比如GUI的界面显示,LED数码管的显示等不需要实时执行的都可以归为这一类任务。实际应用中用户不必拘泥于将这些任务都设置为优先级1的同优先级任务,可以设置多个优先级,只需注意这类任务不需要高实时性。
  •   空闲任务:空闲任务是系统任务。
  •   特别注意:IRQ任务和高优先级任务必须设置为阻塞式(调用消息等待或者延迟等函数即可),只有这样,高优先级任务才会释放CPU的使用权,,从而低优先级任务才有机会得到执行。

这里的优先级分配方案是我们推荐的一种方式,实际项目也可以不采用这种方法。调试出适合项目需求的才是最好的。

12.3 中断优先级和任务优先级区别

部分初学者也容易在这两个概念上面出现问题。简单的说,这两个之间没有任何关系,不管中断的优先级是多少,中断的优先级永远高于任何任务的优先级,即任务在执行的过程中,中断来了就开始执行中断服务程序。

另外对于STM32来说,中断优先级的数值越小,优先级越高。同样,ThreadX的任务优先级也是任务优先级数值越小,任务优先级越高。

12.4 任务优先级修改函数tx_thread_priority_change

函数原型:

UINT tx_thread_priority_change(
    TX_THREAD *thread_ptr,
    UINT new_priority, 
    UINT *old_priority);

函数描述:

函数tx_thread_priority_change用于实现ThreadX任务优先级的修改。

  •   第1个参数thread_ptr是任务句柄,用于区分不同的任务。
  •   第2个参数new_priority是新任务优先级(0 至 (TX_MAX_PRIORITIES-1))。0表示最高优先级。
  •   第3个参数old_priority是任务之前的优先级。

注意事项:

  1. 允许在任务和定时器组里面调用。
  2. 指定任务的抢占阈值自动设置为新的优先级。如果需要新的阈值,则必须在此调用之后使用函数tx_thread_preemption_change。
  3. 第二个参数数值不可大于等于tx_port.h文件中的宏定义:#define  TX_MAX_PRIORITIES 配置的数值。

使用举例:

TX_THREAD   AppTaskUserIFTCB;
UINT OldPriority;

/*优先级将其设置为6 */
tx_thread_priority_change(&AppTaskUserIFTCB, 6, &OldPriority);

12.5 任务优先级获取函数tx_thread_info_get

函数原型:

UINT tx_thread_info_get(
    TX_THREAD *thread_ptr, 
    CHAR **name,
    UINT *state, 
    ULONG *run_count,
    UINT *priority,
    UINT *preemption_threshold,
    ULONG *time_slice,
    TX_THREAD **next_thread,
    TX_THREAD **suspended_thread);

函数描述:

函数tx_thread_info_get不仅仅可用于获取ThreadX任务优先级。还可以获取其它相关信息。

1、  第1个参数thread_ptr是任务句柄,用于区分不同的任务。

2、  第2个参数name用于获取任务名。

3、  第3个参数state用于获取任务状态,可能的值如下所示。

  •   TX_READY (0x00)
  •   TX_COMPLETED (0x01)
  •   TX_TERMINATED (0x02)
  •   TX_SUSPENDED (0x03)
  •   TX_SLEEP (0x04)
  •   TX_QUEUE_SUSP (0x05)
  •   TX_SEMAPHORE_SUSP (0x06)
  •   TX_EVENT_FLAG (0x07)
  •   TX_BLOCK_MEMORY (0x08)
  •   TX_BYTE_MEMORY (0x09)
  •   TX_MUTEX_SUSP (0x0D)

4、  第4个参数run_count用于获取任务运行计数。

5、  第5个参数priority用于获取任务优先级。

6、  第6个参数preemption_threshold用于获取抢占阀值。

7、  第7个参数time_slice用于获取时间片。

8、  第8个参数next_thread指向下一个创建的任务句柄。

9、  第9个参数suspended_thread指向挂起列表中下一个任务句柄。

10、  返回值

  •   TX_SUCCESS:(0X00) 成功检索任务信息。
  •   TX_THREAD_ERROR:(0x0E) 任务控制指针无效。

注意事项:

  •   可以在初始化阶段,任务,定时器组和中断服务程序里面调用。

使用举例:

TX_THREAD  AppTaskUserIFTCB;
CHAR *name;
UINT state;
ULONG run_count;
UINT priority;
UINT preemption_threshold;
UINT time_slice;
TX_THREAD *next_thread;
TX_THREAD *suspended_thread;
UINT status;

status = tx_thread_info_get(&AppTaskUserIFTCB, 
&name,
                            &state, 
&run_count,
                            &priority, 
&preemption_threshold,
                            &time_slice, 
&next_thread,
&suspended_thread);

12.6 实验例程

配套例子:

V7-3007_ThreadX Task Priority Change

实验目的:

  1. 学习ThreadX的开关中断使用BasePri寄存器方案,这样使用ThreadX可以仅开关受ThreadX管理的中断,从而可以让高优先级中断实现零中断延迟。

实验内容:

1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况        

 ===================================================

OS CPU Usage =  1.94%

===================================================

Prio StackSize CurStack MaxStack Taskname

2     4092      383      391    App Task Start

3     4092      543      659    App Msp Pro

4     4092      391      391    App Task UserIF

5     4092      543      659    App Task COM

30     1020      519      519    App Task STAT

31     1020      143       71    App Task IDLE

0     1020      391      391    System Timer Thread               

串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。

App Task Start任务  :启动任务,这里用作BSP驱动包处理。

App Task MspPro任务 :消息处理,这里未使用。

App Task UserIF任务 :按键消息处理。

App Task COM任务    :这里用作LED闪烁。

App Task STAT任务   :统计任务

App Task IDLE任务   :空闲任务

System Timer Thread任务:系统定时器任务

2、 (1) 凡是用到printf函数的全部通过函数App_Printf实现。

 (2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

3、默认上电是通过串口打印信息,如果使用RTT打印信息

(1)   MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

#define Enable_RTTViewer  1

(2)   Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。

实验操作:

  1. K1按键按下打印任务执行情况,按下K2和K3设置优先级后,可以按K1查看任务最新优先级是否设置成功。
  2. K2按键按下,设置任务App Task UserIF的优先级为6。
  3. K3按键按下,设置任务App Task UserIF的优先级为4。

串口打印信息方式(AC5,AC6和IAR):

波特率 115200,数据位 8,奇偶校验位无,停止位 1

 

RTT打印信息方式(AC5,AC6和IAR):

 

Embedded Studio仅支持调试状态RTT打印:

 

由于Embedded Studio不支持中文,所以中文部分显示乱码,不用管。

程序执行框图:

12.7 总结

本章节内容相对比较容易,重点是学习任务优先级分配方案,随着后面的学习,初学者需要慢慢积累这方面的经验。

 

posted @ 2021-06-22 16:28  硬汉嵌入式  阅读(506)  评论(0编辑  收藏  举报