|____2.10 FreeRTOS 深度解析--事件

发布时间:2026/6/8 20:52:12

|____2.10 FreeRTOS 深度解析--事件 事件1. 事件控制块 EventGroup_t2. 常用函数2.1 事件创建 xEventGroupCreate()2.2 事件删除 vEventGroupDelete()2.3 事件组置位(任务) xEventGroupSetBits() / xEventGroupSetBitsFromISR()中断2.4 等待事件 xEventGroupWaitBits()2.5 事件组清位(任务) xEventGroupClearBits() / xEventGroupClearBitsFromISR()中断1. 事件控制块 EventGroup_t事件组存储在EventBits_t类型的变量中24 个位用来实现事件标志组所有在等待此事件的任务均会被挂载在等待事件列表xTasksWaitingForBits2. 常用函数2.1 事件创建 xEventGroupCreate()(1)因为事件标志组是FreeRTOS 的内部资源也是需要RAM 的所以在创建的时候会向系统申请一块内存大小是事件控制块大小sizeof( EventGroup_t )(2)如果分配内存成功那么久对事件控制块的成员变量进行初始化事件标志组变量清零因为现在是创建事件还没有事件发生所以事件集合中所有位都为0然后调用 vListInitialise()函数将事件控制块中的等待事件列表进行初始化该列表用于记录等待在此事件上的任务2.2 事件删除 vEventGroupDelete()(1)挂起调度器因为接下来的操作不知道需要多长的时间并且在删除的时候不希望其他任务来操作这个事件标志组所以暂时把调度器挂起让当前任务占有CPU(2)当有任务被阻塞在事件等待列表中的时候我们就要把任务恢复过来否则删除了事件的话就无法对事件进行读写操作那这些任务可能永远等不到事件因为任务有可能是一直在等待事件发生的使用 while 循环保证所有的任务都会被恢复(3)调用 xTaskRemoveFromUnorderedEventList()函数将任务从等待事件列表中移除然后添加到就绪列表中参与任务调度当然因为挂起了调度器所以在这段时间里即使是优先级更高的任务被添加到就绪列表系统也不会进行任务调度所以也就不会影响当前任务删除事件的操作这也是为什么需要挂起调度器的原因。但是使用事件删除函数vEventGroupDelete()的时候需要注意尽量在没有任务阻塞在这个事件的时候进行删除否则任务无法等到正确的事件因为删除之后所有被恢复的任务都只能获得事件的值为0(4)释放事件的内存因为在创建事件的时候申请了内存的在不使用事件的时候就把内核还给系统(5)恢复调度器之前的操作是恢复了任务现在恢复调度器那么处于就绪态的最高优先级任务将被运行2.3 事件组置位(任务) xEventGroupSetBits() / xEventGroupSetBitsFromISR()中断(1)断言判断要设置的事件标志位是否有效因为一个32 位的事件标志组变量只有24 位是用于设置事件的而 16 位的事件标志组变量只有8 位用于设置事件高8 位不允许设置事件有其他用途(2)挂起调度器因为接下来的操作不知道需要多长的时间因为需要遍历等待事件列表并且有可能不止一个任务在等待事件所以在满足任务等待的事件时候任务允许被恢复但是不允许运行只有遍历完成的时候任务才能被系统调度在遍历期间系统也不希望其他任务来操作这个事件标志组所以暂时把调度器挂起让当前任务占有CPU(3)根据用户指定的uxBitsToSet 设置事件标志位(4)设置这个事件标志位可能是某个任务在等待的事件就需要遍历等待事件列表中的任务看看这个事件是否与任务等待的事件匹配(5)获取要等待事件的标记信息是逻辑与还是逻辑或(6)再获取任务的等待事件是什么(7)如果只需要有任意一个事件标志位满足唤醒任务也是我们常说的“逻辑或”那么还需要看看是否有这个事件发生了(8)判断要等待的事件是否发生了发生了就需要把任务恢复在这里记录一下要恢复的任务(9)如果任务等待的事件都要发生的时候也是我们常说的“逻辑与”就需要就要所有判断事件标志组中的事件是否都发生如果是的话任务才能从阻塞中恢复同样也需要标记一下要恢复的任务(10)这里是FreeRTOS 暂时不用的暂时不用理会(11)找到能恢复的任务然后看下是否需要清除标志位如果需要就记录下需要清除的标志位等遍历完队列之后统一处理注意了在一找到的时候不能清除因为后面有可能一样有任务等着这个事件只能在遍历任务完成之后才能清除事件标志位(12)运用或运算标记一下要清除的事件标志位是哪些(13)将满足事件条件的任务从等待列表中移除并且添加到就绪列表中(14)循环遍历事件等待列表可能不止一个任务在等待这个事件(15)遍历完毕清除事件标志位(16)恢复调度器之前的操作是恢复了任务现在恢复调度器那么处于就绪态的最高优先级任务将被运行(17)返回用户设置的事件标志位值2.4 等待事件 xEventGroupWaitBits()这个函数实现了等待超时机制当且仅当任务等待的事件发生时任务才能获取到事件信息。在这段时间中如果事件一直没发生该任务将保持阻塞状态以等待事件发生。当其它任务或中断服务程序往其等待的事件设置对应的标志位该任务将自动由阻塞态转为就绪态。当任务等待的时间超过了指定的阻塞时间即使事件还未发生任务也会自动从阻塞态转移为就绪态。这样子很有效的体现了操作系统的实时性如果事件正确获取等待到则返回对应的事件标志位由用户判断再做处理因为在事件超时的时候也会返回一个不能确定的事件值所以需要判断任务所等待的事件是否真的发生。当用户调用这个函数接口时系统首先根据用户指定参数和接收选项来判断它要等待的事件是否发生如果已经发生则根据参数 xClearOnExit 来决定是否清除事件的相应标志位并且返回事件标志位的值但是这个值并不是一个稳定的值所以在等待到对应事件的时候还需我们判断事件是否与任务需要的一致 如果事件没有发生则把任务添加到事件等待列表中把任务感兴趣的事件标志值和等待选项填用列表项的值来表示直到事件发生或等待时间超时(1)挂起调度器**(2)先看下当前事件中的标志位是否已经满足条件了任务等待的事件prvTestWaitCondition()函数其实就是判断一下用户等待的事件是否与当前事件标志位一致。(3)满足条件了就可以直接返回了注意这里返回的是的当前事件的所有标志位所以这是一个不确定的值需要用户自己判断一下是否满足要求。然后把用户指定的等待超时时间xTicksToWait也重置为0这样子等下就能直接退出函数返回了(4)看看在退出的时候是否需要清除对应的事件标志位如果xClearOnExit为pdTRUE则需要清除事件标志位如果为pdFALSE就不需要清除(5)当前事件中不满足任务等待的事件并且用户指定不进行等待那么可以直接退出同样也会返回当前事件的所有标志位所以在使用 xEventGroupWaitBits()函数的时候需要对返回值做判断保证等待到的事件是任务需要的事件(6)而如果用户指定超时时间了并且当前事件不满足任务的需求那任务就进入等待状态以等待事件的发生(7)将当前任务添加到事件等待列表中任务将被阻塞指定时间 xTicksToWait并且这个列表项的值是用于保存任务等待事件需求的信息标记以便在事件标志位置位的时候对等待事件的任务进行相应的操作(8)恢复调度器(9)在恢复调度器的时候如果有更高优先级的任务恢复了那么就进行一次任务的切换(10)程序能进入到这里说明当前的任务已经被重新调度了调用 uxTaskResetEventItemValue()返回并重置xEventListItem的值因为之前事件列表项的值被保存起来了现在取出来看看是不是有事件发生(11)如果仅仅是超时返回那系统就会直接返回当前事件的所有标志位(12)再判断一次是否发生了事件(13)如果发生了那就清除事件标志位并且返回(14)否则就返回事件所有标志位然后退出2.5 事件组清位(任务) xEventGroupClearBits() / xEventGroupClearBitsFromISR()中断

相关新闻