【3】STM32·FreeRTOS·任务挂起和恢复

目录

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

1.1、任务挂起函数介绍

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

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

二、任务挂起与恢复实验


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

API函数描述
vTaskSuspend()挂起任务
vTaskResume()恢复被挂起的任务
xTaskResumeFromISR()在中断中恢复被挂起的任务

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

恢复:恢复被挂起的任务

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

1.1、任务挂起函数介绍

void vTaskSuspend(TaskHandle_t xTaskToSuspend);
形参描述
xTaskToSuspend待挂起任务的任务句柄

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

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

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

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

void vTaskResume(TaskHandle_t xTaskToResume);
形参描述
xTaskToResume待恢复任务的任务句柄

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

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

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

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

BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume);
形参描述
xTaskToResume待恢复任务的任务句柄

函数:xTaskResumeFromISR 返回值描述如下:

返回值描述
pdTRUE任务恢复后需要进行任务切换
pdFALSE任务恢复后不需要进行任务切换

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

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

二、任务挂起与恢复实验

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

四个任务的功能如下

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

task1:实现 LED0 每 500ms 闪烁一次

task2:实现 LED1 每 500ms 闪烁一次

task3:判断按键按下逻辑,KEY0 按下,挂起 task1,按下 KEY1 在任务中恢复 task1,按下 WKUP,在中断中恢复 task1(外部中断线实现)

这里需要设置中断优先级分组,将所有优先级位分配为抢占优先级位

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

任何其他配置都会使 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置与分配给各个外设中断的优先级之间的直接关系复杂化

main.c

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

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
    delay_init(168);                    /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
    led_init();                         /* 初始化LED */
    lcd_init();                         /* 初始化LCD */
    key_init();                         /* 初始化按键 */
    extix_init();                       /* 外部中断初始化 */

    freertos_demo();
}

freertos_demo.c

#include "freertos_demo.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); /* 任务函数 */

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

/* LCD刷屏时使用的颜色 */
uint16_t lcd_discolor[11] = {WHITE, BLACK, BLUE, RED,
                             MAGENTA, GREEN, CYAN, YELLOW,
                             BROWN, BRRED, GRAY};

/* FreeRTOS例程入口函数 */
void freertos_demo(void)
{
    lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);
    lcd_show_string(10, 47, 220, 24, 24, "Task Create & Del", RED);
    lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);

    lcd_draw_rectangle(5, 110, 115, 314, BLACK);
    lcd_draw_rectangle(125, 110, 234, 314, BLACK);
    lcd_draw_line(5, 130, 115, 130, BLACK);
    lcd_draw_line(125, 130, 234, 130, BLACK);
    lcd_show_string(15, 111, 110, 16, 16, "Task1: 000", BLUE);
    lcd_show_string(135, 111, 110, 16, 16, "Task2: 000", BLUE);

    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();
}

/* start_task */
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();                             /* 退出临界区 */
}

/* task1 */
void task1(void *pvParameters)
{
    uint32_t task1_num = 0;

    while (1)
    {
        lcd_fill(6, 131, 114, 313, lcd_discolor[++task1_num % 11]);
        lcd_show_xnum(71, 111, task1_num, 3, 16, 0x80, BLUE);
        LED0_TOGGLE();
        vTaskDelay(500);
    }
}

/* task2 */
void task2(void *pvParameters)
{
    uint32_t task2_num = 0;

    while (1)
    {
        lcd_fill(126, 131, 233, 313, lcd_discolor[11 - (++task2_num % 11)]);
        lcd_show_xnum(191, 111, task2_num, 3, 16, 0x80, BLUE);
        LED1_TOGGLE();
        vTaskDelay(500);
    }
}

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

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

        switch (key)
        {
        case KEY0_PRES: /* 挂起任务1 */
        {
            vTaskSuspend(Task1Task_Handler);
            break;
        }
        case KEY1_PRES: /* 恢复任务1 */
        {
            vTaskResume(Task1Task_Handler);
            break;
        }
        default:
        {
            break;
        }
        }

        vTaskDelay(10);
    }
}

freertos_demo.h

#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H

#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/LCD/lcd.h"
#include "FreeRTOS.h"
#include "task.h"

void freertos_demo(void);

#endif

exti.c

#include "./BSP/EXTI/exti.h"

/* task1任务句柄 */
extern TaskHandle_t Task1Task_Handler;

/* 外部中断初始化程序 */
void extix_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    key_init();

    gpio_init_struct.Pin = WKUP_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(EXTI0_IRQn, 5, 0); /* 抢占5,子优先级0 */
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);         /* 使能中断线0 */
}

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

/* 中断服务程序中需要做的事情,在HAL库中所有的外部中断服务函数都会调用此函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20); /* 消抖 */
    switch (GPIO_Pin)
    {
    case WKUP_GPIO_PIN:
        if (WK_UP == 1)
        {
            BaseType_t xYieldRequired;
            xYieldRequired = xTaskResumeFromISR(Task1Task_Handler); /* 恢复任务1 */
            if (xYieldRequired == pdTRUE)                           /* 恢复任务优先级高于当前任务优先级 */
                portYIELD_FROM_ISR(xYieldRequired);                 /* 进行任务切换 */
        }
        break;
    default:
        break;
    }
}

exti.h

#ifndef __EXTI_H
#define __EXTI_H

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/KEY/key.h"
#include "./BSP/LED/led.h"
#include "FreeRTOS.h"
#include "task.h"

void extix_init(void); /* 外部中断初始化 */

#endif
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HZU_Puzzle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值