​​

第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所示:

【STM32F407】第8章   RTX5任务优先级分配和修改_任务栈

图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

实验目的:

  1. 学习RTX的任务优先级设置。

实验内容:

  1. K1键按下,设置任务优先级为osPriorityHigh。
  2. K2键按下,设置任务优先级为osPriorityHigh2。
  3. 各个任务实现的功能如下:

AppTaskUserIF任务   : 按键消息处理。

AppTaskLED任务      : LED闪烁。

AppTaskMsgPro任务   : 消息处理。

AppTaskStart任务      : 启动任务,也是最高优先级任务,这里实现按键扫描。

osRtxTimerThread任务 : 定时器任务,暂未使用。

串口打印信息:

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

 

【STM32F407】第8章   RTX5任务优先级分配和修改_消息处理_02

RTX配置:

RTX配置向导详情如下:

【STM32F407】第8章   RTX5任务优先级分配和修改_优先级_03

  System Configuration

  • Global Dynamic Memory size

全局动态内存,这里设置为32KB。

  • Kernel Tick Frequency

系统时钟节拍,这里设置为1KHz。

  Thread Configuration

  • Default Thread Stack size

默认的任务栈大小,这里设置为1024字节

RTX5任务调试信息:

【STM32F407】第8章   RTX5任务优先级分配和修改_消息处理_04

程序设计:

  任务栈大小分配:

全部独立配置,没有使用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,
};

  系统栈大小分配:

 

【STM32F407】第8章   RTX5任务优先级分配和修改_优先级_05

  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   总结

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

 

微信公众号:armfly_com