ucos(七)事件标志组
一、概述
前面讲述了UCOSIII的信号量、互斥信号量,它们都可以完成任务的同步。但是有时候一个任务可能需要和多个事件同步,这个时候就需要使用事件标志组。事件标志组与任务之间有两种同步机制:
- “或”同步:等待多个事件时,任何一个事件发生 ,任务都被同步,这个就称为“或”同步;
- “与”同步:当所有的事件都发生时任务才被同步,这种同步机制被称为“与”同步。
事件标志组是专门管理标志位,一个事件标志组可以管理32个标志位。
在前后台系统,经常会用到标志位,查询标志位是否置位,有明显的缺点,CPU得不到休息,会一直工作查询,增加CPU的功耗。
void main(void)
{
while(1)
{
if(g_iwdg_reset)
{
}
if(g_wwdg_reset)
{
g_wwdg_reset=0;
}
if(g_usart1_event)
{
}
if(g_usart3_event)
{
}
if(g_rtc_wakeup_event)
{
}
if(g_rtc_alarm_event)
{
}
}
}
1.创建事件标志组
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.等待事件标志组
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(0001'b),则等待bit0;0x05(0101'b),则等待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_SET_ANY: 等待任意一个标志位置位
OS_OPT_PEND_FLAG_CONSUME: 等待任意一个标志位成功后,就自动将其清零
OS_OPT_PEND_BLOCKING: 阻塞等待
OS_OPT_PEND_FLAG_SET_ALL: 等待所有标志位置位,才能跳出阻塞等待
p_ts: 用于记录等待事件花了多长时间,默认写NULL,不记录。
p_err: 返回错误码,没有错误的就返回OS_ERR_NONE.
返回值:
返回等待成功的标志位。
3.设置事件标志组
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。
二、实例
按键触发中断,在中断中设置中断标志位
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "includes.h" #include "exti.h" //任务1控制块 OS_TCB Task1_TCB; void task1(void *parg); CPU_STK task1_stk[128]; //任务1的任务堆栈,大小为128字,也就是512字节 OS_FLAG_GRP g_flag_grp; //事件标志组的对象 //主函数 int main(void) { OS_ERR err; systick_init(); //时钟初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置 usart_init(9600); //串口初始化 LED_Init(); //LED初始化 Exti_Init(); //OS初始化,它是第一个运行的函数,初始化各种的全局变量,例如中断嵌套计数器、优先级、存储器 OSInit(&err); //创建任务1 OSTaskCreate( (OS_TCB *)&Task1_TCB, //任务控制块,等同于线程id (CPU_CHAR *)"Task1", //任务的名字,名字可以自定义的 (OS_TASK_PTR)task1, //任务函数,等同于线程函数 (void *)0, //传递参数,等同于线程的传递参数 (OS_PRIO)6, //任务的优先级6 (CPU_STK *)task1_stk, //任务堆栈基地址 (CPU_STK_SIZE)128/10, //任务堆栈深度限位,用到这个位置,任务不能再继续使用 (CPU_STK_SIZE)128, //任务堆栈大小 (OS_MSG_QTY)0, //禁止任务消息队列 (OS_TICK)0, //默认时间片长度 (void *)0, //不需要补充用户存储区 (OS_OPT)OS_OPT_TASK_NONE, //没有任何选项 &err //返回的错误码 ); if(err!=OS_ERR_NONE) { printf("task 1 create fail\r\n"); while(1); } //创建事件标志组 OSFlagCreate(&g_flag_grp,"g_flag_grp",0,&err); //启动OS,进行任务调度 OSStart(&err); printf(".......\r\n"); while(1); } void task1(void *parg) { uint32_t t=0; OS_ERR err; OS_FLAGS flag = 0; printf("task1 is create ok\r\n"); while(1) { //等待事件标志组 //0x01|0x02 就是等待bit0和bit1 //0:不做超时等待 //OS_OPT_PEND_FLAG_SET_ANY 等待其中一个标志位 //OS_OPT_PEND_FLAG_CONSUME 等待对应的时间成功后,将对应的时间标志位清零 //OS_OPT_PEND_BLOCKING 阻塞形式等待信号量,若等不了信号量,则让出CPU使用权给其他任务 //不需要时间戳(时间标记):用于记录等待信号量花了多长时间,默认写NULL,不记录 //或同步 //flag = OSFlagPend(&g_flag_grp,0x01|0x02,0,OS_OPT_PEND_FLAG_SET_ANY + OS_OPT_PEND_FLAG_CONSUME+OS_OPT_PEND_BLOCKING,NULL,&err); //与同步 flag = OSFlagPend(&g_flag_grp,0x01|0x02,0,OS_OPT_PEND_FLAG_SET_ALL + OS_OPT_PEND_FLAG_CONSUME+OS_OPT_PEND_BLOCKING,NULL,&err); if(flag & 0x01) { printf("bit0 set\r\n"); } if(flag & 0x02) { printf("bit1 set\r\n"); } } } //中断服务函数 在CORE里面的start_stm32f40_41xxx.s这个汇编里面找 void EXTI0_IRQHandler(void)//PA0 { uint8_t b=0; OS_ERR err; //进入中断 OSIntEnter(); //判断确实进中断标志 //if(EXTI_GetITStatus(EXTI_Line9) !=RESET) //==SET if((EXTI->PR & (0x1<<0)) !=0) { b=1; //清楚中断标志位 往里面写1 记住一定要清空 //EXTI_ClearITPendingBit(EXTI_Line0); EXTI->PR = (0x1<<0); } //退出中断 OSIntExit(); if(b) { //设置事件标志组的bit0 OSFlagPost(&g_flag_grp,0x01,OS_OPT_POST_FLAG_SET,&err); } } //中断服务函数 在CORE里面的start_stm32f40_41xxx.s这个汇编里面找 void EXTI2_IRQHandler(void)//PA0 { uint8_t b=0; OS_ERR err; //判断确实进中断标志 if(EXTI_GetITStatus(EXTI_Line2) !=RESET) //==SET { b=1; //清楚中断标志位 往里面写1 记住一定要清空 EXTI_ClearITPendingBit(EXTI_Line2); } if(b) { //设置事件标志组的bit1 OSFlagPost(&g_flag_grp,0x02,OS_OPT_POST_FLAG_SET,&err); } }