UCOSIII中的事件标志组是一种用于任务同步和事件管理的机制,它允许任务和中断服务例程(ISR)发布事件标志,并允许任务等待这些事件标志的发生。以下是对UCOSIII事件标志组的详细介绍:
1. 定义与创建
- 定义:在UCOSIII中,事件标志组是
OS_FLAG_GRP
类型的内核对象,用于管理一串事件标志位。 - 创建:在使用事件标志组之前,需要调用
OSFlagCreate()
函数来创建一个事件标志组。这个函数需要指定事件标志组的名称、初始值以及一个用于保存错误码的参数。
void OSFlagCreate (OS_FLAG_GRP *p_grp,CPU_CHAR *p_name,OS_FLAGS flags,OS_ERR *p_err)
p_grp:事件标志组对象
p_name:事件标志组的名字
flags:事件标志组里所有标志位的初值,默认写0
p_err:返回错误码,没有错误的就返回OS_ERR_NONE
2. 同步机制
事件标志组与任务之间有两种同步机制:
- “或”同步:当等待多个事件时,只要任何一个事件发生,任务就会被同步。
- “与”同步:当所有的事件都发生时,任务才会被同步。
3. 等待事件标志组
- 等待函数:
OSFlagPend()
函数用于等待一个或多个事件标志位的发生。这个函数可以指定要等待的标志位、超时时间以及等待条件等参数。 - 等待条件:可以通过
OS_OPT
参数指定等待条件,如等待任意一个标志位、等待所有标志位、非阻塞等待等。
OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp,OS_FLAGS flags,OS_TICK timeout,OS_OPT opt,CPU_TS *p_ts,OS_ERR *p_err)
p_grp:事件标志组对象
flags:要等待哪些标志位;0x01,则等待bit0;0x05,则等待bit0和bit2;0x83,则等待bit0、bit1、bit7。
timeout:超时时间,默认写0,一直等待
opt:默认是以下格式
OS_OPT_PEND_FLAG_SET_ANY + OS_OPT_PEND_FLAG_CONSUME+OS_OPT_PEND_BLOCKING
OS_OPT_PEND_FLAG_CLR_ALL:等待事件标志组所有的位清零;
OS_OPT_PEND_FLAG_CLR_ANY:等待事件标志组中任意一个标志清零;
OS_OPT_PEND_FLAG_SET_ALL:等待事件标志组中所有的位置位;
OS_OPT_PEND_FLAG_SET_ANY:等待事件标志组中任意一个标志置位。
调用上面四个选项的时候还可以搭配下面三个选项:
OS_OPT_PEND_FLAG_CONSUME:用来设置是否继续保留该事件标志的状态;
OS_OPT_PEND_NON_BLOCKING:标志组不满足条件时不挂起任务;
OS_OPT_PEND_BLOCKING:标志组不满足条件时挂起任务。
p_ts: 用于记录等待事件花了多长时间,默认写NULL,不记录。
p_err: 返回错误码,没有错误的就返回OS_ERR_NONE。
4. 发布事件标志
- 发布函数:
OSFlagPost()
函数用于发布事件标志,可以指定要置位或清零的标志位。 - 发布者:任务和ISR都可以发布事件标志,但只有任务可以创建事件标志组、删除事件标志组以及取消其他任务对事件标志组的等待。
OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp,OS_FLAGS flags,OS_OPT opt,OS_ERR *p_err)
p_grp:事件标志组对象
flags: 结合opt参数一起使用。设置/清零哪些标志位,0x01,则对应bit0;0x05,则对应bit0和bit2;0x83,则对应bit0、bit1、bit7。
opt: OS_OPT_POST_FLAG_SET,对应的bit置位 ,OS_OPT_POST_FLAG_CLR,对应的bit清零.
p_err: 返回错误码,没有错误的就返回OS_ERR_NONE。
5.注意事项
- 在使用事件标志组时,需要确保已经通过
OS_CFG_FLAG_EN
宏启用了事件标志组功能。 - 在设计任务同步逻辑时,应仔细考虑选择“或”同步还是“与”同步机制。
- 在发布事件标志时,应注意避免不必要的重复发布和潜在的竞争条件。
- 在使用事件标志组进行任务同步时,应确保任务间的依赖关系和同步逻辑清晰明确,以避免死锁或竞态条件等问题。
6. 使用场景
事件标志组常用于需要同步多个任务或等待多个事件发生的场景。例如,在一个嵌入式系统中,可能需要等待多个按键被按下才能执行某个任务,这时就可以使用事件标志组来实现。我们在前后台系统中一般都是自己定义全局变量标志,然后循环判断,浪费CPU资源,不能合理的调度,UCOSIII的事件标志组很好的解决了这个问题。
7.代码实现
7.1创建标志组
#define KEYFLAGS_VALUE 0X00
OS_FLAG_GRP EventFlags; //定义一个事件标志组//创建一个事件标志组OSFlagCreate((OS_FLAG_GRP*)&EventFlags, //指向事件标志组(CPU_CHAR* )"Event Flags", //名字(OS_FLAGS )KEYFLAGS_VALUE, //事件标志组初始值(OS_ERR* )&err); //错误码
7.2发送标志组
#define KEY0_FLAG 0x01
#define KEY1_FLAG 0x02
flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,(OS_FLAGS )KEY0_FLAG,(OS_OPT )OS_OPT_POST_FLAG_SET,(OS_ERR* )&err);flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,(OS_FLAGS )KEY1_FLAG,(OS_OPT )OS_OPT_POST_FLAG_SET,(OS_ERR* )&err);
7.3等待标志组
//等待事件标志组OSFlagPend((OS_FLAG_GRP*)&EventFlags,(OS_FLAGS )KEY0_FLAG+KEY1_FLAG,(OS_TICK )0,(OS_OPT )OS_OPT_PEND_FLAG_SET_ALL+OS_OPT_PEND_FLAG_CONSUME,(CPU_TS* )0,(OS_ERR* )&err);
注意:有的朋友可能对flags和opt这两个参数不太理解,比如在flags等于0x03的时候,相当于使用了标志组的bit0和bit1,但是此时如果opt设置了 OS_OPT_PEND_FLAG_SET_ANY,等待任意一个标志位置位,会不会两个参数存在冲突,就是只等待任意一个标志位,加起来到不了0x03。其实falgs的
这个参数只是定义了任务对哪些事件标志位感兴趣,并不是所有置1的标志位相加是0x03才会同步,刚接触这里可能会被例子里面写的赋值KEY0_FLAG+KEY1_FLAG搞蒙掉。