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”下面。

相关文章
arm-linux-gcc的下载与安装步骤
arm-linux-gcc的下载与安装步骤
1949 2
|
安全 物联网 传感器
带你读《工业物联网安全》之一:一个前所未有的机会
本书为读者提供了针对IIoT安全各个方面的综合理解,以及用来构建部署安全IIoT解决方案的实践技术。书中介绍IIoT安全的基本原则、威胁模型、参考架构,以及现实生活中的实例分析学习,涵盖了用来设计基于风险安全控制方案的各种实用工具,并且深入讨论了多层防御相关技术,包括IAM、终端安全、互联技术以及基于边界和云环境的应用。读者能够从本书中获得保护IIoT生命周期流程、标准化、治理与评估新兴技术适用性方面的实用经验,从而实现成规模、可靠且具有社会效益的互联系统。
|
存储 安全
什么是内存管理单元(MMU)?
【8月更文挑战第23天】
644 0
|
数据安全/隐私保护 Python
用python对文件内容进行加密的2种方式
这篇文章介绍了使用Python对文件内容进行加密的两种方式:利用`cryptography`库的Fernet对称加密和使用`rsa`库进行RSA非对称加密。
380 6
|
12月前
|
传感器 监控 JavaScript
千套单片机\stm32毕设课设题目及资料案列-干货分享
为帮助电子工程领域的学习者顺利毕业或掌握更多专业知识,我们精心整理了一系列单片机和STM32相关的题目及资料案例。这些资源覆盖了从毕业设计到课程设计的各个方面,包括但不限于智能小车、温度控制系统、无线通信、智能家居等多个领域。每项设计都配有详细的原理图、仿真图以及完整的文档资料,旨在帮助学生深入理解理论知识的同时,提高实际动手操作能力。无论是初学者还是有一定基础的学生,都能从中找到适合自己的项目进行实践探索。
2094 8
|
存储 安全 C++
【数据结构】无头+单向+非循环链表(SList)(增、删、查、改)详解
【数据结构】无头+单向+非循环链表(SList)(增、删、查、改)详解
|
C语言
C语言学习记录——枚举(定义、与结构体的区别、优点)
C语言学习记录——枚举(定义、与结构体的区别、优点)
230 3
Beckoff的EtherCAT从站代码架构解析
Beckoff的EtherCAT从站代码架构解析
|
传感器 监控 5G
|
移动开发 前端开发
VForm3的文件上传方式
VForm3的文件上传方式
528 0