FreeRTOS-事件组

目录

事件组

创建事件组

删除事件组

设置事件

等待事件

同步点

应用场景:等待多个事件

应用场景:任务同步


事件组

事件组可看成一个整形数,每一位代表一个事件。

每一位事件的含义由程序员决定,如位0表示串口是否就绪,位1表示按键是否被按下。

每一位的值:1表示事件发生,0表示事件还没发生。

一个或多个任务、ISR都可以去读、写位。

可以等待某一位,或等待某些位的任意一个,或等待多位。

事件组用一个整数表示,其中高8位留给内核使用,其他位可表示为事件。

如果configUSE_16_BIT_TICKS是1,就表示该处理器使用16位更高效,则整数是16位,低8位表示事件。

如果configUSE_16_BIT_TICKS是0,就表示该处理器使用32位更高效,则整数是32位,低24位表示事件。

创建事件组

/* 创建一个事件组,返回它的句柄。此函数内部会分配事件组结构体。* 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreate( void );/* 创建一个事件组,返回它的句柄。* 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针* 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );

删除事件组

对于动态创建的事件组,不再需要它们时,可以删除它们以回收内存。

/* xEventGroup: 事件组句柄,你要删除哪个事件组 */
void vEventGroupDelete( EventGroupHandle_t xEventGroup );

设置事件

/* 设置事件组中的位* xEventGroup: 哪个事件组* uxBitsToSet: 设置哪些位?* 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );/* 设置事件组中的位* xEventGroup: 哪个事件组* uxBitsToSet: 设置哪些位?* pxHigherPriorityTaskWoken: 有没有导致更高优先级的任务进入就绪态? pdTRUE-有, pdFALSE-没有* 返回值: pdPASS-成功, pdFALSE-失败
*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken );

注意:

ISR的函数,如队列函数xQueueSendToBackFromISR、信号量函数xSemaphoreGiveFromISR,它们会唤醒某个任务,最多只会唤醒一个任务。

但设置事件组时,可能导致多个任务被唤醒,会带来很大的不确定性。所以xEventGroupSetBitsFromISR函数不是直接去设置事件组,而是给一个FreeRTOS后台任务(daemon task)发送队列数据,由这个任务来设置事件组。

如果后台任务的优先级比当前被中断的任务优先级高,xEventGroupSetBitsFromISR会设置*ppxHigherPriorityTaskWoken为pdTRUE。

如果后台任务成功把队列数据发送给了后台任务,xEventGroupSetBitsFromISR的返回值就是pdPASS。

等待事件

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,	// 等待某个事件组const EventBits_t uxBitsToWaitFor,	// 等待某些位const BaseType_t xClearOnExit,		// pdTRUE:等待的位全部为1;pdFALSE:等待的位某个为1即可const BaseType_t xWaitForAllBits,	// pdTRUE:清除uxBitsToWaitFor指定的位;pdFALSE:不清除TickType_t xTicksToWait );			// 阻塞时间。0表示立即返回,portMAX_DELAY表示直到成功才返回。也可使用pdMS_TO_TICKS(ms)
// 返回值:返回事件值
//		如果期待的事件发生了,返回的是非阻塞条件成立的事件组
//		如果超时退出,返回的是超时时刻的事件值

可以使用xEventGroupWaitBits()等待期待的时间,发生之后再使用xEventGroupClearBits()来清除。但是这两个函数间有可能被其他任务或中断抢占,它们有可能会修改事件组。

可以使用设置xclearOnExit为pdTRUE,使得对事件组的测试、清零都在xEventGroupWaitBits()函数内部完成,这是一个原子操作。

同步点

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,	// 指定事件组const EventBits_t uxBitsToSet,		// 设置事件(位)const EventBits_t uxBitsToWaitFor,	// 等待事件(位)TickType_t xTicksToWait );			// 阻塞时间。0表示立即返回,portMAX_DELAY表示直到成功才返回。可使用pdMS_TO_TICKS(ms)
// 返回值:
// 		如果期待的事件发生了,返回的是非阻塞条件成立时的事件值
//		如果超时退出,返回的是超时时刻的事件值

成功返回后,会清除事件。

应用场景:等待多个事件

int main( void )
{prvSetupHardware();/* 创建递归锁 */xEventGroup = xEventGroupCreate( );if( xEventGroup != NULL ){/* 创建3个任务: 洗菜/生火/炒菜 */xTaskCreate( vWashingTask, "Task1", 1000, NULL, 1, NULL );xTaskCreate( vFiringTask, "Task2", 1000, NULL, 2, NULL );xTaskCreate( vCookingTask, "Task3", 1000, NULL, 3, NULL );/* 启动调度器 */vTaskStartScheduler();} else{/* 无法创建事件组 */} /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}static void vWashingTask( void *pvParameters )
{int i = 0;/* 无限循环 */for(;;){printf("I am washing %d time...\r\n", i++);/* 发出事件:我洗完菜了 */xEventGroupSetBits(xEventGroup, WASHING);/* 等待大厨炒完菜,再继续洗菜 */xEventGroupWaitBits(xEventGroup, COOKING, pdTRUE, pdTRUE, portMAX_DELAY);}
}static void vFiringTask( void *pvParameters )
{int i = 0;/* 无限循环 */for(;;){/* 等待洗完菜,才生火 */xEventGroupWaitBits(xEventGroup, WASHING, pdTRUE, pdTRUE, portMAX_DELAY);printf("I am firing %d time...\r\n", i++);/* 发出事件:我生好火了 */xEventGroupSetBits(xEventGroup, FIRING);		}
}static void vCookingTask( void *pvParameters )
{int i = 0;/* 无限循环 */for(;;){/* 等待两件事:洗完菜,生完火 */xEventGroupWaitBits(xEventGroup, WASHING | FIRING, pdTRUE, pdTRUE, portMAX_DELAY);printf("I am cooking %d time...\r\n", i++);/* 发出事件:我炒完菜了 */xEventGroupSetBits(xEventGroup, WASHING);}
}

实验现象:

I am washing 0 time...

I am firing 0 time...

I am cooking 0 time...

I am washing 1 time...

I am firing 1 time...

I am cooking 1 time...

...

应用场景:任务同步

int main( void )
{prvSetupHardware();/* 创建递归锁 */xEventGroup = xEventGroupCreate( );if( xEventGroup != NULL ){/* 创建3个任务: 洗菜/买酒/摆台 */xTaskCreate( vCookingTask, "task1", 1000, "A", 1, NULL );xTaskCreate( vBuyingTask, "task2", 1000, "B", 2, NULL );xTaskCreate( vTableTask, "task3", 1000, "C", 3, NULL );/* 启动调度器 */vTaskStartScheduler();} else{/* 无法创建事件组 */} /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */return 0;
}static void vCookingTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );int i = 0;/* 无限循环 */for( ;; ){/* 做自己的事 */printf("%s is cooking %d time....\r\n", (char *)pvParameters, i);/* 表示我做好了, 还要等别人都做好 */xEventGroupSync(xEventGroup, COOKING, ALL, portMAX_DELAY);/* 别人也做好了, 开饭 */printf("%s is eating %d time....\r\n", (char *)pvParameters, i++);vTaskDelay(xTicksToWait);}
}static void vBuyingTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );int i = 0;/* 无限循环 */for( ;; ){/* 做自己的事 */printf("%s is buying %d time....\r\n", (char *)pvParameters, i);/* 表示我做好了, 还要等别人都做好 */xEventGroupSync(xEventGroup, BUYING, ALL, portMAX_DELAY);/* 别人也做好了, 开饭 */printf("%s is eating %d time....\r\n", (char *)pvParameters, i++);vTaskDelay(xTicksToWait);}
}static void vTableTask( void *pvParameters )
{const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );int i = 0;/* 无限循环 */for( ;; ){/* 做自己的事 */printf("%s is do the table %d time....\r\n", (char *)pvParameters, i);/* 表示我做好了, 还要等别人都做好 */xEventGroupSync(xEventGroup, TABLING, ALL, portMAX_DELAY);/* 别人也做好了, 开饭 */printf("%s is eating %d time....\r\n", (char *)pvParameters, i++);vTaskDelay(xTicksToWait);}
}

实验现象:

C is do the table 0 time....

B is buying 0 time....

A is cooking 0 time....

C is eating 0 time....

B is eating 0 time....

A is eating 0 time....

C is do the table 1 time....

B is buying 1 time....

A is cooking 1 time....

C is eating 1 time....

B is eating 1 time....

A is eating 1 time....

...

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

快速掌握Pyqt5的9种显示控件

Pyqt5相关文章: 快速掌握Pyqt5的三种主窗口 快速掌握Pyqt5的2种弹簧 快速掌握Pyqt5的5种布局 快速弄懂Pyqt5的5种项目视图(Item View) 快速弄懂Pyqt5的4种项目部件(Item Widget) 快速掌握Pyqt5的6种按钮 快速掌握Pyqt5的10种容器&…

【带头学C++】----- 八、C++面向对象编程 ---- 8.10 函数的默认参数

8.10 函数的默认参数 C在声明函数原型的时可为一个或者多个参数指定默认(缺省)的参数值,当函数调用的时候如果没有指定这个值,编器会自动用默认值代替。 通过为函数参数指定默认值,可以在调用函数时省略相应的参数,而该参数将使用…

陶陶摘苹果、跳跃游戏

1. 陶陶摘苹果 题目描述: 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 30 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。 现在…

【MySQL源码】使用CLion 远程调试MySQL源码

目录 0 准备工作 1 IDE 2 下载MySQL源码 ​编辑 一 配置CLion 1 添加远程服务器 2 配置远程服务器环境 3 升级gdb版本 4 升级CMake版本 5 修改远程服务器文件上传的目录的对应关系 5 配置cmake 7 初始化MySQL 8 启动MySQL 作为DBA工作多年,如果还是停…

48个代码大模型汇总,涵盖原始、改进、专用、微调4大类

代码大模型具有强大的表达能力和复杂性,可以处理各种自然语言任务,包括文本分类、问答、对话等。这些模型通常基于深度学习架构,如Transformer,并使用预训练目标(如语言建模)进行训练。 在对大量代码数据的…

Leetcode(面试题 08.01.)三步问题

文章目录 前言一、题目分析二、算法原理1.状态表示2.状态转移方程3.初始化4.填表顺序5.返回值是什么 三、代码实现总结 前言 在本文章中,我们将要详细介绍一下Leetcode(面试题 08.01.)三步问题相关的内容 一、题目分析 1.小孩可以上一阶,两阶&#xff…

Shell脚本编程案例 – 批量创建特殊要求账户

Shell脚本编程案例 – 批量创建特殊要求账户 Shell Scripting Cases – Create a Bunch of accounts with special requests By JacksonML 本文简要介绍批量执行Shell脚本命令的基本思路,以检验shell脚本知识掌握情况。希望对读者有所帮助。 案例要求&#xff1a…

GO 集成Prometheus

一、Prometheus介绍 Prometheus(普罗米修斯)是一套开源的监控&报警&时间序列数据库的组合,起始是由SoundCloud公司开发的。随着发展,越来越多公司和组织接受采用Prometheus,社会也十分活跃,他们便…

Online ddl和replace ddl

在这个之前我们先来了解两种文件类型 1. .ibd文件 表数据文件,存储了表的数据和索引信息,从Mysql8开始表定义信息,从.frm文件改为.dcl文件存储,而表数据和索引信息仍然储存在.ibd文件,.idb文件通常在书籍库目录下。 …

初刷leetcode题目(10)——数据结构与算法

😶‍🌫️😶‍🌫️😶‍🌫️😶‍🌫️Take your time ! 😶‍🌫️😶‍🌫️😶‍🌫️😶‍🌫️…

PyQt6 QLCDNumber液晶数字显示控件

​锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计29条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话…

(Spring学习06)Spring之循环依赖底层源码解析

什么是循环依赖? 很简单,就是A对象依赖了B对象,B对象依赖了A对象。 比如: // A依赖了B class A{public B b; }// B依赖了A class B{public A a; }那么循环依赖是个问题吗? 如果不考虑Spring,循环依赖并不…

day31_servlet

今日内容 零、 复习昨日 一、请求转发 二、重定向 三、Session 四、Filter 零、 复习昨日 一、请求转发 1.1 现有问题 响应的代码与接收请求代码在一起查询全部的代码与登录的代码在一起,考虑一下后续删除完,更新完要查全部怎么办?这也没有遵循单一职责,不便于后期维护ps: 开…

1089 Insert or Merge (插入排序,相邻归并排序,附模拟实现)

注意点1:判断插入排序不能从头开始判断是否为目标数组, 比如:初始为1 2 3 4 3,目标数组也为1 2 3 4 3,则如果是从头开始推的,则下一步会变成1 2 3 4 3,而下一步应该是 1 2 3 3 4。所以我们应该…

vue3 setup语法糖,常用的几个:defineProps、defineEmits、defineExpose、

vue3和vue2组件之间传参的不同 <script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。 <script setup> 中的代码会在每次组件实例被创建的时候执行。 任何在 <script setup> 声明的顶层的绑定 (包括变量&#xff0c;函数声明&#xff0…

卓越进行时 | 赛宁联合国家一流网络安全学院探索校企合作新模式

为进一步探索网络安全教育技术产业融合发展的新机制新模式&#xff0c;全方位培养适应行业企业需求的复合型、创新型高素质网络安全人才。11月28日&#xff0c;南京赛宁信息技术有限公司&#xff08;赛宁网安&#xff09;与东南大学以优化产教融合发展原则&#xff0c;决定加强…

C++设计模式——Bridge模式(下)

在上篇 《C设计模式——Bridge模式&#xff08;上&#xff09;》中我们对于桥接模式做了一些介绍。介于桥接模式在实际项目开发中使用广泛&#xff0c;而且也是面试中常问常新的话题。在本篇&#xff0c;我们专注bridge模式在具体的项目开发中的应用&#xff0c;举几个例子来说…

服务器修复

服务器修复 主要服务器漏洞展示未禁用sync、shutdown、halt默认账户。未创建系统管理员、审计管理员、安全管理员账户设置系统管理员设置安全管理员 设置审计管理员配置PASS_MAX_DAYS 99999、PASS_MIN_LEN 5未配置TMOUT值配置HISTSIZE0未配置登录失败/密码复杂度策略umask值022…

2021年2月18日 Go生态洞察:Go 1.16中的新模块变化

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

数字时代的表演艺术:TikTok如何重新定义舞台

在数字时代的潮流中&#xff0c;TikTok崭露头角&#xff0c;重新定义了表演艺术的舞台。这款短视频应用不仅改变了用户与内容的互动方式&#xff0c;也为艺术家和创作者提供了全新的表达平台。本文将深入探讨TikTok如何在数字时代重新定义舞台&#xff0c;以及它对表演艺术的深…