UCOSIII中的事件标志组

序言

前面,我们了解到可以使用信号量来完成任务同步,这里我们再讲解一下另一种任务同步的方法:事件标志组。

再本篇文章中,我会首先介绍一下什么是是事件标志组,它是一种什么样的实现思想,然后我会介绍相关的API,最后会有一个小实验。

什么是事件标志组

有时候一个任务可能需要和多个事件同步,这个时候就需要使用事件标志组。事件标志组也是一个内核对象。事件标志组与任务之间有两种同步机制:“或”同步和“与”同步,当任何一个事件发生,任务都被同步的同步机制是“或同步”;需要所有的事件都发生任务才会被同步的机制是“与”同步,这两种同步机制如下图所示:

在这里插入图片描述

  • UCOSIII中的事件标志组是OS_FLAG_GRP,在os.h文件中有定义,事件标志组中也包含了一串任务,这些任务都在等待着事件标志组中的某些标志位被置1或者清零,在使用前,必须创建事件标志组。
  • 任务和ISR都可以发布事件标志,但是,只有任务可以创建事件标志、删除事件标志组以及取消其它任务对事件标志组的等待。
  • 任务可以通过调用函数OSFlagPend()等待事件标志组中的任意个事件标志,调用函数OSFlagPend()的时候可以设置一个超时时间,如果过了超时时间请求的事件还没有被发布,那么任务就会进入就绪态。
  • 我们可以设置同步机制为“或”同步还是“与”同步。

相关函数

函数描述
OSFlagCreate创建事件标志组
OSFlagDel()删除事件标志组
OSFlagPend()等待事件标志组
OSFlagPendAbort()取消等待事件标志组
OSFlagPendGetFlagRdy()获取使任务就绪的事件标志
OSFlagPost()向事件标志组发布标志

创建事件标志组

OSFlagCreate

void  OSFlagCreate (OS_FLAG_GRP  *p_grp,
                    CPU_CHAR     *p_name,
                    OS_FLAGS      flags,
                    OS_ERR       *p_err)
  • p_grp:指向事件标志组的指针
  • p_name:事件标志组的名字
  • flags:定义事件标志组的初始值
  • p_err:用来保存调用此函数后返回的错误码

OSFlagPend

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:bit序列,任务需要等待事件标志组的哪个位就把这个序列对应的位置1,根据设置这个序列可以是8bit、16bit或者32bit。
  • timeout:指向等待事件标志组的超时时间,如果在指定的超时时间内所等待的一个或多个事件没有发生,那么任务恢复运行。如果此值设置为0,则任务就将一直等待下去,直到一个或多个事件发生。
  • opt:选项,具体选项含义,可以自己看看源码注释
  • p_ts:指向一个时间戳,记录了发送、终止和删除事件标志组的时刻,如果为这个指针赋值NULL,则此函数的调用者将不会收到时间戳。
  • p_err:用来保存调用此函数后的错误码

OSFlagPost

OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,
                      OS_FLAGS      flags,
                      OS_OPT        opt,
                      OS_ERR       *p_err)
  • p_grp:指向事件标志组

  • flags:决定哪些位清零

  • opt:具体选项含义可以看源码注释

  • p_err:保存调用此函数后返回的错误码

事件标志组实验

实验概述

任务目标:设计一个程序,只有按下KEY0和KEY1时任务flagsprocess_task任务才能执行。

任务设计:分析上面的任务目标,我们可以使用事件标志组来实现,按下KEY0和KEY1作为两个不同的事件,只有这两个事件同时发生了才能执行任务flagprocess_task。

实验代码

首先定义一个事件标志组

事件标志组//
#define KEY0_FLAG		0x01
#define KEY1_FLAG		0x02
#define KEYFLAGS_VALUE	0X00						
OS_FLAG_GRP	EventFlags;		//定义一个事件标志组

然后创建一个事件标志组

	//创建一个事件标志组
	OSFlagCreate((OS_FLAG_GRP*)&EventFlags,		//指向事件标志组
                 (CPU_CHAR*	  )"Event Flags",	//名字
                 (OS_FLAGS	  )KEYFLAGS_VALUE,	//事件标志组初始值
                 (OS_ERR*  	  )&err);			//错误码

接着创建两个任务

	//创建主任务
	OSTaskCreate((OS_TCB*     )&Main_TaskTCB,		
				 (CPU_CHAR*   )"Main task", 		
                 (OS_TASK_PTR )main_task, 			
                 (void*       )0,					
                 (OS_PRIO	  )MAIN_TASK_PRIO,     
                 (CPU_STK*    )&MAIN_TASK_STK[0],	
                 (CPU_STK_SIZE)MAIN_STK_SIZE/10,	
                 (CPU_STK_SIZE)MAIN_STK_SIZE,		
                 (OS_MSG_QTY  )0,					
                 (OS_TICK	  )0,  					
                 (void*       )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR*     )&err);						
	//创建MSGDIS任务
	OSTaskCreate((OS_TCB*     )&Flagsprocess_TaskTCB,		
				 (CPU_CHAR*   )"Flagsprocess task", 		
                 (OS_TASK_PTR )flagsprocess_task, 			
                 (void* 	  )0,					
                 (OS_PRIO	  )FLAGSPROCESS_TASK_PRIO,     
                 (CPU_STK* 	  )&FLAGSPROCESS_TASK_STK[0],	
                 (CPU_STK_SIZE)FLAGSPROCESS_STK_SIZE/10,	
                 (CPU_STK_SIZE)FLAGSPROCESS_STK_SIZE,		
                 (OS_MSG_QTY  )0,					
                 (OS_TICK	  )0,  					
                 (void* 	  )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR* 	  )&err);

下面实现来个任务

//主任务的任务函数
void main_task(void *p_arg)
{
	u8 key,num;
	OS_FLAGS flags_num;
	OS_ERR err;
	while(1)
	{
		key = KEY_Scan(0);  //扫描按键
		if(key == KEY0_PRES)
		{
			//向事件标志组EventFlags发送标志
			flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,
								 (OS_FLAGS	  )KEY0_FLAG,
								 (OS_OPT	  )OS_OPT_POST_FLAG_SET,
					             (OS_ERR*	  )&err);
			LCD_ShowxNum(174,110,flags_num,1,16,0);
			printf("事件标志组EventFlags的值:%d\r\n",flags_num);
		}
		else if(key == KEY1_PRES)
		{
			//向事件标志组EventFlags发送标志
			flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,
								 (OS_FLAGS	  )KEY1_FLAG,
								 (OS_OPT	  )OS_OPT_POST_FLAG_SET,
								 (OS_ERR*     )&err);
			LCD_ShowxNum(174,110,flags_num,1,16,0);
			printf("事件标志组EventFlags的值:%d\r\n",flags_num);
		}
		num++;
		if(num==50)
		{
			num=0;
			LED0 = ~LED0;
		}
		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
	}
}

//事件标志组处理任务
void flagsprocess_task(void *p_arg)
{
	u8 num;
	OS_ERR err; 
	while(1)
	{
		//等待事件标志组
		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);
		num++;
		LED1 = ~LED1;
		LCD_Fill(6,131,233,313,lcd_discolor[num%14]);
		printf("事件标志组EventFlags的值:%d\r\n",EventFlags.Flags);
		LCD_ShowxNum(174,110,EventFlags.Flags,1,16,0);
	}
}

具体的实验现象,自己抄一下代码,烧录一下历程,分析一下就知道了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值