当前位置: 首页 > article >正文

FreeRTOS从入门到精通 第十五章(事件标志组)

参考教程:【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili

一、事件标志组简介

1、概述

(1)事件标志位是一个“位”,用来表示事件是否发生。

(2)事件标志组是一组事件标志位的集合,可以简单的理解事件标志组,是一个整数。

(3)事件标志组的特点:

①每一个位与一个事件相关联,高8位除外,高8位用作存储事件标志组的控制信息。(下图所示的是32 位长度的事件标志组)

②每一位事件的含义,以及高电平和低电平分别代表什么,由用户自己决定。

③任意任务或中断都可以读写这些位。

④可以等待某一位成立,或者等待多位同时成立。

(4)一个事件组就包含了一个EventBits_t数据类型的变量,变量类型EventBits_t的定义如下所示,它实际上是一个16位或32位无符号的数据类型。

typedef TickType_t EventBits_t;
#if ( configUSE_16_BIT_TICKS == 1 )typedef  uint16_t  TickType_t;
#elsetypedef  uint32_t  TickType_t;
#endif
#define  configUSE_16_BIT_TICKS    0 

(5)事件标志组与队列、信号量的区别:

功能

唤醒对象

事件清除

队列、信号量

事件发生时,只会唤醒一个任务

是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了

事件标志组

事件发生时,会唤醒所有符合条件的任务,可以理解为“广播”的作用

被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

2、事件标志组相关API函数介绍

(1)事件标志组相关API函数概览:

函数

描述

xEventGroupCreate()

使用动态方式创建事件标志组

xEventGroupCreateStatic()

使用静态方式创建事件标志组

xEventGroupClearBits()

清零事件标志位

xEventGroupClearBitsFromISR()

在中断中清零事件标志位

xEventGroupSetBits()

设置事件标志位

xEventGroupSetBitsFromISR()

在中断中设置事件标志位

xEventGroupWaitBits()

等待事件标志位

xEventGroupSync()

设置事件标志位,并等待另一个事件标志位【A事件完成,同时还要等待B事件发生】

(2)xEventGroupCreate函数:

①函数定义:

EventGroupHandle_t xEventGroupCreate
(void
)

②返回值:

返回值

描述

NULL 

事件标志组创建失败

其它值 

事件标志组创建成功,返回其句柄

(3)xEventGroupClearBits函数:

①函数定义:

EventBits_t  xEventGroupClearBits
(EventGroupHandle_t 	xEventGroup,const EventBits_t 		uxBitsToClear
) 

②函数参数:

形参

描述

xEventGroup 

待操作的事件标志组句柄

uxBitsToSet 

待清零的事件标志位

③返回值:

返回值

描述

整数 

清零事件标志位之前事件组中事件标志位的值

(4)xEventGroupSetBits函数:

①函数定义:

EventBits_t  xEventGroupSetBits
(EventGroupHandle_t 	xEventGroup,const EventBits_t 		uxBitsToClear
) 

②函数参数:

形参

描述

xEventGroup 

待操作的事件标志组句柄

uxBitsToSet 

待设置的事件标志位

③返回值:

返回值

描述

整数 

函数返回时,事件组中的事件标志位值

(5)xEventGroupWaitBits函数:

①函数定义:

EventBits_t xEventGroupWaitBits
(EventGroupHandle_t 	xEventGroup,const EventBits_t 		uxBitsToWaitFor,const BaseType_t 		xClearOnExit,const BaseType_t 		xWaitForAllBits,TickType_t 			xTicksToWait
)

②函数参数:

形参

描述

xEvenrGroup

等待的事件标志组句柄

uxBitsToWaitFor

等待的事件标志位,可以用逻辑或等待多个事件标志位

xClearOnExit

成功等待到事件标志位后,清除事件组中对应的事件标志位,

pdTRUE  :清除uxBitsToWaitFor指定位;

pdFALSE:不清除

xWaitForAllBits

等待 uxBitsToWaitFor 中的所有事件标志位(逻辑与)

pdTRUE:等待的位,全部为1

pdFALSE:等待的位,某个为1

xTicksToWait

等待的阻塞时间

③返回值:

返回值

描述

等待的事件标志位值 

等待事件标志位成功,返回等待到的事件标志位

其它值 

等待事件标志位失败,返回事件组中的事件标志位

(6)xEventGroupSync函数:

①函数定义:

EventBits_t xEventGroupSync
(EventGroupHandle_t 	xEventGroup,const EventBits_t 		uxBitsToSet,const EventBits_t 		uxBitsToWaitFor,TickType_t 			xTicksToWait
) 

②函数参数:

形参

描述

xEventGroup 

等待事件标志所在事件组

uxBitsToSet 

达到同步点后,要设置的事件标志

uxBitsToWaitFor 

等待的事件标志

xTicksToWait 

等待的阻塞时间

③返回值:

返回值

描述

等待的事件标志位值 

等待事件标志位成功,返回等待到的事件标志位

其它值 

等待事件标志位失败,返回事件组中的事件标志位

二、事件标志组实验

1、原理图与实验目标

(1)原理图(串口外设的接法与列表项的插入和删除实验相同,下图未示出):

(2)实验目标:

①设计3个任务——start_task、task1、task2:

[1]start_task:用于创建其它三个任务,并创建事件标志组。

[2]task1:读取按键按下键值,根据不同键值将事件标志组相应事件位置1,模拟事件发生(按下某个按键,对应的标志位置1)。

[3]task2:同时等待事件标志组中的多个事件位,当这些事件位都置1的话就执行相应的处理(串口打印信息),同时清除标志位。

②预期实验现象:

[1]程序下载到板子上后,暂时没有任何现象。

[2]按下相关按键,串口会输出相应的信息。

2、实验步骤

(1)将“队列集操作实验”的工程文件夹复制一份,在拷贝版中进行实验。

(2)更改FreeRTOS_experiment.c文件的内容,如下所示。

#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"
#include "Serial.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"//宏定义
#define START_TASK_STACK_SIZE 128   //start_task任务的堆栈大小
#define START_TASK_PRIO       1     //start_task任务的优先级
#define TASK1_STACK_SIZE      128   //task1任务的堆栈大小
#define TASK1_PRIO            2     //task1任务的优先级
#define TASK2_STACK_SIZE      128   //task2任务的堆栈大小
#define TASK2_PRIO            3     //task2任务的优先级#define EVENTBIT_0  (1 << 0)  //用该宏时表示希望事件标志组的bit0位置为1
#define EVENTBIT_1  (1 << 1)  //用该宏时表示希望事件标志组的bit1位置为1EventGroupHandle_t  eventgroup_handle;   //定义事件标志组句柄//任务函数声明
void start_task(void);
void task1(void);
void task2(void);//任务句柄
TaskHandle_t start_task_handler;    //start_task任务的句柄
TaskHandle_t task1_handler;         //task1任务的句柄
TaskHandle_t task2_handler;         //task2任务的句柄QueueSetHandle_t queueset_handle;void FreeRTOS_Test(void)
{//创建任务start_taskxTaskCreate((TaskFunction_t)start_task,            //指向任务函数的指针"start_task",                       //任务名字START_TASK_STACK_SIZE,       //任务堆栈大小,单位为字NULL,                          //传递给任务函数的参数START_TASK_PRIO,              //任务优先级(TaskHandle_t *) &start_task_handler  //任务句柄,就是任务的任务控制块);//开启任务调度器vTaskStartScheduler();
}void start_task(void)
{taskENTER_CRITICAL();eventgroup_handle = xEventGroupCreate();         //创建事件标志组if(eventgroup_handle != NULL){Serial_Printf("事件标志组创建成功!!\r\n");}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 );vTaskDelete(NULL);taskEXIT_CRITICAL();
}void task1(void)
{uint8_t key = 0;while(1) {key = Key_GetNum();if(key == 1){//将事件标志组的bit0位置1xEventGroupSetBits(eventgroup_handle, EVENTBIT_0);}else if(key == 2){//将事件标志组的bit1位置1xEventGroupSetBits(eventgroup_handle, EVENTBIT_1);}vTaskDelay(10);}
}void task2(void)
{EventBits_t event_bit = 0;while(1){event_bit = xEventGroupWaitBits(eventgroup_handle,         //事件标志组句柄EVENTBIT_0 | EVENTBIT_1,  //等待事件标志组的bit0和bit1位均置1pdTRUE,      //等待到事件标志位后,清除事件标志组的bit0和bit1位pdTRUE,      //等待事件标志组的bit0和bit1位都置1,就成立portMAX_DELAY );           //死等Serial_Printf("等待到的事件标志位值为:%#x\r\n",event_bit);}
}

(3)程序完善好后点击“编译”,然后将程序下载到开发板上,打开串口助手分析信息。

3、程序执行流程

(1)main函数全流程:

①初始化串口模块。

②调用FreeRTOS_Test函数。

(2)测试函数全流程:

①创建任务start_task。

②开启任务调度器。

(3)多任务调度执行阶段较为简单,这里不再赘述。

相关文章:

FreeRTOS从入门到精通 第十五章(事件标志组)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、事件标志组简介 1、概述 &#xff08;1&#xff09;事件标志位是一个“位”&#xff0c;用来表示事件是否发生。 &#xff08;2&#xff09;事件标志组是一组事件标志位的集合&#x…...

5 长度和距离计算模块(length.rs)

这段代码定义了一个泛型结构体 Length<T, Unit>&#xff0c;用于表示一维长度&#xff0c;其中 T 表示长度的数值类型&#xff0c;而 Unit 是一个编译时检查单位一致性的占位符类型&#xff0c;不会用于运行时表示长度的值。这个设计允许开发者在编译阶段确保不同单位之间…...

使用Pygame制作“俄罗斯方块”游戏

1. 前言 俄罗斯方块&#xff08;Tetris&#xff09; 是一款由方块下落、行消除等核心规则构成的经典益智游戏&#xff1a; 每次从屏幕顶部出现一个随机的方块&#xff08;由若干小方格组成&#xff09;&#xff0c;玩家可以左右移动或旋转该方块&#xff0c;让它合适地堆叠在…...

deepseek大模型本机部署

2024年1月20日晚&#xff0c;中国DeepSeek发布了最新推理模型DeepSeek-R1&#xff0c;引发广泛关注。这款模型不仅在性能上与OpenAI的GPT-4相媲美&#xff0c;更以开源和创新训练方法&#xff0c;为AI发展带来了新的可能性。 本文讲解如何在本地部署deepseek r1模型。deepseek官…...

常见“栈“相关题目

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 优选算法专题 目录 1047.删除字符串中的所有相邻重复项 844.比较含退格的字符串 227.基本计算器 II 394.字符串解码 946.验证栈序列 104…...

QT实现有限元软件操作界面

本系列文章致力于实现“手搓有限元&#xff0c;干翻Ansys的目标”&#xff0c;基本框架为前端显示使用QT实现交互&#xff0c;后端计算采用Visual Studio C。 本篇将二维矩形截面梁单元&#xff08;Rect_Beam2D2Node&#xff09;组成的钢结构桥作为案例来展示软件功能。 也可以…...

软件工程经济学-日常作业+大作业

目录 一、作业1 作业内容 解答 二、作业2 作业内容 解答 三、作业3 作业内容 解答 四、大作业 作业内容 解答 1.建立层次结构模型 (1)目标层 (2)准则层 (3)方案层 2.构造判断矩阵 (1)准则层判断矩阵 (2)方案层判断矩阵 3.层次单排序及其一致性检验 代码 …...

深度学习篇---深度学习框架

文章目录 前言第一部分&#xff1a;框架简介1. PyTorch简介特点动态计算图易于上手强大的社区支持与Python的集成度高 核心组件 2. TensorFlow简介特点静态计算图跨平台强大的生态系统Keras集成 核心组件 3. PaddlePaddle简介特点易于使用高性能工业级应用丰富的预训练模型 核心…...

Go学习:Go语言中if、switch、for语句与其他编程语言中相应语句的格式区别

Go语言中的流程控制语句逻辑结构与其他编程语言类似&#xff0c;格式有些不同。Go语言的流程控制中&#xff0c;包括if、switch、for、range、goto等语句&#xff0c;没有while循环。 目录 1. if 语句 2. switch语句 3. for语句 4. range语句 5. goto语句&#xff08;不常用…...

Java中初步使用websocket(springBoot版本)

一、什么是websocket WebSocket是一种在Web应用程序中实现实时双向通信的协议。它为浏览器和服务器之间提供了一种持久连接&#xff0c;在一个连接上可以双向传输数据。相比传统的HTTP协议&#xff0c;WebSocket具有更低的延迟和更高的效率。 WebSocket使用了类似于握手的方式来…...

Day50:字典的合并

在 Python 中&#xff0c;字典是一个可变的数据类型&#xff0c;经常需要将多个字典合并成一个字典。合并字典的方式有多种&#xff0c;今天我们将学习几种常见的方法。 1. 使用 update() 方法合并字典 update() 方法可以用来将一个字典中的键值对添加到另一个字典中。如果目…...

14-8C++STL的queue容器

一、queue容器 (1)queue容器的简介 queue为队列容器&#xff0c;“先进先出”的容器 (2)queue对象的构造 queue<T>q; queue<int>que Int;//存放一个int的queue容器 queue<string>queString;//存放一个string的queue容器 (3)queue容器的push()与pop()方…...

C++范围for和auto关键字

这里写目录标题 一.范围for的介绍与使用模版:⽰例:打印数组2. 方法如下⽰例:打印数组二.auto 关键字一.范围for的介绍与使用 模版: for ( 类型 变量名 : 数组名 )语句 //多条语句需要加⼤括号 ⽰例:打印数组 #include <iostream> using namespace std; int main()…...

【B站保姆级视频教程:Jetson配置YOLOv11环境(四)cuda cudnn tensorrt配置】

Jetson配置YOLOv11环境&#xff08;4&#xff09;cuda cudnn tensorrt配置 文章目录 0. 简介1. cuda配置&#xff1a;添加cuda环境变量2. cudnn配置3. TensorRT Python环境配置3.1 系统自带Python环境中的TensorRT配置3.2 Conda 虚拟Python环境中的TensorRT配置 0. 简介 官方镜…...

信号模块--simulink操作

位置simulink/sourses 常用的模块 功能&#xff1a;常数模块&#xff0c;提供一个常数 数据设置可以是一维或多维 一维数据设置 多维数据设置&#xff08;例三维数据设置&#xff09; 方波脉冲模块 模块用于按固定间隔生成方波脉冲信号 振幅就是方波的幅度&#xff0c;0到…...

强化学习笔记(3)——基于值函数的方法和策略梯度方法

分为两大类方法&#xff1a; 基于值函数的方法&#xff08;Temporal Difference Methods, TD Methods&#xff09; 策略梯度方法&#xff08;Policy Gradient Methods&#xff09;。 二者不同之处&#xff1a; 通过值函数来间接表达隐式的策略&#xff0c;一个是直接迭代优化策…...

新年新挑战:如何用LabVIEW开发跨平台应用

新的一年往往伴随着各种新的项目需求&#xff0c;而跨平台应用开发无疑是当前备受瞩目的发展趋势。在众多开发工具中&#xff0c;LabVIEW 以其独特的图形化编程方式和强大的功能&#xff0c;为开发跨平台应用提供了有效的途径。本文将深入探讨如何运用 LabVIEW 开发能够在不同操…...

事务04之死锁,锁底层和隔离机制原理

死锁和事务底层原理 文章目录 死锁和事务底层原理一&#xff1a;MySQL中的死锁现象1&#xff1a;何为死锁1.1&#xff1a;死锁的概念1.2&#xff1a;死锁产生的四个必要条件&#xff1a; 2&#xff1a;MySQL的死锁2.1&#xff1a;死锁的触发2.2&#xff1a;MySQL的死锁如何解决…...

第05章 17 Contour 过滤器介绍与例子

vtkContourFilter 是 VTK&#xff08;Visualization Toolkit&#xff09;中的一个关键类&#xff0c;用于从输入数据生成等值线或等值面。它是基于阈值的过滤器&#xff0c;可以从标量字段中提取等值线或等值面。vtkContourFilter 的核心功能是根据用户指定的值生成等值线或等值…...

Golang 并发机制-2:Golang Goroutine 和竞争条件

在今天的软件开发中&#xff0c;我们正在使用并发的概念&#xff0c;它允许一次执行多个任务。在Go编程中&#xff0c;理解Go例程是至关重要的。本文试图详细解释什么是例程&#xff0c;它们有多轻&#xff0c;通过简单地使用“go”关键字创建它们&#xff0c;以及可能出现的竞…...

【4Day创客实践入门教程】Day0 创想启程——课程与项目预览

Day0 创想启程——课程与项目预览 目录 Day0 创想启程——课程与项目预览前言学习内容基本的单片机开发技能简单的焊接技能简单的MicroPython程序 后记 Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4 迈…...

洛谷P3372 【模板】线段树 1以及分块

【模板】线段树 1 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行下面两种操作&#xff1a; 将某区间每一个数加上 k k k。求出某区间每一个数的和。 输入格式 第一行包含两个整数 n , m n, m n,m&#xff0c;分别表示该数列数字的个数和操作的总个数。 …...

(动态规划基础 打家劫舍)leetcode 198

已知h2和h1&#xff0c;用已知推出未知 推是求答案&#xff0c;回溯是给答案 这里图片给出dfs暴力&#xff0c;再进行记录答案完成记忆化搜索&#xff0c;再转为dp数组 #include<iostream> #include<vector> #include<algorithm> //nums:2,1,1,2 //dp:2,2,…...

Python 梯度下降法(四):Adadelta Optimize

文章目录 Python 梯度下降法&#xff08;四&#xff09;&#xff1a;Adadelta Optimize一、数学原理1.1 介绍1.2 实现流程 二、代码实现2.1 函数代码2.2 总代码 三、优缺点3.1 优点3.2 缺点 四、相关链接 Python 梯度下降法&#xff08;四&#xff09;&#xff1a;Adadelta Opt…...

旅行的意义:“诗与远方”和在旅途中找寻真我

原文链接&#xff1a;旅行的意义&#xff1a;“诗与远方”和在旅途中找寻真我 困在格子间&#xff0c;心向远方 清晨&#xff0c;闹钟催促&#xff0c;打工人挣扎起床出门。地铁拥挤&#xff0c;工作繁忙&#xff0c;加班成常态&#xff0c;下班时夜幕已深&#xff0c;满心疲惫…...

leetcode——将有序数组转化为二叉搜索树(java)

给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视为正确答…...

6 齐次坐标模块(homogen.rs)

homogen.rs代码定义了一个名为 HomogeneousVector 的结构体&#xff0c;它是用于表示三维空间中的齐次向量。齐次向量常用于计算机图形学和几何学中&#xff0c;特别是在处理投影和变换时。下面是对这段代码的详细解释和一些关键的代码片段分析&#xff1a; 一、homogen.rs文件…...

007 JSON Web Token

文章目录 https://doc.hutool.cn/pages/jwt/#jwt%E4%BB%8B%E7%BB%8D JWT是一种用于双方之间安全传输信息的简洁的、URL安全的令牌标准。这个标准由互联网工程任务组(IETF)发表&#xff0c;定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间作为JSON对象安全地传输信息。…...

Cursor 背后的技术栈:从 VS Code 到 AI 集成

引言 在当今快速发展的软件开发领域&#xff0c;开发者工具正在经历一场由人工智能&#xff08;AI&#xff09;驱动的革命。Cursor 作为一款新兴的智能编程助手&#xff0c;凭借其强大的 AI 能力和高效的开发体验&#xff0c;迅速吸引了大量开发者的关注。Cursor 不仅继承了 V…...

【Python蓝桥杯备赛宝典】

文章目录 一、基础数据结构1.1 链表1.2 队列1.3 栈1.4 二叉树1.5 堆二、基本算法2.1 算法复杂度2.2 尺取法2.3 二分法2.4 三分法2.5 倍增法和ST算法2.6 前缀和与差分2.7 离散化2.8 排序与排列2.9 分治法2.10贪心法1.接水时间最短问题2.糖果数量有限问题3.分发时间最短问题4.采摘…...