1、编写延迟列表
1.1、 在FreeRTOS文件夹下新建delay_list.c和delay_list.h文件,添加到工程中。
1.2、 撸代码
delay_list.c的代码
#include "delay_lists.h"
#include "sys_tick.h"
List_t xDelayedTaskList1;
List_t xDelayedTaskList2;
List_t * volatile pxDelayedTaskList;
List_t * volatile pxOverflowDelayedTaskList;
volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U;
/* 初始化延迟列表*/
void prvInitialiseDelayLists(void)
{
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
xNextTaskUnblockTime = portMAX_DELAY;
}
/*将任务从就绪列表移除。
判断对应的位是否存在任务,如果不存在则将对应的位清0
就算出延迟时间,添加到延迟列表当中。*/
void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait )
{
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount;
if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
}
xTimeToWake = xConstTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
if( xTimeToWake < xConstTickCount )
{
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
if( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake;
}
}
}
void prvResetNextTaskUnblockTime( void )
{
TCB_t *pxTCB;
if( listLIST_IS_EMPTY( pxDelayedTaskList ) != 0 )
{
xNextTaskUnblockTime = portMAX_DELAY;
} else
{
( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );
}
}
delay_list.h的代码
#ifndef __DELAY_LISTS_H__
#define __DELAY_LISTS_H__
#include "portmacro.h"
#include "list.h"
#include "task.h"
extern List_t * volatile pxDelayedTaskList;
extern List_t * volatile pxOverflowDelayedTaskList;
extern volatile TickType_t xNextTaskUnblockTime;
#define taskSWITCH_DELAYED_LISTS()\
{\
List_t *pxTemp;\
pxTemp = pxDelayedTaskList;\
pxDelayedTaskList = pxOverflowDelayedTaskList;\
pxOverflowDelayedTaskList = pxTemp;\
prvResetNextTaskUnblockTime();\
}
void prvInitialiseDelayLists(void);
void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait );
void prvResetNextTaskUnblockTime( void );
#endif
2、修改 vTaskDelay()函数
void vTaskDelay(const TickType_t xTicksToDelay)
{
TCB_t *pxTCB = NULL;
pxTCB = pxCurrentTCB;
// pxTCB->xTicksToDelay = xTicksToDelay;
// taskRESET_READY_PRIORITY( pxTCB->uxPriority );/* 任务就绪对应位置0*/
prvAddCurrentTaskToDelayedList( xTicksToDelay );
portYIELD();
}
3、修改 xTaskIncrementTick()函数
void xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
const TickType_t xConstTickCount = xTickCount + 1;
xTickCount = xConstTickCount;
if( xConstTickCount == ( TickType_t ) 0U )/*溢出*/
{
/* ①需要将pxDelayedTaskList和pxOverflowDelayedTaskList对换。
** ②计算出下一次延迟到达时间。
*/
taskSWITCH_DELAYED_LISTS();
}
if( xConstTickCount >= xNextTaskUnblockTime )
{
for( ;; )
{
if( listLIST_IS_EMPTY( pxDelayedTaskList ) != 0 )
{
xNextTaskUnblockTime = portMAX_DELAY;
break;
}else
{
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
if( xConstTickCount < xItemValue )
{
xNextTaskUnblockTime = xItemValue;
break;
}
( void ) uxListRemove( &( pxTCB->xStateListItem ) );//从延迟列表中移除
prvAddTaskToReadyList( pxTCB );//添加到就绪列表中
}
}
}/* xConstTickCount >= xNextTaskUnblockTime */
portYIELD();
}
4、修改main.c文件
int main(void)
{
/* 就绪列表初始化*/
prvInitialiseTaskLists();
/* 初始化延迟列表*/
prvInitialiseDelayLists();
运行结果如下。(和上上一章运行结果一样,没有任何变化。)
在延迟处理方面和之前的有本质的改变。
①当任务要延迟时,从就绪列表中移除,然后添加到延迟列表当中,最后切换任务。
②当任务延迟结束时,从延迟列表中移除,然后添加到就绪列表当中,最后切换任务。
是为了下一章实现时间片做铺垫。