论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=93149
第8章 RTX5任务优先级分配和修改
本章节主要为大家讲解RTX5任务优先级设置的注意事项,任务优先级的分配方案及其相关的一个例子,内容相对比较简单。
8.1 任务优先级设置注意事项
8.2 任务优先级分配方案
8.3 任务优先级设置函数osThreadSetPriority
8.4 任务优先级获取函数osThreadGetPriority
8.5 实验例程说明
8.6 总结
8.1 RTX5支持的优先级设置
RTX5操作系统支持的优先级设置如下:
/// Priority values. typedef enum { osPriorityNone = 0, ///< No priority (not initialized). osPriorityIdle = 1, ///< Reserved for Idle thread. osPriorityLow = 8, ///< Priority: low osPriorityLow1 = 8+1, ///< Priority: low + 1 osPriorityLow2 = 8+2, ///< Priority: low + 2 osPriorityLow3 = 8+3, ///< Priority: low + 3 osPriorityLow4 = 8+4, ///< Priority: low + 4 osPriorityLow5 = 8+5, ///< Priority: low + 5 osPriorityLow6 = 8+6, ///< Priority: low + 6 osPriorityLow7 = 8+7, ///< Priority: low + 7 osPriorityBelowNormal = 16, ///< Priority: below normal osPriorityBelowNormal1 = 16+1, ///< Priority: below normal + 1 osPriorityBelowNormal2 = 16+2, ///< Priority: below normal + 2 osPriorityBelowNormal3 = 16+3, ///< Priority: below normal + 3 osPriorityBelowNormal4 = 16+4, ///< Priority: below normal + 4 osPriorityBelowNormal5 = 16+5, ///< Priority: below normal + 5 osPriorityBelowNormal6 = 16+6, ///< Priority: below normal + 6 osPriorityBelowNormal7 = 16+7, ///< Priority: below normal + 7 osPriorityNormal = 24, ///< Priority: normal osPriorityNormal1 = 24+1, ///< Priority: normal + 1 osPriorityNormal2 = 24+2, ///< Priority: normal + 2 osPriorityNormal3 = 24+3, ///< Priority: normal + 3 osPriorityNormal4 = 24+4, ///< Priority: normal + 4 osPriorityNormal5 = 24+5, ///< Priority: normal + 5 osPriorityNormal6 = 24+6, ///< Priority: normal + 6 osPriorityNormal7 = 24+7, ///< Priority: normal + 7 osPriorityAboveNormal = 32, ///< Priority: above normal osPriorityAboveNormal1 = 32+1, ///< Priority: above normal + 1 osPriorityAboveNormal2 = 32+2, ///< Priority: above normal + 2 osPriorityAboveNormal3 = 32+3, ///< Priority: above normal + 3 osPriorityAboveNormal4 = 32+4, ///< Priority: above normal + 4 osPriorityAboveNormal5 = 32+5, ///< Priority: above normal + 5 osPriorityAboveNormal6 = 32+6, ///< Priority: above normal + 6 osPriorityAboveNormal7 = 32+7, ///< Priority: above normal + 7 osPriorityHigh = 40, ///< Priority: high osPriorityHigh1 = 40+1, ///< Priority: high + 1 osPriorityHigh2 = 40+2, ///< Priority: high + 2 osPriorityHigh3 = 40+3, ///< Priority: high + 3 osPriorityHigh4 = 40+4, ///< Priority: high + 4 osPriorityHigh5 = 40+5, ///< Priority: high + 5 osPriorityHigh6 = 40+6, ///< Priority: high + 6 osPriorityHigh7 = 40+7, ///< Priority: high + 7 osPriorityRealtime = 48, ///< Priority: realtime osPriorityRealtime1 = 48+1, ///< Priority: realtime + 1 osPriorityRealtime2 = 48+2, ///< Priority: realtime + 2 osPriorityRealtime3 = 48+3, ///< Priority: realtime + 3 osPriorityRealtime4 = 48+4, ///< Priority: realtime + 4 osPriorityRealtime5 = 48+5, ///< Priority: realtime + 5 osPriorityRealtime6 = 48+6, ///< Priority: realtime + 6 osPriorityRealtime7 = 48+7, ///< Priority: realtime + 7 osPriorityISR = 56, ///< Reserved for ISR deferred thread. osPriorityError = -1, ///< System cannot determine priority or illegal priority. osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. } osPriority_t;
大家设置任务优先级的时候需要调用这些指定的优先级,其中osPriorityIdle是最低优先级,供空闲任务使用,而osPriorityRealtime7是最高优先级。
8.2 任务优先级分配方案
对于初学者,有时候会纠结任务优先级设置为多少合适,因为任务优先级设置多少是没有标准的。对于这个问题,RTX5有一个推荐的设置标准,任务优先级设置推荐方式如下图8.1所示:
图8.1 任务优先级分配方案
- IRQ任务:IRQ任务是指通过中断服务程序进行触发的任务,此类任务应该设置为所有任务里面优先级最高的。
- 高优先级后台任务:比如按键检测,触摸检测,USB消息处理,串口消息处理等,都可以归为这一类任务。
- 低优先级的时间片调度任务:比如emWin的界面显示,LED数码管的显示等不需要实时执行的都可以归为这一类任务。实际应用中用户不必拘泥于将这些任务都设置为优先级1的同优先级任务,可以设置多个优先级,只需注意这类任务不需要高实时性。
- 空闲任务:空闲任务是系统任务。
- 特别注意:IRQ任务和高优先级任务必须设置为阻塞式(调用消息等待或者延迟等函数即可),只有这样高优先级任务才会释放CPU的使用权,从低优先级任务才有机会得到执行。
这里的优先级分配方案是RTX操作系统推荐的一种方式,实际项目也可以不采用这种方法。调试出适合项目需求的才是最好的。
8.3 任务优先级设置函数osThreadSetPriority
函数原型:
osStatus_t osThreadSetPriority(osThreadId_t thread_id,
osPriority_t priority )
函数描述:
此函数用于修改任务的优先级。
函数参数:
1、 第1个参数填任务的ID。
2、 第2个参数是任务优先级。
3、 返回值:
- osOK: 任务优先级修改成功。
- osErrorParameter: 任务ID是NULL或者优先级无效。
- osErrorResource: 任务处于无效状态。
- osErrorISR: 此函数不可以在中断服务程序里面调用。
使用举例:
/* ********************************************************************************************************** 变量 ********************************************************************************************************** */ static uint64_t AppTaskUserIFStk[512/8]; /* 任务栈 */ /* 任务句柄 */ OS_TID HandleTaskUserIF = NULL; /* ********************************************************************************************************* * 函 数 名: AppTaskChangePrio * 功能说明: 修改任务优先级 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppTaskDelete (void) { HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */ 1, /* 任务优先级 */ &AppTaskUserIFStk, /* 任务栈 */ sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */ if(os_tsk_prio(HandleTaskLED, 3) == OS_R_OK) { printf("任务AppTaskLED优先级修改成功\r\n"); } else { printf("任务AppTaskLED优先级修改失败\r\n"); } }
8.4 任务优先级获取函数osThreadGetPriority
函数原型:
osPriority_t osThreadGetPriority (osThreadId_t thread_id )
函数描述:
此函数用于获取任务的优先级。
函数参数:
1、 第1个参数填任务的ID。
2、 返回值:
- 正常情况下,可以返回任务优先级。
- osPriorityError 任务优先级无法确定或者非法的,如果是在中断服务程序里面调用此函数也返回错误。
使用举例:
/* ********************************************************************************************************** 变量 ********************************************************************************************************** */ static uint64_t AppTaskUserIFStk[512/8]; /* 任务栈 */ /* 任务句柄 */ OS_TID HandleTaskUserIF = NULL; /* ********************************************************************************************************* * 函 数 名: AppTaskChangePrio * 功能说明: 修改任务优先级 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppTaskDelete (void) { HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF, /* 任务函数 */ 1, /* 任务优先级 */ &AppTaskUserIFStk, /* 任务栈 */ sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */ if(os_tsk_prio(HandleTaskLED, 3) == OS_R_OK) { printf("任务AppTaskLED优先级修改成功\r\n"); } else { printf("任务AppTaskLED优先级修改失败\r\n"); } }
8.5 实验例程说明
配套例子:
V5-404_RTX5 Task Priority
实验目的:
- 学习RTX的任务优先级设置。
实验内容:
- K1键按下,设置任务优先级为osPriorityHigh。
- K2键按下,设置任务优先级为osPriorityHigh2。
- 各个任务实现的功能如下:
AppTaskUserIF任务 : 按键消息处理。
AppTaskLED任务 : LED闪烁。
AppTaskMsgPro任务 : 消息处理。
AppTaskStart任务 : 启动任务,也是最高优先级任务,这里实现按键扫描。
osRtxTimerThread任务 : 定时器任务,暂未使用。
串口打印信息:
波特率 115200,数据位 8,奇偶校验位无,停止位 1。
RTX配置:
RTX配置向导详情如下:
System Configuration
- Global Dynamic Memory size
全局动态内存,这里设置为32KB。
- Kernel Tick Frequency
系统时钟节拍,这里设置为1KHz。
Thread Configuration
- Default Thread Stack size
默认的任务栈大小,这里设置为1024字节
RTX5任务调试信息:
程序设计:
任务栈大小分配:
全部独立配置,没有使用RTX5默认配置:
/* ********************************************************************************************************** 变量 ********************************************************************************************************** */ /* 任务的属性设置 */ const osThreadAttr_t ThreadStart_Attr = { /* 未使用 */ // .cb_mem = &worker_thread_tcb_1, // .cb_size = sizeof(worker_thread_tcb_1), // .stack_mem = &worker_thread_stk_1[0], // .stack_size = sizeof(worker_thread_stk_1), // .priority = osPriorityAboveNormal, // .tz_module = 0 .name = "osRtxStartThread", .attr_bits = osThreadDetached, .priority = osPriorityHigh4, .stack_size = 2048, }; const osThreadAttr_t ThreadMsgPro_Attr = { .name = "osRtxMsgProThread", .attr_bits = osThreadDetached, .priority = osPriorityHigh3, .stack_size = 1024, }; const osThreadAttr_t ThreadLED_Attr = { .name = "osRtxLEDThread", .attr_bits = osThreadDetached, .priority = osPriorityHigh2, .stack_size = 512, }; const osThreadAttr_t ThreadUserIF_Attr = { .name = "osRtxThreadUserIF", .attr_bits = osThreadDetached, .priority = osPriorityHigh1, .stack_size = 1024, };
系统栈大小分配:
RTX5初始化:
/* ********************************************************************************************************* * 函 数 名: main * 功能说明: 标准c程序入口。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ int main (void) { /* HAL库,MPU,Cache,时钟等系统初始化 */ System_Init(); /* 内核开启前关闭HAL的时间基准 */ HAL_SuspendTick(); /* 内核初始化 */ osKernelInitialize(); /* 创建启动任务 */ ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr); /* 开启多任务 */ osKernelStart(); while(1); }
RTX5任务创建:
/* ********************************************************************************************************* * 函 数 名: AppTaskCreate * 功能说明: 创建应用任务 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppTaskCreate (void) { ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr); ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr); ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr); }
四个RTX任务的实现:
/* ********************************************************************************************************* * 函 数 名: AppTaskUserIF * 功能说明: 按键消息处理 * 形 参: 无 * 返 回 值: 无 * 优 先 级: osPriorityHigh1 (数值越小优先级越低,这个跟uCOS相反) ********************************************************************************************************* */ void AppTaskUserIF(void *argument) { uint8_t ucKeyCode; while(1) { ucKeyCode = bsp_GetKey(); if (ucKeyCode != KEY_NONE) { switch (ucKeyCode) { /* K1键按下,设置任务优先级为osPriorityHigh */ case KEY_DOWN_K1: printf("K1键按下,设置任务 HandleTaskLED的优先级为osPriorityHigh\r\n"); osThreadSetPriority(ThreadIdTaskLED, osPriorityHigh); printf("任务ThreadIdTaskLED的优先级 = %d\r\n",osThreadGetPriority(ThreadIdTaskLED)); break; /* K2键按下,设置任务优先级为osPriorityHigh2 */ case KEY_DOWN_K2: printf("K2键按下,设置任务 HandleTaskLED的优先级为osPriorityHigh2\r\n"); osThreadSetPriority(ThreadIdTaskLED, osPriorityHigh2); printf("任务ThreadIdTaskLED的优先级 = %d\r\n", osThreadGetPriority(ThreadIdTaskLED)); break; /* 其他的键值不处理 */ default: break; } } osDelay(20); } } /* ********************************************************************************************************* * 函 数 名: AppTaskLED * 功能说明: LED闪烁。 * 形 参: 无 * 返 回 值: 无 * 优 先 级: osPriorityHigh2 ********************************************************************************************************* */ void AppTaskLED(void *argument) { const uint16_t usFrequency = 200; /* 延迟周期 */ uint32_t tick; /* 获取当前时间 */ tick = osKernelGetTickCount(); while(1) { bsp_LedToggle(2); /* 相对延迟 */ tick += usFrequency; osDelayUntil(tick); } } /* ********************************************************************************************************* * 函 数 名: AppTaskMsgPro * 功能说明: 消息处理,暂时未用到。 * 形 参: 无 * 返 回 值: 无 * 优 先 级: osPriorityHigh3 ********************************************************************************************************* */ void AppTaskMsgPro(void *argument) { while(1) { osDelay(10); } } /* ********************************************************************************************************* * 函 数 名: AppTaskStart * 功能说明: 启动任务,这里用作BSP驱动包处理。 * 形 参: 无 * 返 回 值: 无 * 优 先 级: osPriorityHigh4 ********************************************************************************************************* */ void AppTaskStart(void *argument) { const uint16_t usFrequency = 1; /* 延迟周期 */ uint32_t tick; /* 初始化外设 */ HAL_ResumeTick(); bsp_Init(); /* 创建任务 */ AppTaskCreate(); /* 获取当前时间 */ tick = osKernelGetTickCount(); while(1) { /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */ bsp_ProPer1ms(); /* 相对延迟 */ tick += usFrequency; osDelayUntil(tick); } }
8.6 总结
本章节内容相对比较容易,重点是学习任务优先级分配方案,随着后面的学习,初学者需要慢慢积累这方面的经验。