提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、时间片?
多个任务拥有相同的任务优先级,当此时当前任务优先级下的任务进入运行态时,这几个任务轮流享有CPU使用时间,任务调度允许一个任务运行一个时间片后让出CPU使用权给同优先级的任务,如此反复。
二、配置
使用时间片调度的话宏configUSE_PREEMPTION
和宏configUSE_TIME_SLICING
必须为1.
一个时间片的长度由configTICK_RATE_HZ
配置,一个时间片的长度就是一个滴答定时器的中断周期。
例:
configTICK_RATE_HZ=1000
时间片长度为1ms
时间片任务调度发生在滴答定时器的中断服务函数中,SysTick_Handler()中会调用可以出发任务调度的函数xPortSysTickHandler()
void xPortSysTickHandler( void )
{
vPortRaiseBASEPRI();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
vPortClearBASEPRIFromISR();
}
这里有一个条件: xTaskIncrementTick() != pdFALSE
满足才能触发任务调度
BaseType_t xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE;
traceTASK_INCREMENT_TICK( xTickCount );
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
{
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) )
> ( UBaseType_t ) 1 )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
························
#endif /* configUSE_PREEMPTION */
return xSwitchRequired;
}
#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
上述两个宏,少一个都不会编译
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
判断当前任务优先级下是否还有其他任务,如果有就返回pdTRUE,触发任务调度。
三、解释
configTICK_RATE_HZ
它配置了滴答定时器的中断周期
滴答定时器一般是用来做延时函数
另外,可以做操作系统的心跳节拍,根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片。
配置滴答定时器和单条语句的执行没有太多关系。
vTaskDelay
延时N个时间片,这是个相对延时
四、延时
相对延时
从调用vTaskDelay开始延时多长时间,相当于裸机中的delay,延时时间是从调用这个函数开始的。
如果调用vTaskDelay()函数的任务在执行过程中被更高优先级的任务或者中断所打断,那么调用vTaskDelay()函数的任务将会受到影响,此时将不能保持一个固定的时间间隔运行。
绝对延时
调用vTaskDelayUntil()函数时,绝对延时的时间包含该任务本身的执行时间,以及任务被打断的时间。
即从第一次开始任务x,到第二次开始任务x,中间的时间间隔就是设置的延时长度。
void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
pxPreviousWakeTime:指针,指向一个变量,该变量保存任务最后一次解除阻塞的时间。第一次使用前,该变量
必须初始化为当前时间。之后这个变量会在vTaskDelayUntil()函数内自动更新。
xTimeIncrement :绝对延时时间,即任务重复执行的时间间隔。
例:
static portTickType xlastwaketime;
vTaskDelayUntil(&xlastwaketime,N);
区别
相对延时的时间不会包含任务本身的执行时间和任务被打断的时间,绝对延时的时间则会包含任务本身的执行时间和任务被打断的时间,这一点是两种延时函数之间的重要区别。
注:
如果任务延时过程中被打断的时间太长,回来之后延时都超过了,那么则会立马执行程序,不会再执行延时操作(任务不会再阻塞延时)。
如果vTaskDelayUntil()函数的任务优先级并非最高级,那么该任务可能被中断或者更高优先级的任务打断,若此时延时时间到了该任务将处于就绪态,但无法保证该任务能够马上执行。
上述的情况两个函数都有可能遇到,即使是vTaskDelayUntil也没有办法保证延时时间一定准确,实际项目还需要借助Tracealyzer等RTOS可视化分析工具进行分析。