1. 任务延时列表的工作原理
在FreeRTOS中,有一个任务延时列表,实际上有两个,为了方便讲解原理,我们假装合并为一个,其实两个的作用是一样的。当任务需要延时的时候,则先将任务挂起,即先将任务从就绪列表删除,然后插入到任务延时列表,同时更新下一个任务的解锁时刻变量:xNextTaskUnblockTime的值。
xNextTaskUnblockTime的值等于系统时基计数器的值xTickCount加上任务需要延时的值xTicksToDelay
任务延时列表表维护着一条双向链表,每个节点代表了正在延时的任务,节点按照延时时间大小做升序排列。每次在SysTick中断就比较一下系统时基计数器的值xTickCount与下一个任务的解锁时刻变量xNextTaskUnblockTime的值。
2. 实现任务延时列表
- 全部代码在task.c中添加和修改
FreeRTOS定义了两个任务延时列表,当系统时基计数器xTickCount没有溢出时,用一条列表,当xTickCount溢出后,用另外一条列表。
static List_t xDelayedTaskList1;
static List_t xDelayedTaskList2;
static List_t * volatile pxDelayedTaskList;
static List_t * volatile pxOverflowDelayedTaskList;
2.1 任务延时列表初始化
任务延时列表属于任务列表的一种,也是在prvInitialiseTaskLists()函数中初始化。
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
2.2 xNextTaskUnblockTime
xNextTaskUnblockTime是一个在task.c中定义的静态变量,用于表示下一个任务的解锁时刻。xNextTaskUnblockTime的值等于系统时基计数器的值xTickCount加上任务需要延时值xTicksToDelay。当系统时基计数器xTickCount的值与xNextTaskUnblockTime相等时,就表示有任务延时到期了,需要将该任务就绪。
xNextTaskUnblockTime在vTaskStartScheduler()函数中初始化为portMAX_DELAY
3. 修改代码
修改vTaskDelay()
实现prvAddCurrentTaskToDelayedList():添加当前任务到延时列表
修改xTaskIncrementTick():更新时基,在更新的过程中判断是否到期
实现taskSWITCH_DELAYED_LISTS():切换延时列表,实际就是更换pxDelayedTaskList和pxOverflowDelayedTaskList这两个指针的指向
实现prvResetNextTaskUnblockTime():更新xNextTaskUnblockTime的值
修改taskRESET_READY_PRIORITY():当任务要延时的时候,将任务从就绪列表移除,然后添加到延时列表,同时将任务在优先级位图表uxTopReadyPriority中对应的位清除。在清除任务在优先级位图表uxTopReadyPriority中对应的位的时候,需要判断就绪列表pxReadyTasksLists[]在当前优先级下对应的链表的节点是否为0,只有当该链表下没有任务时才真正地将任务在优先级位图表uxTopReadyPriority中对应的位清零。