FreeRTOS基础(五):任务挂起与恢复

       今天我们将探讨FreeRTOS中的两个非常重要的函数:任务挂起和恢复函数。在实际的嵌入式系统开发中,我们常常需要在特定条件下暂停某些任务的执行,而在满足某些条件后再恢复这些任务的执行。这就像我们日常生活中的“暂停”和“继续”按钮。无论是为了节省资源,还是为了确保系统的稳定性,这两个操作都是至关重要的。通过理解和掌握任务的挂起与恢复,我们可以更灵活和高效地管理系统中的任务,确保各个任务能够协调运作,从而实现更稳定、更高效的系统表现。接下来,我们将深入了解如何使用这两个函数,以及它们在实际应用中的场景和注意事项。

一、任务挂起与恢复函数

二、任务挂起函数

使用前先使能API函数

三、任务恢复函数(任务中恢复)

使用前先使能API函数

四、FreeRTOS 中断优先级概述

         FreeRTOS 的配置文件 FreeRTOSConfig.h 中有两个关键宏定义:

configMAX_SYSCALL_INTERRUPT_PRIORITY  //定义了可以使用 FreeRTOS API 的最高中断优先级。
configKERNEL_INTERRUPT_PRIORITY      //定义了 FreeRTOS 内核的优先级

       我们知道,Stm32一共有10个系统中断(内核中断),FreeRTOS便可以对这些系统中断进行管理;

       第一个宏其实代表的是FreeRTOS可以管理的中断的最高的优先级;在 ARM Cortex-M 微控制器上,优先级数值越低,优先级越高。configMAX_SYSCALL_INTERRUPT_PRIORITY 通常设置为一个中等优先级数值。例如,如果 FreeRTOS 管理的最高优先级为 5,则 configMAX_SYSCALL_INTERRUPT_PRIORITY 可以设置为 5。

解释:中断优先级与 FreeRTOS API

        如果在中断服务程序(ISR)中调用 FreeRTOS 的 API 函数,该 ISR 的优先级必须小于或者等于 configMAX_SYSCALL_INTERRUPT_PRIORITY。这意味着中断优先级数值必须大于等于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的值。

         如果 ISR 的优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY(即数值低于 configMAX_SYSCALL_INTERRUPT_PRIORITY),在该 ISR 中调用 FreeRTOS API 函数可能会导致不可预期的行为,例如任务切换不正确或系统崩溃。这是因为 FreeRTOS 的调度器和其他 API 函数不是为在高优先级中断上下文中执行而设计的,即该中断不受FreeRTOS的管理。

#define configMAX_SYSCALL_INTERRUPT_PRIORITY 5

// 假设这是一个中断服务程序,优先级为6
void MyISR(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    // 恢复任务,只有优先级为6或更低的中断才能调用该函数
    vTaskResumeFromISR(xTaskHandle);

    // 如果恢复的任务优先级较高,可以请求上下文切换
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

五、任务恢复函数(中断中恢复)

使用前先使能API函数

六、任务挂起与恢复API函数解析(选学)

6.1 任务挂起函数vTaskSuspend( )

6.2 (任务中调用)任务恢复函数vTaskResume( )

6.3(中断中调用)任务恢复函数xTaskResumeFromISR( )

七、任务挂起与恢复实验

创建任务及实现任务函数:

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"



/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/

#define        START_TASK_STACK_SIZE  128   //定义堆栈大小为128字(1字等于4字节)
#define        START_TASK_PRIO         1    //定义任务优先级,0-31根据任务需求
TaskHandle_t   start_task_handler;    //定义任务句柄(结构体指针)
void start_task(void* args);




/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK1_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK1_PRIO         2             //定义任务优先级,0-31根据任务需求
TaskHandle_t   task1_handler;           //定义任务句柄(结构体指针)
void task1(void* args);




/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK2_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK2_PRIO         3             //定义任务优先级,0-31根据任务需求
TaskHandle_t   task2_handler;           //定义任务句柄(结构体指针)
void task2(void* args);



/**********************TASK3任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK3_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK3_PRIO         4            //定义任务优先级,0-31根据任务需求
TaskHandle_t   task3_handler;           //定义任务句柄(结构体指针)
void task3(void* args);




/*********开始任务用来创建其他三个任务,只创建一次,不能是死循环,同时创建完3个任务后删除任务1本身***********/
void start_task(void* args)
{
	taskENTER_CRITICAL();        /*进入临界区*/
	
	xTaskCreate( (TaskFunction_t)         task1,
                             (char *)     "task1",  
              ( configSTACK_DEPTH_TYPE)   TASK1_STACK_SIZE,
                            (void *)      NULL,
                            (UBaseType_t) TASK1_PRIO ,
                        (TaskHandle_t *)  &task1_handler );
							
	xTaskCreate( (TaskFunction_t)         task2,
                             (char *)     "task2",  
              ( configSTACK_DEPTH_TYPE)   TASK2_STACK_SIZE,
                            (void *)      NULL,
                            (UBaseType_t) TASK2_PRIO ,
                        (TaskHandle_t *)  &task2_handler );	

     xTaskCreate( (TaskFunction_t)         task3,
                             (char *)     "task3",  
              ( configSTACK_DEPTH_TYPE)   TASK3_STACK_SIZE,
                            (void *)      NULL,
                            (UBaseType_t) TASK3_PRIO ,
                        (TaskHandle_t *)  &task3_handler );	
							
	vTaskDelete(NULL);    //删除开始任务自身,传参NULL
							
	taskEXIT_CRITICAL();   /*退出临界区*/
		

    //临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式						
}




/********其余三个任务的任务函数,无返回值且是死循环***********/

/***任务1:实现LED0每500ms翻转一次*******/
void task1(void* args)
{
	uint32_t task1_num=0;
	while(1)
	{
		 printf("task1_num:%d\n",++task1_num);
		 GPIO_ToggleBits(GPIOF,GPIO_Pin_9 );
         vTaskDelay(500);       //FreeRTOS自带的延时函数
	
	}
	
	
}

/***任务2:实现LED1每500ms翻转一次*******/
void task2(void* args)
{
	uint32_t task2_num=0;
	while(1)
	{
		printf("task2_num:%d\n",++task2_num);
		 GPIO_ToggleBits(GPIOF,GPIO_Pin_10 );
         vTaskDelay(500);       //FreeRTOS自带的延时函数
	}
	
	
}


/***任务3:判断按键KEY0,按下KEY0,任务1删除*******/
void task3(void* args)
{
	while(1)
	{
		 
		 if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)  //表示按键Key0按下
	     {
			   vTaskSuspend(task1_handler);                         //挂起任务1
	     }	
         else if (GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)		//表示按键Key1按下
		 {
			 vTaskResume(task1_handler);                           //恢复任务1
		 }
		 vTaskDelay(10); 
	}
	
}





//FreeRTO入口例程函数,无参数,无返回值
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_handler );
							
							
	vTaskStartScheduler();  //开启任务调度器
	
}

主函数调用入口函数,操作系统开始进行任务的切换和调度

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "myled.h"
#include "mykey.h"
#include "myusart.h"

#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"

int main(void)
{
    //硬件初始化
     My_UsartInit();
     LED_Init();
     KEY_Init();
    
    //调用入口函数
     freertos_demo();
	

    
}

八、任务挂起与任务恢复函数的使用场景

8.1 .临界区保护

        在某些情况下,需要确保一段代码不被中断或其他任务打断。例如,在对共享资源进行操作时,可以使用任务挂起和恢复函数来实现临界区保护。

void vTaskSuspendAll( void )

可将所有任务挂起,实质是将任务调度器锁定。

// 共享资源操作示例
void critical_section(void) {
    // 挂起其他任务
    vTaskSuspendAll();

    // 临界区代码
    shared_resource++;

    // 恢复任务调度
    xTaskResumeAll();
}

8.2 资源管理

         在访问某些硬件资源(如SPI总线、I2C总线等)时,需要确保在使用资源期间不会被其他任务干扰。这时可以挂起其他可能访问该资源的任务,使用完毕后再恢复它们.

void access_resource_task(void *pvParameters) {
    // 挂起可能使用相同资源的任务
    vTaskSuspend(task_handle);

    // 操作硬件资源
    use_hardware_resource();

    // 恢复任务
    vTaskResume(task_handle);
}

8.3 任务间同步

       在某些场景下,可能需要一个任务等待另一个任务完成特定操作后再继续执行。可以通过挂起和恢复任务实现这种同步机制。

// 任务A
void taskA(void *pvParameters) {
    // 执行某些操作

    // 挂起任务A自己
    vTaskSuspend(NULL);

    // 当任务B完成操作后任务A将被恢复
}

// 任务B
void taskB(void *pvParameters) {
    // 执行任务A需要等待的操作

    // 恢复任务A
    vTaskResume(task_handleA);
}

        需要注意的是,滥用任务挂起和恢复函数可能导致系统响应变慢或引入难以调试的错误。在实际应用中,应尽量通过其他FreeRTOS提供的同步机制(如信号量、消息队列等)来实现任务间的协调和同步。

 至此,任务挂起与恢复函数就已经讲解完毕!初次学习,循序渐进,一步步掌握即可!以上就是全部内容!请务必掌握,创作不易,欢迎大家点赞加关注评论,您的支持是我前进最大的动力!下期再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/668382.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5月29日-shell复习

一.Shell概述 1)Linux提供的Shell解析器有:sudo cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh 2)bash和sh的关系 cd /bin ll | grep bash 或者使用:ls -l /bin/ | grep bash 3&#xff0…

力扣257. 二叉树的所有路径

思路&#xff1a;题目需要记录从根节点开始走的路径&#xff0c;无疑选用前序遍历&#xff0c;用一个数组paths 记录走过的节点信息&#xff0c;遇到叶子节点就用另一个list记录下路径&#xff0c;回溯时删掉paths尾节点即可 class Solution {public List<String> binar…

数学函数,字符串

目录 Math类 三角函数 指数函数 取整方法 其他方法 String类 常见方法 字符串比较方法 子串和数字与字符串的转换 Math类 Math类在java.lang中&#xff0c;不用显式引入。 三角函数 private static void triangleFunc() {double degree Math.toDegrees(Math.PI / 3…

PMP学习和考试难度分析

PMP&#xff08;项目管理专业人士&#xff09;考试目前是全球范围内比较具权威性和认可度的项目管理证书之一。因此PMP考试的难度是一个备受关注的话题。根据我们以往的学员经验我从不同角度解析PMP考试的难度&#xff0c;并提供一些应对挑战的建议。希望对大家有所帮助。 PMP考…

PPT 隐藏开启对象图层

目录预览 一、问题描述二、解决方案三、参考链接 一、问题描述 制作PPT的时候&#xff0c;有时候需要在一张PPT放置多个依次出现的内容&#xff0c;然后设置对应的动画&#xff0c;要是需要对某个内容进行修改的话&#xff0c;就会很不方便&#xff0c;这个时候就需要使用&…

JSL-11G定时限过流继电器 JOSEF约瑟

JSL系列定时限过流继电器型号&#xff1a; JSL-11定时限过流继电器; JSL-12定时限过流继电器; JSL-13定时限过流继电器&#xff1b; JSL-14定时限过流继电器&#xff1b; JSL-15定时限过流继电器&#xff1b; JSL-16定时限过流继电器; JSL-21定时限过流继电器; JSL-22定时限…

【数据结构】六种排序实现方法及区分比较

文章目录 前言插入排序希尔排序选择排序堆排序快速排序冒泡排序总结 前言 众所周知&#xff0c;存在许多种排序方法&#xff0c;作为新手&#xff0c;最新接触到的就是冒泡排序&#xff0c;这种排序方法具有较好的教学意义&#xff0c;但是实用意义不高&#xff0c;原因就在于…

【文件fd】回顾C语言文件操作 | 详细解析C语言文件操作写w追加a | 重定向和“w““a“

目录 前言 回顾C语言的操作 Q1 Q2 Q3 C语言文件操作 w方式 a方式 重定向和"w""a"方式 前言 前面进程虚拟地址空间让我们对进程的理解更加深入。在基础IO我们会详细介绍文件和文件系统。本专题的核心内容是文件。 深刻理解文件&#xff08;站在…

知识库管理系统:是什么、作用、如何搭建

你有没有遇到过这种情况&#xff1a;在工作中想要查找某个信息&#xff0c;查找了很多个文档还是没找到准确的信息&#xff1b;或者在团队中&#xff0c;总是在重复做着相同的资料搜集工作&#xff0c;浪费了大量时间和精力&#xff1f;如果你在烦恼这个问题&#xff0c;那么跟…

【Vue3】自定义组件directiveapp.use()

历史小剧场 崇祯很勤政&#xff0c;崇祯并非王国之君&#xff0c;弘光很昏庸&#xff0c;弘光活该倒霉&#xff0c;几百年来&#xff0c;我们都这样认为。 但我们之所以一直这样认为&#xff0c;只是因为有人这样告诉我们。 之所以有人这样告诉我们&#xff0c;是因为他们希望我…

Java | Leetcode Java题解之第121题买卖股票的最佳时机

题目&#xff1a; 题解&#xff1a; public class Solution {public int maxProfit(int prices[]) {int minprice Integer.MAX_VALUE;int maxprofit 0;for (int i 0; i < prices.length; i) {if (prices[i] < minprice) {minprice prices[i];} else if (prices[i] -…

PieCloudDB Database Flink Connector:让数据流动起来

面对客户环境中长期运行的各种类型的传统数据库&#xff0c;如何优雅地设计数据迁移的方案&#xff0c;既能灵活地应对各种数据导入场景和多源异构数据库&#xff0c;又能满足客户对数据导入结果的准确性、一致性、实时性的要求&#xff0c;让客户平滑地迁移到 PieCloudDB 数据…

快递100使用

1.快递100 接口文档 链接: 接口文档 2.授权参数 授权Key: qZgsNFSo5391 customer&#xff1a;8EEA8C4FB90B275E228CA322EF0E61E5 3.技术文档 链接: 技术文档 4.使用 <dependency><groupId>com.github.kuaidi100-api</groupId><artifactId>sdk&l…

AI大模型探索之路-实战篇12: 构建互动式Agent智能数据分析平台:实现多轮对话控制

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

【CPP】双端队列简介(deque)

简介&#xff1a;双端队列(deque) 目录 1.概述2.特点3.底层原理 1.概述 双端队列&#xff1a;是一种顺序表和顺序表的结合数据结构&#xff0c;不是队列。 它提供顺序表的[]下标访问和链表的中间头部的较高效率插入删除操作。 2.特点 顺序表的优缺点&#xff1a; 优点&…

网络安全基础技术扫盲篇 — 名词解释之“数据包“

用通俗易懂的话说&#xff1a; 数据包就像是一个信封。当你写信给某个人时&#xff0c;你将内容写在一张纸上&#xff0c;然后将纸叠起来并放入信封中&#xff0c;就形成了一个完整要发送的数据内容。信封上有发件人和收件人的详细地址&#xff0c;还有一些其他必要的信息&…

动态规划(Dynamic-Programming)问题讲解

动态规划类问题 从已知子问题的解&#xff0c;推导出当前问题的解 推导过程可以表达为一个数学公式用一维或二维数组来保存之前的计算结果&#xff08;可以进一步降维优化&#xff09; 将当前问题 分解成子问题 &#xff0c;找出递归公式&#xff0c;分阶段进行求解 求解过程中…

【scau大数据技术与原理2】综合性实验Spark集群的安装和使用——安装启动spark shell篇

实验内容简介&#xff1a; Spark是一个分布式计算框架&#xff0c;常用于大数据处理。本次实验中&#xff0c;首先设计一个包含主节点和从节点的Spark集群架构&#xff0c;并在CentOS的Linux环境下进行搭建。通过下载并解压Spark安装包&#xff0c;配置环境变量和集群参数&…

python分别保存聚类分析结果+KeyError: ‘CustomerID‘报错

如何在完成聚类分析后按聚类编号保存数据并且带上原数据所属ID # 将每个聚类的数据保存到不同的文件中 for cluster_id in range(6): # 假设共有6个聚类cluster_data data[data[cluster] cluster_id]cluster_data_with_customer_id cluster_data.copy()cluster_data_with_…

量化研究---强大的可转债分析系统上线,提供api,实时数据支持

今天把可转债实盘的分析模型拿出来&#xff0c;放在服务器方便选股分析&#xff0c;方便后面对接大qmt直接选股交易 强大的禄得可转债自定义因子轮动系统完成&#xff0c;可转债三低为例子 自定义因子实盘的框架 自定义因子轮动框架非常强大 网页 http://120.78.132.143:8023/…