【FreeRTOS操作系统教程】第13章 FreeRTOS任务优先级修改及其分配方案
2016-08-22 15:21阅读:
第13章
FreeRTOS任务优先级修改及其分配方案
本文完整版地址:http://bbs.armfly.com/read.php?tid=21119
本章节主要为大家讲解FreeRTOS任务优先级设置的注意事项、任务优先级的分配方案及其相关的一个例子,内容相对比较简单。
本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
13.1 任务优先级说明
13.2 任务优先级分配方案
13.3 中断优先级和任务优先级的区别
13.4 任务优先级修改
13.5 任务优先级获取
13.6 实验例程说明
13.7
总结
13.1
任务优先级说明
下面对FreeRTOS优先级相关的几个重要知识点进行下说明,这些知识点在以后的使用中务必要掌握牢固。
u
FreeRTOS中任务的最高优先级是通过FreeRTOSConfig.h文件中的configMAX_PRIORITIES进行配置的,用户实际可以使用的优先级范围是0到configMAX_PRIORITIES
–
1。比如我们配置此宏定义为5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
u
用户配置任务的优先级数值越小,那么此任务的优先级越低,空闲任务的优先级是0。
u
建议用户配置宏定义configMAX_PRIORITIES的最大值不要超过32,即用户任务可以使用的优先级范围是0到31。因为对于CM内核的移植文件,用户任务的优先级不是大于等于32的话,portmacro.h文件中的宏定义configUSE_PORT_OPTIMISED_TASK_SELECTION会优化优先级列表中要执行的最高优先级任务的获取算法(对于CM内核的移植文件,此宏定义默认是使能的,当然,用户也可以在FreeRTOSConfig.h文件中进行配置)。相比通用的最高优先级任务获取算法,这两种方式的对比如下:
Ø
通用方式,没有优化---配置宏定义configUSE_PORT_OPTIMISED_TASK_SELECTION为0:
²
所有平台的移植文件都可以配置为0,因为这是通用方式。
²
纯C编写,比专用方式效率低。
²
可用的优先级数量不限制。
Ø
专用方式,进行优化---配置宏定义configUSE_PORT_OPTIMISED_TASK_SELECTION为为1:
²
部分平台支持。
²
这些平台架构有专用的汇编指令,比如CLZ(Count Leading
Zeros)指令,通过这些指令可以加速算法执行速度。
²
比通用方式高效。
²
有最大优先级数限制,通常限制为32个。
u
如果用户在FreeRTOSConfig.h文件中配置宏定义configUSE_TIME_SLICING为1,或者没有配置此宏定义,时间片调度都是使能的。另外,只要芯片资源允许,可以配置任意多个同优先级任务。
(备注:没有定义configUSE_TIME_SLICING,也能使用时间片调度是因为此宏定义默认已经在FreeRTOS.h文件中使能)
u
FreeRTOS中处于运行状态的任务永远是当前能够运行的最高优先级任务。下一章节讲解调度器,大家会对这个知识点有一个全面的认识。
13.2
任务优先级分配方案
对于初学者,有时候会纠结任务优先级设置为多少合适,因为任务优先级设置多少是没有标准的。对于这个问题,我们这里为大家推荐一个标准,任务优先级设置推荐方式如下图13.1所示:
图13.1 任务优先级分配方案
u
IRQ任务:IRQ任务是指通过中断服务程序进行触发的任务,此类任务应该设置为所有任务里面优先级最高的。
u
高优先级后台任务:比如按键检测,触摸检测,USB消息处理,串口消息处理等,都可以归为这一类任务。
u
低优先级的时间片调度任务:比如emWin的界面显示,LED数码管的显示等不需要实时执行的都可以归为这一类任务。实际应用中用户不必拘泥于将这些任务都设置为优先级1的同优先级任务,可以设置多个优先级,只需注意这类任务不需要高实时性。
u
空闲任务:空闲任务是系统任务。
u
特别注意:IRQ任务和高优先级任务必须设置为阻塞式(调用消息等待或者延迟等函数即可),只有这样,高优先级任务才会释放CPU的使用权,,从而低优先级任务才有机会得到执行。
这里的优先级分配方案是我们推荐的一种方式,实际项目也可以不采用这种方法。调试出适合项目需求的才是最好的。
13.3
中断优先级和任务优先级区别
部分初学者也容易在这两个概念上面出现问题。简单的说,这两个之间没有任何关系,不管中断的优先级是多少,中断的优先级永远高于任何任务的优先级,即任务在执行的过程中,中断来了就开始执行中断服务程序。
另外对于STM32F103,F407和F429来说,中断优先级的数值越小,优先级越高。而FreeRTOS的任务优先级是,任务优先级数值越小,任务优先级越低。
13.4任务优先级修改
使用如下函数可以实现FreeRTOS的任务优先级修改:
u vTaskPrioritySet
()
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:

这里也对此函数进行下介绍。
函数原型:
void vTaskPrioritySet( TaskHandle_t xTask,
UBaseType_t
uxNewPriority );
函数描述:
函数vTaskPrioritySet用于实现FreeRTOS任务优先级的修改。
u
第1个参数是任务句柄,用于区分不同的任务。
u
第2个参数是给任务配置的新优先级。
使用这个函数要注意以下问题:
1.
使用此函数需要在FreeRTOSConfig.h配置文件中配置如下宏定义为1
#define INCLUDE_vTaskPrioritySet
1
2.
如果第二个参数里面填的是NULL,即数值0的话,那么配置的就是当前正在执行的任务。
3.
如果被修改的任务的优先级,修改后高于正在执行的任务,将执行任务切换,切换到修改好的高优先级任务。
4.
第二个参数数值不可大于等于FreeRTOSConfig.h文件中的宏定义:
#define configMAX_PRIORITIES
配置的数值。
使用举例:
static TaskHandle_t xHandleTaskLED = NULL;
static void vTaskTaskUserIF(void *pvParameters)
{
uint8_t
ucKeyCode;
while(1)
{
ucKeyCode = bsp_GetKey();
if (ucKeyCode != KEY_NONE)
{
switch
(ucKeyCode)
{
case KEY_DOWN_K2:
printf('K2键按下,设置任务vTaskLED的优先级为1\r');
vTaskPrioritySet( xHandleTaskLED, 1);
printf('K2键按下,任务vTaskLED的优先级已经设置为:%d\r',
(int)uxTaskPriorityGet(xHandleTaskLED));
break;
case KEY_DOWN_K3:
printf('K3键按下,设置任务vTaskLED的优先级为2\r');
vTaskPrioritySet( xHandleTaskLED, 2);
printf('K3键按下,任务vTaskLED的优先级已经设置为:%d\r',
(int)uxTaskPriorityGet(xHandleTaskLED));
break;
default:
break;
}
}
vTaskDelay(20);
}
}
static void AppTaskCreate (void)
{
xTaskCreate( vTaskLED,
'vTaskLED',
512,
NULL,
2,
&xHandleTaskLED );
}
13.5任务优先级获取
使用如下函数可以实现FreeRTOS的任务优先级获取:
u vTaskPriorityGet
()
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:

这里也对此函数进行下介绍。
函数原型:
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask
);
函数描述:
函数vTaskPriorityGet用于获取FreeRTOS任务优先级。
u
第1个参数是任务句柄,用于区分不同的任务。
使用这个函数要注意以下问题:
1.
使用此函数需要在FreeRTOSConfig.h配置文件中配置如下宏定义为1
#define INCLUDE_vTaskPriorityGet
1
2.
如果第二个参数里面填的是NULL,即数值0的话,那么获取的优先级就是当前正在执行的任务。
使用举例:
static TaskHandle_t xHandleTaskLED = NULL;
static void vTaskTaskUserIF(void *pvParameters)
{
uint8_t
ucKeyCode;
while(1)
{
ucKeyCode = bsp_GetKey();
if (ucKeyCode != KEY_NONE)
{
switch
(ucKeyCode)
{
case KEY_DOWN_K2:
printf('K2键按下,设置任务vTaskLED的优先级为1\r');
vTaskPrioritySet( xHandleTaskLED, 1);
printf('K2键按下,任务vTaskLED的优先级已经设置为:%d\r',
(int)uxTaskPriorityGet(xHandleTaskLED));
break;
case KEY_DOWN_K3:
printf('K3键按下,设置任务vTaskLED的优先级为2\r');
vTaskPrioritySet( xHandleTaskLED, 2);
printf('K3键按下,任务vTaskLED的优先级已经设置为:%d\r',
(int)uxTaskPriorityGet(xHandleTaskLED));
break;
default:
break;
}
}
vTaskDelay(20);
}
}
static void AppTaskCreate (void)
{
xTaskCreate( vTaskLED,
'vTaskLED',
512,
NULL,
2,
&xHandleTaskLED );
}
13.6实验例程说明
13.6.1STM32F103开发板实验
配套例子:
V4-307_FreeRTOS实验_任务优先级修改
实验目的:
1.
学习FreeRTOS的任务优先级修改。
实验内容:
1.
K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
2.
K2按键按下,设置任务vTaskLED的优先级为1。
3.
K3按键按下,设置任务vTaskLED的优先级为2。
4.
各个任务实现的功能如下:
vTaskUserIF任务
:按键消息处理。
vTaskLED任务
:LED闪烁。
vTaskMsgPro任务
:消息处理,这里是用作LED闪烁。
vTaskStart任务
:启动任务,也是最高优先级任务,这里实现按键扫描。
FreeRTOS的配置:
FreeRTOSConfig.h文件中的配置如下:
#if defined(__ICCARM__) || defined(__CC_ARM) ||
defined(__GNUC__)
#include
extern volatile uint32_t
ulHighFrequencyTimerTicks;
#endif
#define configUSE_PREEMPTION
1
#define configUSE_IDLE_HOOK
0
#define configUSE_TICK_HOOK
0
#define configCPU_CLOCK_HZ
( ( unsigned long )
72000000 )
#define configTICK_RATE_HZ
( ( TickType_t )
1000 )
#define configMAX_PRIORITIES
( 5 )
#define configMINIMAL_STACK_SIZE ( (
unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE
( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN
( 16 )
#define configUSE_TRACE_FACILITY
1
#define configUSE_16_BIT_TICKS
0
#define configIDLE_SHOULD_YIELD
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
//#define portALT_GET_RUN_TIME_COUNTER_VALUE
1
#define configUSE_CO_ROUTINES
0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define INCLUDE_vTaskPrioritySet
1
#define INCLUDE_uxTaskPriorityGet
1
#define INCLUDE_vTaskDelete
1
#define INCLUDE_vTaskCleanUpResources
0
#define INCLUDE_vTaskSuspend
1
#define INCLUDE_vTaskDelayUntil
1
#define INCLUDE_vTaskDelay
1
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS
__NVIC_PRIO_BITS
#else
#define configPRIO_BITS
4
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY
0x0f
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
0x01
FreeRTOS任务调试信息(按K1按键,串口打印):
上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
#define tskBLOCKED_CHAR
( 'B' )
任务阻塞
#define tskREADY_CHAR
( 'R' )
任务就绪
#define tskDELETED_CHAR
( 'D' )
任务删除
#define tskSUSPENDED_CHAR ( 'S' )
任务挂起
程序设计:
u
任务栈大小分配:
vTaskUserIF任务
:2048字节
vTaskLED任务
:2048字节
vTaskMsgPro任务
:2048字节
vTaskStart任务
:2048字节
任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
#define configTOTAL_HEAP_SIZE
( ( size_t ) ( 17 * 1024 ) )
u
系统栈大小分配:
u
FreeROTS初始化:
int main(void)
{
__set_PRIMASK(1);
bsp_Init();
vSetupSysInfoTest();
AppTaskCreate();
vTaskStartScheduler();
while(1);
}
u
硬件外设初始化
硬件外设的初始化是在bsp.c文件实现:
void bsp_Init(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
bsp_InitUart();
bsp_InitLed();
bsp_InitKey();
}
u
FreeRTOS任务创建:
static void AppTaskCreate (void)
{
xTaskCreate( vTaskTaskUserIF,
'vTaskUserIF',
512,
NULL,
1,
&xHandleTaskUserIF ); /*
任务句柄 */
xTaskCreate( vTaskLED,
'vTaskLED',
512,
NULL,
2,
&xHandleTaskLED );
xTaskCreate(
vTaskMsgPro,
'vTaskMsgPro',
512,
NULL,
3,
&xHandleTaskMsgPro ); /*
任务句柄 */
xTaskCreate(
vTaskStart,
'vTaskStart',
512,
NULL,
4,
&xHandleTaskStart );
}
u
四个FreeRTOS任务的实现:
static void vTaskTaskUserIF(void *pvParameters)
{
uint8_t
ucKeyCode;
uint8_t
pcWriteBuffer[500];
while(1)
{
ucKeyCode = bsp_GetKey();
if (ucKeyCode != KEY_NONE)
{
switch
(ucKeyCode)
{
case KEY_DOWN_K1:
printf('=================================================\r');
printf('任务名
任务状态 优先级 剩余栈
任务序号\r');
vTaskList((char *)&pcWriteBuffer);
printf('%s\r', pcWriteBuffer);
printf('\r任务名
运行计数
使用率\r');
vTaskGetRunTimeStats((char *)&pcWriteBuffer);
printf('%s\r', pcWriteBuffer);
break;
case KEY_DOWN_K2:
printf('K2键按下,设置任务vTaskLED的优先级为1\r');
vTaskPrioritySet( xHandleTaskLED, 1);
printf('K2键按下,任务vTaskLED的优先级已经设置为:%d\r',
(int)uxTaskPriorityGet(xHandleTaskLED));
break;
case KEY_DOWN_K3:
printf('K3键按下,设置任务vTaskLED的优先级为2\r');
vTaskPrioritySet( xHandleTaskLED, 2);
printf('K3键按下,任务vTaskLED的优先级已经设置为:%d\r',
(int)uxTaskPriorityGet(xHandleTaskLED));
break;
default:
break;
}
}
vTaskDelay(20);
}
}
static void vTaskLED(void *pvParameters)
{
while(1)
{
bsp_LedToggle(2);
vTaskDelay(200);
}
}
static void vTaskMsgPro(void *pvParameters)
{
while(1)
{
bsp_LedToggle(3);
vTaskDelay(300);
}
}
static void vTaskStart(void *pvParameters)
{
while(1)
{
bsp_KeyScan();
vTaskDelay(10);
}
}