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);
	}	
}

  

 

  

posted @ 2021-09-05 16:11  轻轻的吻  阅读(403)  评论(0编辑  收藏  举报