FreeRTOS_事件标志组
FreeRTOS事件标志组
事件标志组简介
1. 事件位(事件标志)
事件位用于表明某个事件是否发生,事件位通常用作事件标志,比如下面的几个例子:
当收到一条消息并且把这条消息处理掉以后就可以将某个位(标志)置1,当队列中没有消息需要处理的时候就可以将这个位(标志)置0。
当把队列中的消息通过网络发送输出以后就可以将某个位(标志)置1,当没有数据需要从网络发送出去的话就将这个位(标志)置0。
现在需要向网络中发送一个心跳信息,将某个位(标志)置1。现在不需要项网络中发送心跳信息,这个位(标志)置0。
2. 事件组
一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问,同样,以上面列出的三个例子为例:
事件标志组bit0 表示队列中的消息是否处理掉。
事件标志组bit1 表示是否有纤细需要从网络中发送出去。
事件标志组bit2 表示现在是否需要向网路发送心跳信息。
3. 事件标志组和事件位的数据类型
事件标志组的数据类型为 EventBits_t,当configUSE_16_BIT_TICKS为1的时候,事件标志组可以存储8个事件位,当configUSE_16_BIT_TICKS为0的时候,事件标志组存储24个事件位。
事件标志组中所有事件位都存储在一个无符号的EventBits_t类型的变量中,EventBits_t在event_groups.h中有如下定义:
typedef TickType_t EventBits_t;
数据类型TickType_t在文件portmacro.h中有如下定义:
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
可以看出当 configUSE_16_BIT_TICKS 为0的时候,TickType_t是个32位的数据类型,因此EventBits_t也是个32位的数据类型。EventBits_t类型的变量可以存储24个事件位,另外的那高8位有其他用。事件位0存放在这个变量的bit0上,变量的bit1就是事件位1,以此类推。对于STM32来说,一个事件标志组最多可以存储24个事件位,如下图:
创建事件标志组
FreeRTOS提供了两个用于创建事件标志组的函数:
函数 | 描述 |
xEventGroupCreate() | 使用动态方法创建事件标志组 |
xEventGroupCreateStatic() | 使用静态方法创建事件标志组 |
1. 函数 xEventGroupCreate()
此函数用于创建一个时间标志组,锁需要的内存通过动态内存管理方法分配。由于内部处理的原因,事件标志组可用的bit数取决于configUSE_16_BIT_TICKS,当configUSE_16_BIT_TICKS为1的时候,事件标志组有8个可用的位(bit0~bit7),当configUSE_16_BIT_TICKS为0的时候,时间标志组有24个可用的位(bit0~bit23)。EventBits_t类型的变量用来存储事件标志组中的各个事件位,函数原型如下:
EventGroupHandle_t xEventGroupCreate( void )
参数:
无。
返回值:
NULL:事件标志组创建失败。
其他值:创建成功的事件标志组句柄。
2. 函数xEventGroupCreateStatic()
此函数用于创建一个事件标志组,所需要的内存需要用于自行分配,此函数原型如下:
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
参数:
pxEventGroupBuffer:参数指向一个StaticEventGroup_t类型的变量,用来保存时间组结构体。
返回值:
NULL:事件标志组创建失败。
其他值:创建成功的事件标志组句柄。
设置事件位
FreeRTOS提供了4个函数用来设置事件标志组中事件位(标志),事件位的设置包括清零和置1两种操作:
函数 | 描述 |
xEventGroupClearBits() | 将指定的事件位清零,用在任务中。 |
xEventGroupClearBitsFromISR() | 将指定的事件位清零,用在中断服务函数中。 |
xEventGroupSetBits() | 将指定的事件位置1,用在任务中。 |
xEventGroupSetBitsFromISR() | 将指定的事件位置1,用在中断服务函数中。 |
1. 函数 xEventGroupClearBits()
将事件标志组中指定事件位清零,此函数只能用在任务中,不能用在中断服务函数中,中断服务函数中有其他的API函数。函数原型如下:
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
参数:
xEventGroup:要操作的事件标志组的句柄。
uxBitsToClear:要清零的事件位,比如要清除bit3的话就设置为0x08。可以同时清除多个bit,如设置0x09的话就是同时清除bit3和bit0。
返回值:
任何值:将指定事件位清零之前的事件组值。
2. 函数xEventGroupClearBitsFromISR()
此函数为xEventGroupClearBits()的中断级版本,也是将指定的事件位(标志)清零。此函数用在中断服务函数中,函数原型如下:
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet )
参数:
xEventGroup:要操作的事件标志组的句柄。
uxBitsToClear:要清零的事件位,比如要清除bit3的话就设置为0x08。可以同时清除多个bit,如设置0x09的话就是同时清除bit3和bit0。
返回值:
pdPASS:事件位清零成功。
pdFALSE:事件位清零失败。
3. 函数 xEventGroupSetBits()
设置指定的事件位为1,此函数只能用在任务中,不能用于中断服务函数。此函数原型如下:
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet )
参数:
xEventGroup:要操作的事件标志组句柄。
uxBitsToSet:指定要置1的事件位,比如要将bit3 置1的话就设置为0x08。可以同时将多个bit置1,如设置为0x09的话就是同时将bit3和bit0置1。
返回值:
任何值:在将指定事件位置1后的事件组值。
3. 函数xEventGroupSetBitsFromISR()
此函数也用于将指定事件位置1,此函数是xEventGroupSetBits()的中断版本,用在中断服务函数中,函数原型如下:
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken )
参数:
xEventGroup:要操作的事件标志组的句柄。
uxBitsToClear:指定要置1的事件位,比如要将bit3置1的话就设置0x08。可以同时将多个bit置1,如设置为0x09的话就是同时将bit3和bit0置1。
pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换。这个变量的值,函数会自动设置,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
pdPASS:事件位置1成功。
pdFALSE:事件位置1失败。
获取事件标志组值
我们可以通过FreeRTOS提供的API函数来查询事件标志组值。FreeRTOS一共提供了两个这样的API函数。
函数 | 描述 |
xEventGroupGetBits() | 获取当前事件标志组的值(各个事件位的值),用在任务中 |
xEventGroupGetBitsFromISR() | 获取当前事件标志组的值,用在中断服务函数中。 |
1. 函数xEventGroupGetBits()
此函数用于获取当前事件标志组的值,也就是各个事件位的值。此函数用在任务中,不能用在中断服务函数中。此函数是个宏,真正执行的事函数xEventGroupClearBits(),函数原型如下:
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup )
参数:
xEventGroup:要获取的事件标志组的句柄。
返回值:
任何值:当前时间标志组的值。
2. 函数xEventGroupGetBitsFromISR()
获取当前事件标志组的值,此函数是xEventGroupGetBits()的中断版本,函数原型如下:
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
参数:
xEventGroup:要获取的事件标志组的句柄。
返回值:
任何值:当前事件标志组的值。
等待指定的事件位
某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志),使用函数 xEventGroupWaitBits()可以完成这个功能。调用函数以后如果任务要等待的事件位还没有准备好(置1或清零)的话任务就会进入阻塞态,直到阻塞时间达到或者所等待的事件位准备好。函数原型如下:
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait )
参数:
xEventGroup:指定要等待的事件标志组。
uxBitsToWaitFor:指定要等待的事件位,比如要等待bit0和(或)bit2的时候,此参数就是0x05,如果要等待bit0和(或)bit1和(或)bit2的时候此函数就是0x07,以此类推。
xClearOnExit:此参数要是pdTRUE的话,那么在退出此函数之前有由参数uxBitsToWaitFor所设置的这些事件位就会清零。如果设置为pdFALSE的话这些事件位就不会改变。
xWaitForAllBits:此参数如果设置为pdTRUE的话,当uxBitsToWaitFor所设置的这些事件位都置1,或者指定的阻塞时间到的时候函数xEventGroupWaitBits()才会返回。当此参数为pdFALSE的话,只要uxBitsToWaitFor所设置的这些事件位其中的任意一个置1,或者指定的阻塞时间到的话函数xEventGroupWaitBits()就会返回。
xTicksToWait:设置阻塞时间,单位为节拍数。
返回值:
任何值:返回当所等待的事件位置1以后的事件标志组的值,或者阻塞时间到。根据这个值我们就知道哪些事件位置1了。如果函数因为阻塞时间到而返回的话,那么这个返回值就不代表任何的含义。
事件标志组实验
创建事件标志组、将相应的事件位置1、等待相应事件位置1的操作。
实验设置三个任务:start_task、eventsetbit_task、eventgroup_task。
start_task:用来创建其他两个任务,创建时间标志组。
eventsetbit_task:通过不同按键值,将事件标志组中相应事件位置1。
eventgroup_task:等待事件标志组中的事件位,当这些事件位都置1,执行相应的处理。
EventGroupHandler:创建的事件标志组句柄。使用事件标志组的事件位:bit0 bit1 bit2
任务分配:
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters); //任务优先级
#define EVENTSETBIT_TASK_PRIO 2
//任务堆栈大小
#define EVENTSETBIT_STK_SIZE 50
//任务句柄
TaskHandle_t EventSetbitTask_Handler;
//任务函数
void eventsetbit_task(void *pvParameters); //任务优先级
#define EVENTGROUP_TASK_PRIO 3
//任务堆栈大小
#define EVENTGROUP_STK_SIZE 50
//任务句柄
TaskHandle_t EventGroupTask_Handler;
//任务函数
void eventgroup_task(void *pvParameters); EventGroupHandle_t EventGroupHandle; // 事件标志组句柄 // 定义事件位
#define BIT_0 (1<<0)
#define BIT_1 (1<<1)
#define BIT_2 (1<<2)
main() 函数:
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(); //初始化串口
LED_Init(); //初始化LED
KEY_Init(); // 初始化按键 //创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
任务函数:
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区 EventGroupHandle = xEventGroupCreate(); // 创建事件标志组
if(EventGroupHandle == NULL)
{
printf("EventGroup Create Failed!\r\n");
} //创建eventsetbit任务
xTaskCreate((TaskFunction_t )eventsetbit_task,
(const char* )"eventsetbit_task",
(uint16_t )EVENTSETBIT_STK_SIZE,
(void* )NULL,
(UBaseType_t )EVENTSETBIT_TASK_PRIO,
(TaskHandle_t* )&EventSetbitTask_Handler);
//创建eventgroup任务
xTaskCreate((TaskFunction_t )eventgroup_task,
(const char* )"eventgroup_task",
(uint16_t )EVENTGROUP_STK_SIZE,
(void* )NULL,
(UBaseType_t )EVENTGROUP_TASK_PRIO,
(TaskHandle_t* )&EventGroupTask_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
} //eventsetbit_task任务函数
void eventsetbit_task(void *pvParameters)
{
u8 key = ; while()
{
key = KEY_Scan();
switch(key)
{
case KEY1_PRES:
if(EventGroupHandle != NULL)
{
xEventGroupSetBits(EventGroupHandle,BIT_0); // 设置事件标志组 BIT_0 置1
}
break;
case KEY2_PRES:
if(EventGroupHandle != NULL)
{
xEventGroupSetBits(EventGroupHandle,BIT_1); // 设置事件标志组 BIT_0 置1
}
break;
}
vTaskDelay();
}
} //eventgroup_task任务函数
void eventgroup_task(void *pvParameters)
{
EventBits_t EventBitsVal = ; while()
{
if(EventGroupHandle != NULL)
{
EventBitsVal = xEventGroupWaitBits(
EventGroupHandle, // 要等待的事件标志组
(BIT_0|BIT_1), // 等待的事件位
pdTRUE, // 清零
pdFALSE, // 只要事件位其一得到就退出
portMAX_DELAY ); // 死等 printf("EventBitsVal = %#x\r\n",EventBitsVal);
}else{
vTaskDelay();
} }
}
运行结果:
按下KEY1,输出 EventBitsVal = 0x1
按下KEY2,输出 EventBitsVal = 0x2
FreeRTOS_事件标志组的更多相关文章
- 16.3-uC/OS-III同步 (事件标志组实验)
事件标志组,顾名思义,就是若干个事件标志的组合,代表若干个事件是否发生,通常用于集合两个或两个以上事件的状态 . 1.如果想要使用事件标志组,就必须事先使能事件标志组.消息队列的使能位于“os_cfg ...
- 16.2-uC/OS-III同步 (事件标志组)
事件标志组 1.当任务要与多个事件同步时可以使用事件标志.若其中的任意一个事件发生时任务被就绪, 叫做逻辑或(OR).若所有的事件都发生时任务被就绪,叫做逻辑与( AND). 2.用户可以创建任意个事 ...
- FreeRTOS 事件标志组 ——提高篇
假设你已经看过FreeRTOS 事件标志组这篇随笔了. 之前的基础篇,真的就只是简单了解一下,相当于大学实验室的实验,但是,我们实际公司项目中,需要更多地思考,就算我们之前只是学习了基础概念以及基础语 ...
- RTX——第13章 事件标志组
以下内容转载自安富莱电子: http://forum.armfly.com/forum.php 前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制.首先讲解任务间的通信 ...
- FreeRTOS 事件标志组
以下转载自安富莱电子: http://forum.armfly.com/forum.php 为什么要使用事件标志事件标志组是实现多任务同步的有效机制之一.也许有不理解的初学者会问采用事件标志组多麻烦, ...
- FreeRTOS 任务计数信号量,任务二值信号量,任务事件标志组,任务消息邮箱
以下基础内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 计数信号量的另一种实现方式----基于任务通知(Task Not ...
- FreeRTOS 任务通知模拟事件标志组
实验 //设置事件位的任务 void eventsetbit_task(void *pvParameters) { u8 key; while(1) { if(EventGroupTask_Handl ...
- UCOSIII事件标志组
两种同步机制 "或"同步 "与"同步 使能 #define OS_CFG_FLAG_EN 1u /* Enable (1) or Disable (0) cod ...
- ucos中信号量 事件标志 消息队列都怎么用
信号量 事件标志和消息队列分别应用于什么场景(反正我学的时候有点闹不清,现在总结一下): 信号量和事件标志用于任务同步.详细来说,这个功能可以替代以前裸机中你打一个标记的功能,比如使用了一个定时器,5 ...
随机推荐
- map中根据value获取key
public static String getKeyByValue(Map map, Object value) { String keys=""; Iterator it = ...
- sqlserver2012——EXCEPT差查询
代表第一个select查询结果与第二个select查询结果去除相交后的数据
- Unity ShadowMapping
原理: 场景中一个plane,一个cube,一个light,一个mainCamera 为了在plane上呈现cube的shadow,先在light上放一个lightCamera(位置方向跟light相 ...
- 浅淡Java多线程
工作中一直忙着实现业务逻辑,多线程接触得不多.对多线程的认知,一直停留在Thread和Runnable上.最近心血来潮,找了几本多线程的书,不看不知道,一看吓一跳.原来我对多线程的理解是多么的肤浅.记 ...
- codevs 3333 高级打字机
3333 高级打字机 题目描述 Description 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作 ...
- Android实现点击两次返回退出APP
Android实现点击两次退出APP 这两天在做一个项目碰到这么个问题,需要主界面点击两次直接退出整个APP而不是返回上一个界面,查找了网上的资料,整合和修改了一下写了这篇博客. 这里我主要以我的项目 ...
- PAT甲级——1104 Sum of Number Segments (数学规律、自动转型)
本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90486252 1104 Sum of Number Segmen ...
- mysql5.7日志时间戳(log_timestmaps)与系统时间不一致问题以及日志报Got an error reading communication packets情况分析
一.mysql安装后error_log日志时间戳默认为UTC(如下图),因此会造成与系统时间不一致,与北京时间相差8个小时. 解决errro_logs时间戳与linux系统时间不一致问题 step1: ...
- GYM 101933A(dp)
要点 \(\sum{w_i} <= 1e8\)是有意味的. 设\(dp[i]\)为至少可以承受重量\(i\)的最大可达高度.转移时可以转移的\(j\)必须满足加上它之后得保证各层不能超重,所以\ ...
- criteria用法
Criteria Query通过面向对象化的设计,将数据查询条件封装为一个对象.简单来讲,Criteria Query可以看作是传统SQL的对象化表示,如: Java代码 Criteria cri ...