FreeRTOS学习(六)

任务挂起与恢复的API函数

vTaskSuspend() 任务挂起函数。

vTaskResume() 任务恢复函数。

xTaskResumeFromISR() 在中断中恢复被挂起的任务函数。

任务挂起和删除任务的区别是任务挂起后可以恢复,任务删除后无法恢复。

任务恢复即恢复被挂起的任务。

带有"FromISR"后缀表示专门用在中断函数中的API函数。

vTaskSuspend()函数具体形式如下。

使用此函数用于挂起任务时,需要将宏INCLUDE_vTAaskSuspend配置为1。

无论任务优先级如何,只要任务被挂起,就不会执行任务。

当传入的参数是NULL时,则代表挂起任务自身。

 vTaskResume()函数具体形式如下。

使用此函数用于挂起任务时,需要将宏INCLUDE_vTaskSuspend配置为1。

任务无论使用vTaskSuspend()挂起多少次,只需要使用vTaskResume()恢复一次即可,且被恢复的任务会立即进入就绪态。

vTaskResumeFromISR()函数具体形式如下。

当恢复的任务的优先级高于当前执行的任务的优先级时,则任务恢复后需要进行任务切换,反之则不需要任务切换。

xTaskResumeFromISR()要将宏INCLUDE_vTaskSuspend和INCLUDE_xTaskResumeFromISR定义为1。

该函数专门用在中断服务函数中,用于恢复被挂起任务。

中断服务程序中要调用FreeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级,FreeRTOS中的中断优先级一般是5-15。

任务挂起和任务恢复

#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIORITY 1

#define START_TASK1_STACK_SIZE 128
#define START_TASK1_PRIORITY 2
#define START_TASK2_STACK_SIZE 128
#define START_TASK2_PRIORITY 3
#define START_TASK3_STACK_SIZE 128
#define START_TASK3_PRIORITY 4

void start_task(void* pvParameters);

void task1(void* pvParameters);
void task2(void* pvParameters);
void task3(void* pvParameters);

TaskHandle_t start_task_handler;

TaskHandle_t task1_handler;
TaskHandle_t task2_handler;
TaskHandle_t task3_handler;

void freertos_demo(void)
{
    /*创建任务start_task*/
    xTaskCreate(start_task, 
                "start_task",
                START_TASK_STACK_SIZE, 
                NULL, START_TASK_PRIORITY, 
                &start_task_handler);
    /*开启任务调度器*/
    vTaskStartScheduler();
}

void start_task(void* pvParameters)
{
    /*创建任务task1*/
    xTaskCreate(task1, 
                "task1",
                START_TASK1_STACK_SIZE, 
                NULL, START_TASK1_PRIORITY, 
                &task1_handler);

     /*创建任务task2*/
     xTaskCreate(task2, 
                 "task2",
                 START_TASK2_STACK_SIZE, 
                 NULL, START_TASK2_PRIORITY, 
                 &task2_handler);

     /*创建任务task3*/
     xTaskCreate(task3, 
                 "task3",
                 START_TASK3_STACK_SIZE, 
                 NULL, START_TASK3_PRIORITY, 
                 &task3_handler);

     /*删除任务 防止start_task多次创建Task1、Task2、Task3使得超出FreeRTOS提供的堆栈大小*/
     vTaskDelete(NULL);
     //vTaskDelete(start_task_handler);
}

/*LED0每500ms翻转一次*/
void task1(void* pvParameters)
{
    while(1)
    {
        LED0_TOGGLE();
        vTaskDelay(500); //系统延时函数
    }
}

/*LED1每500ms翻转一次*/
void task2(void* pvParameters)
{
    while(1)
    {
        LED1_TOGGLE();
        vTaskDelay(500); //系统延时函数
    }
}


void task3(void* pvParameters)
{
    uint8_t key = 0;

    while(1)
    {
        key = key_scan(0);

        if(key == KEY0_PRES)
        {
            vTaskSuspend(task1_handler);
        }
        else if(key == KEY1_PRES)
        {
            vTaskResume(task1_handler);
        }
        vTaskDelay(10);
    }
}

中断函数中使用xTaskResumeFromISR()恢复任务。

void HAL_GPIO_EXTI_CallBack(uint16_t GPIO_Pin)
{
    delay_ms(20);
    switch(GPIO_Pin)
    {
        BaseType_t xYieldRequired;
        case KEY_INT_GPIO_PIN;
            if(KEY2 == 0)
            {
                xYieldRequired = xTaskResumeFromISR(task1_handler);
            }
            if(xYieldRequired == pdTRUE)
            {
                /*进行任务切换*/
                portYIELD_FROM_ISR(xYieldRequired);
            }
            break;
        default:break;
    }
}

有两点需要关注,一是中断的抢占优先级的大小应该5-15之间。二是建议将所有的中断优先级指定为抢占优先级,也就是说,不留任何优先级位作为子优先级位,否则会使得FreeRTOS管理复杂化,可以通过NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)来确保所有优先级位分配为抢占优先级位。

挂起函数和恢复函数的内部实现

1.根据任务句柄获取TCB,若句柄为NULL,则挂起任务自身。

pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

通过函数prvGetTCBFromHandle() 从句柄xTaskToSuspend中获取TCB。

#define prvGetTCBFromHandle(pxHandle) (((pxHandle) == NULL) ? pxCurrentTCB : (pxHandle))

 (((pxHandle) == NULL) ? pxCurrentTCB : (pxHandle))是一个三目运算符,意思是如果pxHandle == NULL则使用pxCurrentTCB即当前任务控制块,否则则通过指针pxHandle指向其他TCB。

2.将要挂起的任务移除状态列表项和事件列表项。

/* Remove task from the ready/delayed list and place in thesuspended list. */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
    {
        taskRESET_READY_PRIORITY( pxTCB->uxPriority );
    }
else
    {
        mtCOVERAGE_TEST_MARKER();
    }
/* Is the task waiting on an event also? */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
    ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
    mtCOVERAGE_TEST_MARKER();
}

 3.将待挂起任务的任务状态列表插入到挂起态任务列表的末尾。

vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );

4.判断调度器是否运行,若运行则更新阻塞时间。

if( xSchedulerRunning != pdFALSE )
    {
        taskENTER_CRITICAL();
        {
            prvResetNextTaskUnblockTime();
        }
        taskEXIT_CRITICAL();
    }
else
    {
        mtCOVERAGE_TEST_MARKER();
    }

5.若挂起任务自身,继续判断调度器是否运行。若调度器正在运行,则进行一次强制任务切换。若调度器未运行,判断挂起任务数是否等于任务总数。若等于则表示所有任务均被挂起,则当前任务块赋值NULL。若不等于则通过函数vTaskSwitchContext寻找下一个最高优先级任务。

if( pxTCB == pxCurrentTCB )
{
    if( xSchedulerRunning != pdFALSE )
    {
        /* The current task has just been suspended. */
        configASSERT( uxSchedulerSuspended == 0 );
        portYIELD_WITHIN_API();
    }
    else
    {
        /* The scheduler is not running, but the task that was pointed
         * to by pxCurrentTCB has just been suspended and pxCurrentTCB
         * must be adjusted to point to a different task. */
        if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )                 
        /*lint !e931 Right has no side effect, just volatile. */
        {
            /* No other tasks are ready, so set pxCurrentTCB back to
             * NULL so when the next task is created pxCurrentTCB will
             * be set to point to it no matter what its relative priority
             * is. */
            pxCurrentTCB = NULL;
            }
            else
            {
                vTaskSwitchContext();
            }
      }
}
else
{
     mtCOVERAGE_TEST_MARKER();
}

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值