Task.c文件:
全局变量:
static xListxDelayedTaskList1;
PRIVILEGED_DATA static xListxDelayedTaskList2;
< Delayed tasks (two lists are used - one fordelays that have overflowed the current tick count.
PRIVILEGED_DATA static xListxPendingReadyList;
任务控制块结构:
typedef struct tskTaskControlBlock
{
} tskTCB;
任务函数API:
主要分为以下几个:
任务创建:xTaskCreate()
删除:vTaskDelete()
优先级设置:vTaskPrioritySet()
任务挂起:vTaskSuspend()
任务唤醒:vTaskResume()
从中断函数唤醒:xTaskResumeFromISR()
禁止调度:vTaskSuspendAll()
允许调度:xTaskResumeAll()
一:任务创建。
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode,const signed char * const pcName, unsigned short usStackDepth, void*pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle*pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion* const xRegions )。
代码体概述:
1:分配TCB和任务堆栈
pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer);:
2:栈顶指针赋值:
3:初始化变量:名称,优先级,那两个列表项:xGenericItem,xEventItem
4:判断是否是第一个任务
下面列出函数体:
}
二:任务删除
freertos的任务删除分两步完成,
第一步在vTaskDelete中完成,FreeRTOS先把要删除的任务从就绪任务链表和事件等待链表中删除,然后把此任务添加到任务删除链表(即那个xTasksWaitingTermination
第2步 则是在idle任务中完成,idle任务运行时,检查xTasksWaitingTermination
void vTaskDelete( xTaskHandle pxTaskToDelete )
{
}
Idle任务。
static portTASK_FUNCTION( prvIdleTask, pvParameters)
{
( void ) pvParameters;
for( ;; )
{
prvCheckTasksWaitingTerm
…………………………….
这里prvCheckTasksWaitingTerm
static void prvCheckTasksWaitingTerm
{
#if ( INCLUDE_vTaskDelete == 1 )
{
portBASE_TYPE xListIsEmpty;
if( uxTasksDeleted > ( unsignedportBASE_TYPE ) 0 )
{//禁止调度
vTaskSuspendAll();
xListIsEmpty = listLIST_IS_EMPTY(&xTasksWaitingTermination
xTaskResumeAll();
if( !xListIsEmpty )
{
tskTCB *pxTCB;
//关中断
portENTER_CRITICAL();
{
pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( (( xList * ) &xTasksWaitingTermination
vListRemove( &(pxTCB->xGenericListItem ) );
--uxCurrentNumberOfTasks;
--uxTasksDeleted;
}
portEXIT_CRITICAL();
//释放内存,删除tcb
prvDeleteTCB( pxTCB );
}
}
}
#endif
}
三:禁止调度,打开调度
调度器的禁止和打开
这是一种同步机制,比关中断要温和点。禁止调度由vTaskSuspendAll实现,打开调度由xTaskResumeAll实现。
void vTaskSuspendAll( void )
{
portENTER_CRITICAL();
++uxSchedulerSuspended;
portEXIT_CRITICAL();
}
这个很简单,系统维护一个计数uxSchedulerSuspended,当它大于0时候表示禁止调度,等于0则打开调度(允许调度)。
signed portBASE_TYPE xTaskResumeAll( void )
{
register tskTCB *pxTCB;
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
在禁止调度器件,如果ISR导致一个任务就绪,这个任务会放在xPendingReadyList中,一旦调度允许,必须把所有的xPendingzList中的任务移动到theappropriate ready list中。
portENTER_CRITICAL();
{//将计数减一
--uxSchedulerSuspended;
//如果等于0,则允许调度
if( uxSchedulerSuspended == ( unsignedportBASE_TYPE ) pdFALSE )
{
if( uxCurrentNumberOfTasks > (unsigned portBASE_TYPE ) 0 )
{
portBASE_TYPE xYieldRequired = pdFALSE;
while( ( pxTCB = ( tskTCB * )listGET_OWNER_OF_HEAD_ENTRY(
{
vListRemove( &(pxTCB->xEventListItem ) );
vListRemove( &(pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB );
if( pxTCB->uxPriority>= pxCurrentTCB->uxPriority )
{
xYieldRequired = pdTRUE;
}
}
if( uxMissedTicks > ( unsignedportBASE_TYPE ) 0 )
{
while( uxMissedTicks > ( unsignedportBASE_TYPE ) 0 )
{
vTaskIncrementTick();
--uxMissedTicks;
}
#if configUSE_PREEMPTION == 1
{
xYieldRequired = pdTRUE;
}
#endif
}
if( ( xYieldRequired == pdTRUE ) || ( xMissedYield== pdTRUE ) )
{
xAlreadyYielded = pdTRUE;
xMissedYield = pdFALSE;
taskYIELD();
}
}
}
}
portEXIT_CRITICAL();
return xAlreadyYielded;
}
四:任务的挂起与唤醒。
freertos的任务挂起与ucosii也不大一样。它把 所有挂起的任务加到xSuspendedTaskList中,而且一旦调用vTaskSuspend()函数挂起一个任务,该任务就将从所有它原先连入的链表中删除(包括就绪表,延时表和它等待的事件链表),也就是说,和ucosii不同,一旦一个任务被挂起,它将取消先前它的延 时和对事件的等待。ucosii中是不同的,在ucosii里 面一个任务被挂起仅仅是把任务的状态或上一个OS_STAT_SUSPEND并从就绪表中删除,如果先前这个任务正在等待某事件,则并不取消等待。
//如果传进来的pxTaskToSuspend==NULL,则表示挂起当前任务
void vTaskSuspend( xTaskHandle pxTaskToSuspend)
{
tskTCB *pxTCB;
taskENTER_CRITICAL();
{
if( pxTaskToSuspend == pxCurrentTCB )
{
pxTaskToSuspend = NULL;
}
pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
traceTASK_SUSPEND( pxTaskToSuspend );
vListRemove( &(pxTCB->xGenericListItem ) );
if(pxTCB->xEventListItem.pvContainer )
{
vListRemove( &(pxTCB->xEventListItem ) );
}
//插到xSuspendedTaskList
vListInsertEnd( ( xList * )&xSuspendedTaskList, &(pxTCB->xGenericListItem ) );
}
taskEXIT_CRITICAL();
if( ( void * ) pxTaskToSuspend == NULL )
{
taskYIELD();///又是调度。
}
}
相反的唤醒就是把任务从xSuspendedTaskList中删除,加到对应的就绪链表中(根据任务的优先级),然后如果唤醒的任务优先级高于当前任务优先级,则调度。
void vTaskResume( xTaskHandle pxTaskToResume )
{
tskTCB *pxTCB;
pxTCB = ( tskTCB * ) pxTaskToResume;
if( pxTCB != NULL )
{
taskENTER_CRITICAL();
{
if( prvIsTaskSuspended( pxTCB ) == pdTRUE )
{
traceTASK_RESUME( pxTCB );
vListRemove(
prvAddTaskToReadyQueue( pxTCB );
if( pxTCB->uxPriority>= pxCurrentTCB->uxPriority )
{
taskYIELD();
}
}
}
taskEXIT_CRITICAL();
}
}
#endif
上面两种唤醒不大一样:
任务重唤醒:可以直接进行任务调度(如果唤醒的优先级比正在运行的优先级高)。
中断唤醒:最多可以把被唤醒的任务加入到就绪表或者pendinglist中,返回可以进行调度标志变量。
五:设置优先级
#endif
#if ( INCLUDE_vTaskPrioritySet == 1 )
#endif