5 FreeRTOS的任务挂起与恢复

1 任务挂起与恢复的API函数

API函数描述

vTaskSuspend()

挂起任务

vTaskResume()

恢复被挂起的任务

xTaskResumeFromISR()

在中断中恢复被挂起的任务

挂起:挂起任务类似暂停,可恢复;删除任务,无法恢复

恢复:恢复被挂起的任务

FromISR:带FromISR后缀是在中断函数中专用的API函数

1.1 任务挂起函数

void vTaskSuspend(TaskHandle_t xTaskToSuspend)    //xTaskToSuspend 待挂起任务的任务句柄

注意:

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

2)无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复

3)当传入的参数为NULL,则代表挂起任务自身(当前正在执行的任务)

1.2 任务恢复函数(任务中恢复)

void vTaskResume(TaskHandle_t xTaskToResume)  //xTaskToResume 待恢复任务的任务句柄

注意:任务无论被 vTaskSuspend()挂起多少次,只需在任务中调用vTaskResume()恢复一次,就可以继续运行。且被恢复的任务会进入就绪态。

1.3任务恢复函数(中断中恢复)

BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)   
//xTaskToResume待恢复任务的任务句柄

函数返回值描述如下:

返回值描述
pdTRUE任务恢复后需要进行任务切换(就是恢复的任务优先级大于当前正在执行的任务)
pdFALSE任务恢复后不需要进行任务切换

注意:

1)INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1。

2)该函数专用于中断服务函数中,用于解挂被挂起任务。

3)中断服务程序中调用FreeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级(FreeRTOS管理的优先级是5~15),如果中断优先级在0~4,比5~15中断优先级高,因此会报错。

4)任务优先级和中断优先级是有区别的,3)中的指的是中断优先级,任务优先级是数值越大,优先级越高;中断优先级是数值越小优先级越高。

使用中断恢复时需要更改:

* 都设置成抢占优先级,就是为了方便FreeRTOS方便管理

*抢占优先级最大设置为5

2 任务挂起与恢复实验

实验设计:将设计四个任务:start_tasktask1task2task3

start_task :用来创建其他的三个任务

task1 :实现LED0500ms闪烁一次

task2 :实现LED1500ms闪烁一次

task3 :判断按键按下逻辑,KEY0按下,挂起task1,按下KEY1在任务中恢复task1

中断中:按下KEY2,在中断中恢复task1(外部中断线实现)

//在任务中恢复
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 */

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */

/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 */

/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO      4                   /* 任务优先级 */
#define TASK3_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task3Task_Handler;  /* 任务句柄 */
void task3(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/

void freertos_demo(void)
{
   
    xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */
                (const char*    )"start_task",          /* 任务名称 */
                (uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传入给任务函数的参数 */
                (UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */
                (TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */
    vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    
	  /* 创建任务1 */
    xTaskCreate((TaskFunction_t )task1,
                (const char*    )"task1",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);
    
		/* 创建任务2 */
    xTaskCreate((TaskFunction_t )task2,
                (const char*    )"task2",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
								
		/* 创建任务3 */
    xTaskCreate((TaskFunction_t )task3,
                (const char*    )"task3",
                (uint16_t       )TASK3_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK3_PRIO,
                (TaskHandle_t*  )&Task3Task_Handler);
								
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
								
    taskEXIT_CRITICAL();            /* 退出临界区 */
}


void task1(void *pvParameters)
{
    uint32_t task1_num = 0;
    while(1)
    {
				printf("task1_num:%d\r\n",++ task1_num);
        LED0_TOGGLE();                                                  /* LED0闪烁 */
        vTaskDelay(500);                                               /* 延时500ms */
    }
}

void task2(void *pvParameters)
{  
	  uint32_t task2_num = 0;
    while(1)
    {
			  printf("task2_num:%d\r\n",++task2_num);
        LED1_TOGGLE();                                                  /* LED0闪烁 */
        vTaskDelay(500);                                                /* 延时500ms */
    }
}

/* 任务三:判断按键KEY0,按下KEY0删除task*/
void task3(void *pvParameters)
{
	uint8_t key = 0;
	while(1)
	{
		
		key = key_scan(0);
		if(key == KEY0_PRES)
		{
			printf("挂起task1\r\n");
			vTaskSuspend(Task1Task_Handler);
		}
		else if(key == KEY1_PRES)
		{
			printf("在任务中恢复task1\r\n");
			vTaskResume(Task1Task_Handler);
		}
		vTaskDelay(10);
	}
}
//在中断中恢复任务
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20);      /* 消抖 */
    switch(GPIO_Pin)
    {
			BaseType_t xYieldRequired;
        case KEY2_INT_GPIO_PIN:
            if (KEY2 == 0)
            {
               xYieldRequired = xTaskResumeFromISR(Task1Task_Handler);  
                //xYieldRequired用取函数返回值
            }
						if (xYieldRequired == pdTRUE)
                        //判断任务是否需要切换
						{
							printf("在中断中恢复task1\r\n");
							portYIELD_FROM_ISR(xYieldRequired);         
                            //调用该函数实现任务切换
						}
            break;
        default : break;
    }
}

3 总结

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值