FreeRTOS学习笔记—任务挂起和恢复

简介: 本文学习了FreeRTOS任务挂起和解挂的内容。编程实现了任务挂起和解挂。对于编程实现中的问题进行了分析总结。


🎀 文章作者:二土电子
🐸 期待大家一起学习交流!


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

在项目中有时我们会遇到某些任务需要暂停一段时间,过一段时间在重新运行的情况。任务挂起和恢复就满足了这种需求。当某个任务需要暂停一段时间时,可以将其挂起。当需要重新运行时,再恢复就可以了。。FreeRTOS 的任务挂起和恢复API函数如下

7382f5af8c8784c405a4d1997f00853e_5d243ad18217493b83157d42f3fa2888.png

1.1 vTaskSuspend()函数

该函数的功能是于将某个任务设置为挂起态。任务进入挂起态后,就永远都不会进入运行态。除非调用任务恢复函数 vTaskResume()或 xTaskResumeFromISR()。任务挂起函数有以下输入参数

  • xTaskToSuspend
    要挂起的任务的任务句柄。如果需要挂起任务自身,该参数写NULL。

任务挂起函数无返回值。

1.2 vTaskResume()函数

该函数的功能是将一个任务从挂起态恢复到就绪态。任务恢复函数有以下输入参数

  • xTaskToResume
    需要恢复的任务的任务句柄。

任务恢复函数也没有返回值。

1.3 xTaskResumeFromISR()函数

该函数的功能是在中断服务函数中恢复一个任务。该函数有以下输入参数

  • xTaskToResume
    要恢复的任务的任务句柄。

该函数有以下返回值

  • pdTRUE
    恢复运行的任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后必须进行一次上下文切换。
  • pdFALSE
    恢复运行的任务的任务优先级低于当前正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数的以后不需要进行上下文切换。

    二、任务挂起和恢复

    2.1 任务1挂起解挂任务2

    任务创建可以见上一篇,任务创建与删除。这里直接修改任务1。任务1修改为,运行10次任务1之后,将任务2挂起。再运行10次后,解挂任务2。任务1函数如下
void taks1_task (void *pxCreatedTask)
{
   
   
    u8 task1Cunt = 0;   // 任务1运行次数计数变量

    while (1)
    {
   
   
        task1Cunt = task1Cunt + 1;   // task1运行次数加1

        Med_Led_StateReverse(LED0);   // LED0状态取反
        vTaskDelay(500);   // 延时500ms

        // 运行5次后
        if (task1Cunt == 10)
        {
   
   
            // 挂起任务2
            vTaskSuspend(TASK2Task_Handler);
        }
        if (task1Cunt == 20)
        {
   
   
            // 解挂任务2
            vTaskResume(TASK2Task_Handler);
        }
    }
}

2.2 中断中解挂任务1

最开始尝试在外部中断中挂起和解挂任务1,发现挂起任务1时,程序异常。查询后发现,在中断中不能使用挂起函数。因此调整了一下,任务2运行5次后,挂起任务1。通过外部中断,解挂任务1。

在中断中解挂任务时注意,需要判断一下函数xTaskResumeFromISR()的返回值。如果函数xTaskResumeFromISR()返回值为pdTRUE,那么说明要恢复的这个任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),所以在退出中断的时候一定要进行上下文切换

外部中断程序配置如下

/*
 *==============================================================================
 *函数名称:Exit_Init
 *函数功能:初始化外部中断
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Exit_Init (void)
{
   
   
    NVIC_InitTypeDef NVIC_InitStructure;
    EXTI_InitTypeDef  EXTI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路

    //EXTI0 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6;   //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;   //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);       //根据指定的参数初始化VIC寄存器

    EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0
    EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断
    EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能
    EXTI_Init(&EXTI_InitStructure);
}

外部中断的中断服务函数如下

/*
 *==============================================================================
 *函数名称:EXTI0_IRQHandler
 *函数功能:外部中断0中断服务函数
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */

// 任务1的任务句柄
extern TaskHandle_t TASK1Task_Handler;

void EXTI0_IRQHandler(void)
{
   
   
    BaseType_t YieldRequired;    

    // 如果EXIT0中断标志位被置1
    if(EXTI_GetITStatus (EXTI_Line0)==1)
    {
   
   
        YieldRequired = xTaskResumeFromISR(TASK1Task_Handler);   // 恢复任务1

        if(YieldRequired == pdTRUE)
        {
   
   
            // 执行一次任务调度
            portYIELD_FROM_ISR(YieldRequired);
        }
    }
    EXTI_ClearITPendingBit (EXTI_Line0);   // 清除中断标志位
}

三、补充内容

3.1 FreeRTOS数据类型

在portmacro.h头文件,里面定义了2个数据类型

  • TickType_t
    FreeRTOS中断计数值类型,可以是16位也可以是32位,对于32位CPU来说TickType_t最好为32位。
  • BaseType_t
    能够让CPU运行效率最高的数据类型。对于32位CPU,BaseType_t就是uint32_t 。16位CPU就是uint16_t ,8位CPU就是uint8_t 。

    3.2 中断优先级分组

    优先级分组:中断控制器(NVIC)允许定义每个中断优先级的比特被分割成定义中断的优先级比特和定义中断的次优先级比特。为简单起见,必须将所有位定义为抢占优先位。如果不是这样(如果某些位表示次优先级),下面的断言将失败。

简单来说,就是在设置优先级分组时,需要将全部的位都设置为抢占优先级。否则会导致程序异常。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);   // 设置系统中断优先级分组4

3.3 错误问题

在编译时发现有下面的错误提示

b750e1fde954a81829f43df42b50fdc3_513b5c31b0df43cfae55a0648e64898a.png

该错误是因为“task.h”必须出现在“FreeRTOS.h”下面。

相关文章
|
6月前
【FreeRTOS】中断管理(三)
【FreeRTOS】中断管理
|
6月前
【FreeRTOS】中断管理(二)
【FreeRTOS】中断管理
116 0
|
6月前
|
Linux 调度
Linux进程状态
Linux进程状态
|
4月前
STM32CubeMX FreeRTOS 任务的挂起和恢复
STM32CubeMX FreeRTOS 任务的挂起和恢复
101 12
|
6月前
|
API C语言
【FreeRTOS】中断管理(一)
【FreeRTOS】中断管理
117 0
|
6月前
|
资源调度 调度 UED
CPU执行系统调用时发生中断,操作系统还能切回中断前的系统调用继续执行吗?
系统调用服务例程在执行过程中,通常不会被中断。系统调用服务例程的执行是一个原子操作,即在执行期间不会被中断。这是为了确保在系统调用服务例程执行期间对内核数据结构的一致性和完整性。
|
6月前
|
API 调度
FreeRTOS深入教程(中断管理)
FreeRTOS深入教程(中断管理)
294 0
|
6月前
|
调度
FreeRTOS深入教程(空闲任务和Tick中断深入分析)
FreeRTOS深入教程(空闲任务和Tick中断深入分析)
282 0
|
存储 算法 Linux
《Linux操作系统编程》第二章 进程运行与调度: 了解进程的定义与特征、进程的状态与切换、进程管理的数据结构、进程的创建与终止、阻塞与唤醒、挂起与激活以及处理机调度的相关概念
《Linux操作系统编程》第二章 进程运行与调度: 了解进程的定义与特征、进程的状态与切换、进程管理的数据结构、进程的创建与终止、阻塞与唤醒、挂起与激活以及处理机调度的相关概念
252 0
|
Linux
如何在Linux中挂起和恢复进程?
如何在Linux中挂起和恢复进程?
492 1