FreeRTOS 24:事件组EventGroup等待、清零、获取操作

等待事件标志位xEventGroupWaitBits()

既然标记了事件的发生,那么我怎么知道他到底有没有发生,这也是需要一个函数来获 取 事 件 是 否 已 经 发 生 , FreeRTOS 提 供 了 一 个 等 待 指 定 事 件 的 函 数 — —
xEventGroupWaitBits(),通过这个函数, 任务可以知道事件标志组中的哪些位,有什么事件发生了, 然后通过 “逻辑与”、“逻辑或”等操作对感兴趣的事件进行获取,并且这个函数实现了等待超时机制, 当且仅当任务等待的事件发生时,任务才能获取到事件信息。在这段时间中,如果事件一直没发生,该任务将保持阻塞状态以等待事件发生。当其它任务或中断服务程序往其等待的事件设置对应的标志位,该任务将自动由阻塞态转为就绪态。当任务等待的时间超过了指定的阻塞时间,即使事件还未发生,任务也会自动从阻塞态转移为就绪态。这样子很有效的体现了操作系统的实时性,如果事件正确获取(等待到) 则返回对应的事件标志位,由用户判断再做处理, 因为在事件超时的时候也会返回一个不能确定的事件值,所以需要判断任务所等待的事件是否真的发生。

EventGroupWaitBits()用于获取事件组中的一个或多个事件发生标志, 当要读取的事件标 志 位 没 有 被 置 位 时 任 务 将 进 入 阻 塞 等 待 状 态 。

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )
{EventGroup_t * pxEventBits = xEventGroup;EventBits_t uxReturn, uxControlBits = 0;BaseType_t xWaitConditionMet, xAlreadyYielded;BaseType_t xTimeoutOccurred = pdFALSE;// 检查用户是否尝试等待内核自身使用的位,并且至少请求了一个位configASSERT( xEventGroup );configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );configASSERT( uxBitsToWaitFor != 0 );#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ){configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );}#endifvTaskSuspendAll();{const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;// 检查等待条件是否已经满足xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );if( xWaitConditionMet != pdFALSE ){// 等待条件已经满足,无需阻塞uxReturn = uxCurrentEventBits;xTicksToWait = ( TickType_t ) 0;// 如果需要,清除等待的位if( xClearOnExit != pdFALSE ){pxEventBits->uxEventBits &= ~uxBitsToWaitFor;}else{mtCOVERAGE_TEST_MARKER();}}else if( xTicksToWait == ( TickType_t ) 0 ){// 等待条件未满足,但未指定阻塞时间,直接返回当前值uxReturn = uxCurrentEventBits;xTimeoutOccurred = pdTRUE;}else{// 任务将阻塞等待所需位被设置// 使用控制位记录此调用的行为if( xClearOnExit != pdFALSE ){uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;}else{mtCOVERAGE_TEST_MARKER();}if( xWaitForAllBits != pdFALSE ){uxControlBits |= eventWAIT_FOR_ALL_BITS;}else{mtCOVERAGE_TEST_MARKER();}// 将调用任务等待的位存储在任务的事件列表项中,以便内核知道何时找到匹配项vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );// 这是过时的,但在某些编译器中如果不这样做会生成警告uxReturn = 0;traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );}}xAlreadyYielded = xTaskResumeAll();if( xTicksToWait != ( TickType_t ) 0 ){if( xAlreadyYielded == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}// 任务阻塞等待所需位被设置,此时要么所需位已被设置,要么阻塞时间已到期// 如果所需位已被设置,它们将存储在任务的事件列表项中,现在应检索并清除uxReturn = uxTaskResetEventItemValue();if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ){taskENTER_CRITICAL();{// 任务超时,返回当前事件位值uxReturn = pxEventBits->uxEventBits;// 可能在任务离开阻塞状态和再次运行之间更新了事件位if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ){if( xClearOnExit != pdFALSE ){pxEventBits->uxEventBits &= ~uxBitsToWaitFor;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}xTimeoutOccurred = pdTRUE;}taskEXIT_CRITICAL();}else{// 任务因位被设置而解除阻塞}// 任务阻塞,因此可能设置了控制位uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;}traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );// 防止编译器警告( void ) xTimeoutOccurred;return uxReturn;
}

xEventGroupWaitBits 函数用于等待事件组中的特定事件位被设置。具体功能和步骤如下:

  1. 参数检查

    • 检查传入的事件组是否有效。

    • 检查等待的位是否包含内核自身使用的位。

    • 检查至少请求了一个位。

    • 如果配置了 INCLUDE_xTaskGetSchedulerState 或 configUSE_TIMERS,则检查调度器是否暂停并且等待时间不为零。

  2. 任务调度暂停

    • 暂停任务调度,防止其他任务干扰。

  3. 检查当前事件位

    • 获取当前事件位。

    • 检查等待条件是否已经满足。

      • 如果满足,直接返回当前事件位,并根据需要清除这些位。

      • 如果不满足且未指定阻塞时间,直接返回当前事件位并设置超时标志。

      • 如果不满足且指定了阻塞时间,将任务加入等待队列。

  4. 任务阻塞

    • 根据需要设置控制位,记录任务的行为。

    • 将任务加入等待队列,等待所需事件位被设置。

    • 恢复任务调度。

  5. 任务唤醒

    • 如果任务因事件位被设置而唤醒,返回当前事件位。

    • 如果任务因超时而唤醒,返回当前事件位并设置超时标志。

  6. 清除控制位

    • 返回前清除控制位,防止影响后续操作。

清零事件标志位

xEventGroupClearBits()与 xEventGroupClearBitsFromISR()都是用于清除事件组指定的位, 如果在获取事件的时候没有将对应的标志位清除, 那么就需要用这个函数来进行显式清除, xEventGroupClearBits()函数不能在中断中使用,而是由具有中断保护功能 的xEventGroupClearBitsFromISR() 来代替,中断清除事件标志位的操作在守护任务(也叫定时 器 服 务 任 务 ) 里 面 完 成 。 守 护 进 程 的 优 先 级 由 FreeRTOSConfig.h 中 的 宏configTIMER_TASK_PRIORITY 来 定 义 。

xEventGroupClearBits()清零事件标志位

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear )
{EventGroup_t * pxEventBits = xEventGroup;EventBits_t uxReturn;/* 检查用户是否尝试清除内核自身使用的位 */configASSERT( xEventGroup );configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );taskENTER_CRITICAL();{traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );/* 返回值是清除位之前的事件组值 */uxReturn = pxEventBits->uxEventBits;/* 清除指定的位 */pxEventBits->uxEventBits &= ~uxBitsToClear;}taskEXIT_CRITICAL();return uxReturn;
}

函数 xEventGroupClearBits,用于清除事件组中的指定位。

  1. 参数检查

    • configASSERT( xEventGroup );:检查事件组句柄是否有效。
    • configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );:确保要清除的位不包含内核保留的位。
  2. 进入临界区

    • taskENTER_CRITICAL();:进入临界区,防止多任务环境下的并发问题。
  3. 记录当前事件组值

    • uxReturn = pxEventBits->uxEventBits;:在清除位之前,记录当前事件组的值。
  4. 清除指定位

    • pxEventBits->uxEventBits &= ~uxBitsToClear;:通过按位与操作清除指定的位。
  5. 退出临界区

    • taskEXIT_CRITICAL();:退出临界区。
  6. 返回结果

    • return uxReturn;:返回清除位之前的事件组值。

xEventGroupClearBitsFromISR()在中断中清零事件标志位

#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear )
{BaseType_t xReturn;// 记录从中断服务例程清除事件组位的操作traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );// 将清除位的操作挂起到调度器,以便在合适的时机执行xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); /*lint !e9087 无法避免将指针强制转换为 void*,因为这是一个通用的回调函数,不是特定于此用例的。回调会将指针重新转换为原始类型,因此是安全的。 */// 返回挂起结果return xReturn;
}#endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */

函数 xEventGroupClearBitsFromISR,用于在中断服务例程(ISR)中清除事件组中的指定位。具体功能如下:

  1. 参数检查:无显式的参数检查,但通过调用 xTimerPendFunctionCallFromISR 来确保安全。

  2. 记录事件:记录从中断服务例程清除事件组位的操作。

  3. 挂起函数调用:使用 xTimerPendFunctionCallFromISR 将清除位的操作挂起到调度器,以便在合适的时机执行。

  4. 返回结果:返回 xTimerPendFunctionCallFromISR 的结果,指示是否成功挂起函数调用。

获取事件组中各事件标志位的值xEventGroupGetBits()

EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{UBaseType_t uxSavedInterruptStatus;EventGroup_t const * const pxEventBits = xEventGroup;EventBits_t uxReturn;// 保存当前的中断状态,防止中断嵌套uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();{// 从事件组中读取当前的位值uxReturn = pxEventBits->uxEventBits;}// 恢复中断状态portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );// 返回事件组的当前位值return uxReturn;
} /*lint !e818 EventGroupHandle_t 是一个在其他函数中使用的 typedef,因此不能是指向常量的指针。*//*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */

函数 xEventGroupGetBitsFromISR,用于在中断服务例程(ISR)中获取事件组的当前位。具体功能如下:

  1. 保存中断状态:使用 portSET_INTERRUPT_MASK_FROM_ISR 保存当前的中断状态,防止中断嵌套。

  2. 获取事件组位:从事件组中读取当前的位值。

  3. 恢复中断状态:使用 portCLEAR_INTERRUPT_MASK_FROM_ISR 恢复中断状态。

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

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

相关文章

世界坐标和Local坐标的区分

TargetPos.position(-TargetPos.forward*-4)TargetPos.up*7 这是相对于TargetPos的位置进行偏移, 动态的与Target的本地坐标改变 new Vector3(TargetPos.position.x, TargetPos.position.y 7, TargetPos.position.z - 5) 这个是直接new了一个世界坐标的Vector3 &…

Ubuntu 22.04 的Python3.11.8 安装

背景 新版本的Python需要更高版本的OpenSSL 依赖。使用操作系统的SSL不然会提示缺少SSL的报错。 部署 ## Openssl部署 wget https://github.com/openssl/openssl/releases/download/openssl-3.4.0/openssl-3.4.0.tar.gz## ./config --prefix/usr/local/openssl make &&…

在Ubuntu下安装RabbitMQ、添加一个新的登录用户并设置密码

在Ubuntu下安装RabbitMQ、添加一个新的登录用户并设置密码 在Ubuntu下安装RabbitMQ可以按照以下步骤进行:步骤 1: 更新系统步骤 2: 安装Erlang步骤 3: 添加RabbitMQ仓库步骤 4: 更新APT索引并安装RabbitMQ步骤 5: 启动RabbitMQ服务步骤 6: 检查RabbitMQ状态步骤 7: …

nacos单机源码解析-服务发现和心跳检测

目录 1 服务发现 1.1 客户端 1.1.1 入口 1.1.2 定时拉取 1.1.3 总结 1.2 服务端 2 心跳检测 2.1 客户端 2.2 服务端 2.2.1 处理心跳请求 2.2.2 开启定时任务进行心跳检测 2.2.3 总结 1 服务发现 服务列表:Nacos 维护一个服务列表,记录所有已注…

在线绘制带community的蛋白质-蛋白质相互作用(PPI)网络图

导读:分子相互作用网络图揭示了细胞内部分子间的复杂相互作用。通过识别网络中密集连接的节点所形成的社区(community),可以揭示它们之间以前未知的功能联系。这些社区可能代表了具有共同功能的功能模块,对于理解细胞生…

【商城系统搭建流程】

商城系统的搭建流程可以分为以下几个步骤: 1.需求分析:确定商城系统的功能和特性,例如商品展示、购物车、订单管理、支付等。 2.系统设计:根据需求分析结果设计商城系统的架构,包括前端页面设计和后端数据库设计。 …

qt QTableView详解

1、概述 QTableView 是 Qt 框架中的一个高级视图类,用于以表格形式展示二维数据。它基于 QAbstractItemView,并与模型(通常是 QAbstractTableModel 或 QStandardItemModel)结合使用,以实现数据的展示和交互。QTableVi…

Orleans集群及Placement设置

服务端界面使用相同的clusterid和serviceid,相同ip地址,不同网关端口号和服务端口号,启动两个silo服务,并使用MySql数据库做Silo间信息同步,实现集群。 silo服务启动代码如下(从nuget下载Microsoft.Orleans…

OceanBase 4.3.3 功能解析:列存副本

OceanBase 从4.3.0 版本开始,引入了列式存储的支持。用户可以根据业务的具体需求,选择创建列存表、行存表或是行列混存表。无论选择哪种表类型,在不同的Zone内,租户使用的副本模式都是一致的。详见官网文档: https://w…

【Linux】 IPC 进程间通信(三)(消息队列 信号量)

📃个人主页:island1314 🔥个人专栏:Linux—登神长阶 ⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞 一、消息队列 💌…

如何管理PHP API版本

管理PHP API版本是确保API稳定性和兼容性的关键步骤。以下是一些有效的PHP API版本管理方法: 一、使用命名空间和类库 在PHP中,可以通过命名空间和类库来实现API版本的管理。通过为不同版本的API创建不同的命名空间,可以将它们隔离开来&…

Docker:镜像构建 DockerFile

Docker:镜像构建 DockerFile 镜像构建docker build DockerfileFROMCOPYENVWORKDIRADDRUNCMDENTRYPOINTUSERARGVOLUME 镜像构建 在Docker官方提供的镜像中,大部分都是基础镜像,他们只提供某个简单的功能,如果想要一个功能更加丰富…

遥控器数图控链路系统核心技术+算法详解

一、核心技术 无线通信技术 遥控器数图控链路系统主要基于无线通信技术进行数据传输。通过特定的调制、编码和信号处理技术,将遥控器的操作指令转化为无线电信号,并传输给被控制设备。被控制设备接收到信号后,再将其解码为可识别的指令&…

Kafka 源码 KRaft 模式本地运行

KRaft(Kafka Raft Metadata mode),从版本 2.8.0 开始作为测试特性引入,并在后续版本中持续得到改进和增强。 KRaft 模式是指 Kafka 使用 Raft 协议来管理集群元数据的一种运行模式,这标志着 Kafka 向去除对 ZooKeeper …

Java:使用Jackson的jsonPtrExp获取节点值的问题说明

使用Jackson时解析json时,经常会使用jsonPath直接获取某一节点下的值,这种方式非常直观 ,例如: { “data”: { "test1": "value1", "test2": null, "test3": 10 } } 以Jackson2.13.5&…

链表存储密度

链表的存储密度是一个衡量链表空间利用率的指标。为了理解链表的存储密度,我们需要先简单了解一下链表的基本结构和特点。 链表的基本结构 链表是一种线性数据结构,其中每个元素(称为节点)包含两部分: 数据域&#…

Android下的系统调用 (syscall),内联汇编syscall

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ 什么是系统调用 (syscall) 系统调用是操作系统提供给应用程序的一组接口,允许用户空间程序与内核进行交互。 在 Android(基于 Linux …

大语言模型安全威胁

文章目录 基座安全一、大模型训练阶段(1)训练环境安全风险(2)训练环境隔离缺陷 二、大模型部署阶段(1)利用不安全系统配置(2)CI&CD流程攻击(3)部署环境组…

RAGulator:如何识别和缓解大模型所谓的“忠实幻觉”

RAGulator,一个轻量级的、用于检测RAG系统中语义上与上下文不符(OOC)的LLM生成文本的检测器 论文链接:https://arxiv.org/abs/2411.03920 论文概述 实时检测大型语言模型(LLM)生成的与上下文不符的输出问题&#xff…

简单介绍 Spring 中获取 Bean 的三种方式

文章目录 一、自动注入方式二、从 ApplicationContext 手动获取 Bean三、使用 BeanFactory 获取 Bean四、总结推荐阅读文章 在 Spring 应用中,Bean 是项目的核心。无论是通过自动注入、依赖注入还是手动获取 Bean,了解获取 Bean 的多种方式能够帮助我们更…