FreeRTOS的任务挂起与恢复

一、任务挂起和恢复的API函数

1、任务挂起函数介绍

void vTaskSuspend(TaskHandle_t xTaskToSuspend) 

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

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

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

2、任务恢复函数介绍(任务中恢复)

void vTaskResume(TaskHandle_t xTaskToResume) 

使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1

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

3、任务恢复函数介绍(中断中恢复)

BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)  

使用该函数注意宏:INCLUDE_vTaskSuspendINCLUDE_xTaskResumeFromISR 必须定义为 1

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

注意:中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级

二、任务挂起与恢复实验

实验设计:将设计四个任务:start_task、task1、task2、task3

四个任务的功能如下:

1、main.c

在main.c中,初始化使用到的各个外设,再调用freertos_demo()函数即可,代码如下:

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
//#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./MALLOC/malloc.h"
#include "./BSP/EXTI/exti.h"

#include "freertos_demo.h"

int main(void)
{

    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
//    usmart_dev.init(72);                /* 初始化USMART */
    led_init();                         /* 初始化LED */
//    lcd_init();                         /* 初始化LCD */
    extix_init();                        /* 初始化外部中断按键 */
    key_init();                         /* 初始化按键 */
    my_mem_init(SRAMIN);                /* 初始化内部SRAM内存池 */
    
    freertos_demo();
}

2、exti.c

在exti.c中,初始化外部中断按键wk_up,然后判断按键按下时,将任务1恢复,注意按键的中断抢占优先级只能在5-15中选择,并且在stm32f1xx_hal.c中修改中断分组函数为HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);即4位抢占优先级,0位子优先级。

代码如下:

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/EXTI/exti.h"

#include "FreeRTOS.h"       //添加头文件
#include "task.h"

extern TaskHandle_t task1_hander;
/**
 * @brief       WK_UP 外部中断服务程序
 * @param       无
 * @retval      无
 */
void WKUP_INT_IRQHandler(void)
{ 
    HAL_GPIO_EXTI_IRQHandler(WKUP_INT_GPIO_PIN);        /* 调用中断处理公用函数 清除KEY_UP所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
    __HAL_GPIO_EXTI_CLEAR_IT(WKUP_INT_GPIO_PIN);        /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}

/**
 * @brief       中断服务程序中需要做的事情
                在HAL库中所有的外部中断服务函数都会调用此函数
 * @param       GPIO_Pin:中断引脚号
 * @retval      无
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20);      /* 消抖 */
    switch(GPIO_Pin)
    {
        BaseType_t xYieldRequired;
        case WKUP_INT_GPIO_PIN:
            if (WK_UP == 1)
            {
                xYieldRequired = xTaskResumeFromISR(task1_hander);//中断中恢复函数
                printf("在中断中恢复task1\r\n");
            }
            if (xYieldRequired == pdTRUE)               //需要进行任务切换
            {
                portYIELD_FROM_ISR(xYieldRequired);
            }
            break;
    }
}

/**
 * @brief       外部中断初始化程序
 * @param       无
 * @retval      无
 */
void extix_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    WKUP_GPIO_CLK_ENABLE();                                  /* WKUP时钟使能 */
    
    gpio_init_struct.Pin = WKUP_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_IT_RISING;             /* 上升沿触发 */
    gpio_init_struct.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct);        /* WKUP配置为下降沿触发中断 */

    HAL_NVIC_SetPriority(WKUP_INT_IRQn, 5, 0);               /* 抢占5,子优先级0 */
    HAL_NVIC_EnableIRQ(WKUP_INT_IRQn);                       /* 使能中断线0 */
}

3、freertos_demo.c

代码如下:

#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_TASK_STACK_SIZE   128
TaskHandle_t start_task_hander;
void start_task( void * pvParameters );

/* TASK1 任务配置 */
#define TASK1_PRIO         4
#define TASK1_STACK_SIZE   128
TaskHandle_t task1_hander;
void task1( void * pvParameters );

/* TASK2 任务配置 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t task2_hander;
void task2( void * pvParameters );

/* TASK3 任务配置 */
#define TASK3_PRIO         2
#define TASK3_STACK_SIZE   128
TaskHandle_t task3_hander;
void task3( void * pvParameters );



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


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",//任务名字
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,//堆栈大小
                (void *                 )   NULL,//入口参数
                (UBaseType_t            )   START_TASK_PRIO,//任务优先级
                (TaskHandle_t *         )   &start_task_hander);//任务句柄

    vTaskStartScheduler();//开启任务调度器
}

void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();//进入临界区
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",//任务名字
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,//堆栈大小
                (void *                 )   NULL,//入口参数
                (UBaseType_t            )   TASK1_PRIO,//任务优先级
                (TaskHandle_t *         )   &task1_hander);//任务句柄
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",//任务名字
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,//堆栈大小
                (void *                 )   NULL,//入口参数
                (UBaseType_t            )   TASK2_PRIO,//任务优先级
                (TaskHandle_t *         )   &task2_hander);//任务句柄

    xTaskCreate((TaskFunction_t         )   task3,
                (char *                 )   "task3",//任务名字
                (configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,//堆栈大小
                (void *                 )   NULL,//入口参数
                (UBaseType_t            )   TASK3_PRIO,//任务优先级
                (TaskHandle_t *         )   &task3_hander);//任务句柄
                
    vTaskDelete(NULL);//删除开始任务
    taskEXIT_CRITICAL();//退出临界区
}

/* 任务一:LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    uint32_t task1_num = 0;
    while(1)
    {
        printf("task1_num:%d\r\n", ++task1_num);
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}

/* 任务二:LED1每500ms翻转一次 */
void task2( void * pvParameters )
{
    uint32_t task2_num = 0;
    while(1)
    {
        printf("task2_num:%d\r\n", ++task2_num);
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}

/* 任务三:判断按键KEY0按下,按下KEY0删除task1 */
void task3( void * pvParameters )
{
    uint8_t key = 0;
    while(1)
    {
        taskENTER_CRITICAL();
        key = key_scan(0);
        if (key == KEY0_PRES)
        {
            printf("挂起task1\r\n");
            vTaskSuspend(task1_hander);//挂起任务1
        }
        else if (key == KEY1_PRES)
        {
            printf("任务中恢复task1\r\n");
            vTaskResume(task1_hander);//恢复任务1
        }
        taskEXIT_CRITICAL();
        vTaskDelay(1);
    }
}
    


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值