1. 任务延时相关API函数
函数 | 描述 |
---|---|
vTaskDelay() | 任务相对延时 |
vTaskDelayUntil() | 任务绝对延时,相对于任务相对延时而言,即以一定的周期执行任务函数 |
xTaskAbortDelay() | 任务中止延时函数,该函数能立即解除任务的阻塞状态,将任务插入就绪列表中 |
任务挂起中其它重要的API函数(介绍过的函数不列出,请参考前面的文章):
函数 | 描述 |
---|---|
prvAddCurrentTaskToDelayedList() | 将当前任务添加到延时列表或者溢出延时列表中 |
eTaskGetState() | 或者任务的状态,如运行态、挂起态、阻塞态等 |
2. 任务延时的基本概念
在FreeRTOS中任务的延时和阻塞都是以系统节拍时钟周期为单位,在FreeRTOSConfig.h中需要设置:
#define configTICK_RATE_HZ (1000) //时钟节拍频率,这里设置为1000,周期就是1ms
在FreeRTOS中,系统节拍时钟周期为时钟节拍频率的导数,即T=1/f,比如设置时钟节拍频率为1000,则系统节拍时钟周期为1/1000(s),即为1ms。当任务调度器正常工作时,每1ms产生一次节拍中断,同时变量xTickCount加1,xTickCount记录系统节拍时钟中断次数。当变量xTickCount累加到0xFFFF FFFF时,再增加1,则会溢出。
为了解决xTickCount溢出问题,在FreeRTOS中使用了两个延时列表:xDelayedTaskList1和xDelayedTaskList2,并且使用延时列表指针和溢出延时列表指针分别指向上面两个延时列表。在创建第一个任务时,会调用函数prvInitialiseTaskLists()来初始化两个指针。当xTickCount溢出时,会调用宏taskSWITCH_DELAYED_LISTS(),将延时列表指针和溢出延时列表指针交换,这样,不管时钟节拍数xTickCount在任意数值时,都可通过插入到延时列表或者溢出延时列表,实现数值为0xFFFF FFFF的时钟节拍数延时。
#define taskSWITCH_DELAYED_LISTS() \
{ \
List_t *pxTemp; \
configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \
\
/* 将指向延时列表和溢出延时列表的指针交换 */ \
pxTemp = pxDelayedTaskList; \
pxDelayedTaskList = pxOverflowDelayedTaskList; \
pxOverflowDelayedTaskList = pxTemp; \
\
xNumOfOverflows++; \
\
/* 重新获取下一次解除阻塞的时间 */ \
prvResetNextTaskUnblockTime(); \
}
说明:
- 在延时列表中,会根据任务的延时时间先后插入到延时列表中,延时时间短的在前,延时时间长的在后,同时下一个要唤醒的任务时间值保存在xNextTaskUnblockTime中。
- 系统节拍到达最近的唤醒时间时,系统会将应该唤醒的任务从延时列表中清除,并挂接到就绪列表中。
- 当系统节拍溢出后,延时列表变成溢出延时列表,溢出延时列表变成了延时列表。而原先的延时列表里的任务在系统节拍溢出之后肯定已经全部被超时唤醒。
3. 任务的相对延时函数vTaskDelay()
3.1 相对延时vTaskDelay()分析
使用任务的相对延时函数vTaskDelay()时,一般先执行完任务函数的主要功能模块,再以用户设置的时钟节拍数xTicksToDelay 延时任务函数。如果xTicksToDelay 设置为0,相当于只执行了一次任务切换。
使用此函数,需要将INCLUDE_vTaskDelay设置为1,在FreeRTOSConfig.h中定义。
函数原型如下:
/********************************************************
参数:xTicksToDelay :需要延时的时钟节拍数(0~0xFFFF FFFF)
返回:无
*********************************************************/
void vTaskDelay( const TickType_t xTicksToDelay )
函数源代码如下:
void vTaskDelay( const TickType_t xTicksToDelay )
{
BaseType_t xAlreadyYielded