任务优先级
接上一章:
xTaskCreate()参数中uxPriority表明了任务在创建时的起始优先级,当任务创建后用户可以使用vTaskPrioritySet()来更改任务优先级。
有效优先级的最大数通过FreeRTOSConfig.h中的configMAX_PRIORITIES来定义,数字越大代表优先级越高,并且可以多个任务具有相同优先级。
FREERTOS时间任务调度器主要通过两种方法决定调度哪一个任务。configMAX_PRIORITIES所能设置的最大值取决于以下两种方法的适用。
通用方法(Generic Method):
通用方法通过C来实现,可以适用于所有结构的FREERTOS。若适用通用方法,则并不限制configMAX_PRIORITIES所能设置的最大值,然而,我们建议configMAX_PRIORITIES尽量设置为所需要的最小值,因为,configMAX_PRIORITIES的值越大,所消耗的RAM也就越大,并且最坏执行时间长度也会加长。当FreeRTOSConfig.h中的configUSE_PORT_OPTIMISED_TASK_SELECTION设置为0时,或者并没有定义该值或者该方法为FREERTOS所提供的唯一方案时,将采用通用方法。
结构优化方法(Architecture Optimized Method):
该方法采用一小段汇编来实现,并且速度比通用方法更快,configMAX_PRIORITIES所设置的值并不影响最坏执行时间的大小,当使用该方法时configMAX_PRIORITIES的值不能超过32。同时我们依旧该值越小越好,因为较大的configMAX_PRIORITIES会导致使用较多的RAM,当FreeRTOSConfig.h中的configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1时,采用该方法。注意,并不是所有的FREERTOS结构都支持这种方法。
FREERTOS总是保证高优先级的任务先进入运行状态,当优先级相同时,调度器会让多个相同优先级的任务交替进入执行状态。
时间管理与心跳(Tick Interrupt)
进程调度算法中描述了一种时间片(time slicing)的可选功能,下图表明了两个优先级相同的任务的执行过程:
两个任务交替执行,每次执行的时间为一个时间片。
为了决定时间片里执行哪一个任务,任务调度器必须在一个时间片结束时开始执行,来选出下一个时间片所执行的任务,因此需要一个周期性中断,我们称之为心跳(Tick Interrupt)就是为了这个目的。时间片的长度取决于心跳的周期,在FreeRTOSConfig.h中的configTICK_RATE_HZ即描述了心跳的频率,例如,configTICK_RATE_HZ被设置为100(Hz),则时间片的长度为10ms,两个心跳之间的长度被称为心跳周期,一个时间片的长度等于一个心跳周期。对于两个同优先级任务执行的具体过程如下所示:
FREERTOS应用层总是以心跳次数来表示时间,因此最常见的为‘ticks’,宏pdMS_TO_TICKS() 用于将一个正常时间转化为心跳次数。这个宏使用范围仅限于心跳频率低于1KHz的情况,其使用方法如下:
/* pdMS_TO_TICKS() takes a time in milliseconds as its only parameter, and evaluates
to the equivalent time in tick periods. This example shows xTimeInTicks being set to
the number of tick periods that are equivalent to 200 milliseconds. */
TickType_t xTimeInTicks = pdMS_TO_TICKS( 200 );
注意:此处并不推荐在应用层直接将时间转化为心跳时间,推荐使用上述的宏,这样的话,当心跳频率改变后,应用层的时间并不会改变。
心跳次数(tick count)的值表明了在调度器开始执行后心跳的总次数(假定该值还没有溢出),应用层在指定延时时间时,并不需要考虑该值溢出的问题。
优先级的实例
/* Define the strings that will be passed in as the task parameters. These are
defined const and not on the stack to ensure they remain valid when the tasks are
executing. */
static const char *pcTextForTask1 = "Task 1 is running\r\n";
static const char *pcTextForTask2 = "Task 2 is running\r\n";
int main( void )