FreeRTOS学习笔记(3)

4、任务挂起与恢复函数

4.1 任务挂起与恢复函数简介

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

恢复:恢复被挂起的任务

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

4.2 任务挂起函数介绍

void vTaskSuspend(TaskHandle_t xTaskToSuspend) 

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

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

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

4.3 任务恢复函数介绍

任务中恢复被挂起函数:void vTaskResume(TaskHandle_t xTaskToResume) 

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

注意:任务无论被挂起多少次,只需要在任务中调用vTaskResume()恢复一次,就可以继续运行。

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

中断中恢复被挂起函数: BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)  

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

什么时候需要进行任务切换:当恢复后的任务的优先级大于当前正在执行的任务的优先级,就需要进行任务的切换。

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

4.4 编程实战

 freertos_demo.c:

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 精英F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#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_STACK_SIZE 128
 #define START_TASK_PRIORITY   1
 TaskHandle_t  Start_Task_Handler;
 void start_task( void * pvParameters );
 
 /* Task1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK1_STACK_SIZE 128
 #define TASK1_PRIORITY   2
 TaskHandle_t  Task1_Handler;
 void task1( void * pvParameters );
 
 /* Task2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK2_STACK_SIZE 128
 #define TASK2_PRIORITY   3
 TaskHandle_t  Task2_Handler;
 void task2( void * pvParameters );
 
 /* Task3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK3_STACK_SIZE 128
 #define TASK3_PRIORITY   4
 TaskHandle_t  Task3_Handler;
 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_PRIORITY,
               (TaskHandle_t *        ) &Start_Task_Handler );
    vTaskStartScheduler();//开启任务调度器
}

 void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /*创建任务1*/
    xTaskCreate(( TaskFunction_t       ) task1,
               (char *                ) "task1", 
               (configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK1_PRIORITY,
               (TaskHandle_t *        ) &Task1_Handler );
    
    /*创建任务2*/
    xTaskCreate(( TaskFunction_t       ) task2,
               (char *                ) "task2", 
               (configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK2_PRIORITY,
               (TaskHandle_t *        ) &Task2_Handler );
               
    /*创建任务3*/
    xTaskCreate(( TaskFunction_t       ) task3,
               (char *                ) "task3", 
               (configSTACK_DEPTH_TYPE) TASK3_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK3_PRIORITY,
               (TaskHandle_t *        ) &Task3_Handler );
    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)
    {
        Key = key_scan(0);
        if(Key == KEY0_PRES)
        {
            printf("挂起task1\r\n");
            vTaskSuspend(Task1_Handler);
        }
        else if(Key == KEY1_PRES)
        {
            printf("在任务中恢复task1\r\n");
            vTaskResume(Task1_Handler);
        }
        vTaskDelay(10);
    }
}
 
 

exti.c:

/**
 ****************************************************************************************************
 * @file        exti.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-04-19
 * @brief       外部中断 驱动代码
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 STM32F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 * 修改说明
 * V1.0 20200420
 * 第一次发布
 *
 ****************************************************************************************************
 */

#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_Handler;

/**
 * @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_Handler);
               printf("在中断中恢复task1\r\n");
            }
            if(xYieldRequired == pdTRUE)
            {
                portYIELD_FROM_ISR( xYieldRequired );/*实现任务切换*/
            }
            break;
        default : 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 */
}












在编写代码时一定要注意:

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

如果优先级高于FreeRTOS管理的最高优先级,将会出现报错。

5、FreeRTOS的中断管理

5.1 中断管理简介

中断优先级的相关知识参考STM32学习笔记,在这里主要讲解中断优先级的设置

特点:

1、低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断里才允许调用FreeRTOS 的API函数。

2、建议将所有优先级位指定为抢占优先级位,方便FreeRTOS的管理。

3、中断优先级数值越小越优先,任务优先级数值越大越优先。

5.2 中断相关寄存器

三个系统中断优先级配置寄存器,分别为SHPR1、SHPR2、SHPR3

FreeRTOS中如何配置PendSV和Systick中断优先级呢?

通过左移位数来进行配置

三个中断屏蔽寄存器,分别为PRIMASK、FAULTMASK和BASEPRI。

5.3 编程实战

freertos_demo.c:

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 精英F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

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

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

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define START_TASK_STACK_SIZE 128
 #define START_TASK_PRIORITY   1
 TaskHandle_t  Start_Task_Handler;
 void start_task( void * pvParameters );
 
 /* Task1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 #define TASK1_STACK_SIZE 128
 #define TASK1_PRIORITY   2
 TaskHandle_t  Task1_Handler;
 void task1( 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_PRIORITY,
               (TaskHandle_t *        ) &Start_Task_Handler );
    vTaskStartScheduler();//开启任务调度器
}

 void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /*创建任务1*/
    xTaskCreate(( TaskFunction_t       ) task1,
               (char *                ) "task1", 
               (configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
               (void *                ) NULL,
               ( UBaseType_t          ) TASK1_PRIORITY,
               (TaskHandle_t *        ) &Task1_Handler );
    
    vTaskDelete(NULL);//删除开始任务
    taskEXIT_CRITICAL();            /* 退出临界区 */
}


/*任务一,实现LED0每500ms翻转一次*/
void task1( void * pvParameters )
{
    uint8_t task1_num = 0;
    while(1)
    {
        if(++task1_num == 5)
        {
            task1_num = 0;
            printf("关中断!!\r\n");
            portDISABLE_INTERRUPTS();
            delay_ms(5000);
            printf("开中断!!\r\n");
            portENABLE_INTERRUPTS();
        }
        vTaskDelay(1000);
    }
}



 
 

btim.c:
 

/**
 ****************************************************************************************************
 * @file        btim.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-04-20
 * @brief       基本定时器 驱动代码
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 STM32F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 * 修改说明
 * V1.0 20211216
 * 第一次发布
 *
 ****************************************************************************************************
 */

#include "./BSP/LED/led.h"
#include "./BSP/TIMER/btim.h"
#include "./SYSTEM/usart/usart.h"

TIM_HandleTypeDef g_timx_handle;  /* 定时器句柄 */
TIM_HandleTypeDef g_tim7_handle;  /* 定时器句柄 */

/**
 * @brief       基本定时器TIMX定时中断初始化函数
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
 *              基本定时器的时钟为APB1时钟的2倍, 而APB1为36M, 所以定时器时钟 = 72Mhz
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft=定时器工作频率,单位:Mhz
 *
 * @param       arr: 自动重装值。
 * @param       psc: 时钟预分频数
 * @retval      无
 */
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
    g_timx_handle.Instance = BTIM_TIMX_INT;                      /* 通用定时器X */
    g_timx_handle.Init.Prescaler = psc;                          /* 设置预分频系数 */
    g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_timx_handle.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_timx_handle);

    HAL_TIM_Base_Start_IT(&g_timx_handle);    /* 使能定时器x及其更新中断 */
}

/*TIM7初始化函数*/
void btim_tim7_int_init(uint16_t arr, uint16_t psc)
{
    g_tim7_handle.Instance = BTIM_TIM7_INT;                      /* 通用定时器X */
    g_tim7_handle.Init.Prescaler = psc;                          /* 设置预分频系数 */
    g_tim7_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_tim7_handle.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_tim7_handle);

    HAL_TIM_Base_Start_IT(&g_tim7_handle);    /* 使能定时器x及其更新中断 */
}

/**
 * @brief       定时器底层驱动,开启时钟,设置中断优先级
                此函数会被HAL_TIM_Base_Init()函数调用
 * @param       htim:定时器句柄
 * @retval      无
 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        BTIM_TIMX_INT_CLK_ENABLE();                     /* 使能TIM时钟 */
        HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 6, 0); /* 抢占6,子优先级0,组2 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITM3中断 */
    }
    if(htim->Instance == BTIM_TIM7_INT)
    {
        BTIM_TIM7_INT_CLK_ENABLE();                     /* 使能TIM时钟 */
        HAL_NVIC_SetPriority(BTIM_TIM7_INT_IRQn, 4, 0); /* 抢占4,子优先级0,组2 */
        HAL_NVIC_EnableIRQ(BTIM_TIM7_INT_IRQn);         /* 开启ITM7中断 */
    }
}

/**
 * @brief       定时器TIMX中断服务函数
 * @param       无
 * @retval      无
 */
void BTIM_TIMX_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handle); /* 定时器中断公共处理函数 */
}
/*TIM7中断服务函数*/
void BTIM_TIM7_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_tim7_handle); /* 定时器中断公共处理函数 */
}

/**
 * @brief       定时器更新中断回调函数
 * @param       htim:定时器句柄
 * @retval      无
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        printf("TIM6优先级为6正在运行!!!\r\n");
    }
    else if(htim->Instance == BTIM_TIM7_INT)
    {
        printf("TIM7优先级为4正在运行!!!\r\n");
    }
}




需要注意的是,当使用延时关中断时,不能调用系统的延时函数,只能使用用户自定义的delay函数,因为当调用系统延时函数时,将操作临界区,调用中断函数,打开中断。这就导致关闭后立即就打开了中断。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值