【UCOSIII操作系统】事件篇

UCOSIII其他内容导航不迷路
UCOSIII操作系统-简介
【UCOSIII操作系统】任务篇(1)创建任务
【UCOSIII操作系统】任务篇(2)相关API函数
【UCOSIII操作系统】系统初始化篇(1)系统初始化
【UCOSIII操作系统】系统初始化篇(2)CPU,SysTick,内存初始化
【UCOSIII操作系统】硬件初始化篇(1)硬件初始化以及开始运行系统
【UCOSIII操作系统】消息队列篇(1)消息队列
【UCOSIII操作系统】消息队列篇(2)任务消息队列
【UCOSIII操作系统】信号量与互斥量篇(1)信号量
【UCOSIII操作系统】信号量与互斥量篇(2)互斥量
【UCOSIII操作系统】信号量与互斥量篇(3)任务信号量
【UCOSIII操作系统】中断管理篇
【UCOSIII操作系统】临界段篇
【UCOSIII操作系统】软件定时器篇
【UCOSIII操作系统】内存管理篇
已完结

说在前面:
这个内容不适合0基础的人,因为这里只讲了应用层面的东西,并没有深入内核讲解,所以要从零开始学UCOSIII的朋友,可以先去学完入门内容,再来观看这个笔记加深印象。
这篇文章是个人学习整理,如有错误请指正

UCOSIII操作系统——事件篇

  • 前面我们讲过可以使用信号量来完成任务同步,这里我们再讲解一-下另外一种任务同步的
    方法,就是事件标志组,事件标志组用来解决一个任务和多个事件之间的同步。
  • 事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。
  • 相当于标志位(可以这么理解吧)
  • 事件不与任务相关联,事件相互独立,一个32位的变量就是事件的集合,用于标识该任务发生的事件类型,其中每一位表示一种事件类型 (0表示该事件类型未发生、1表示该事件类型已经发生),一共32种事件。
  • 32个事件,一个32位的变量,每一位表示一个事件

事件相关的API函数

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

创建事件标志组->OSFlagCreate()

  • 函数原型
void  OSFlagCreate (OS_FLAG_GRP  *p_grp,  //事件标志组指针
                    CPU_CHAR     *p_name, //命名事件标志组
                    OS_FLAGS      flags,  //标志初始值
                    OS_ERR       *p_err)  //返回错误类型

事件标志组指针: 事件标志组的存储空间需要应用程序进行实际分配,我们可以
按照下面的例子来定义一个事件标志组。

OS_FLAG_GRP flag_grp;     //声明事件标志组

标志初始值赋0就好

  • 创建实例
 /* 创建事件标志组 flag_grp */
 OSFlagCreate ((OS_FLAG_GRP  *)&flag_grp,        //指向事件标志组的指针
               (CPU_CHAR     *)"FLAG For Test",  //事件标志组的名字
               (OS_FLAGS      )0,                //事件标志组的初始值
               (OS_ERR       *)&err);			//返回错误类型

向事件标志组发布标志->OSFlagPost()

OSFlagPost()用于设置事件组中指定的位。使用该函数接口时,通过参数指定的事件标志来设置事件的标志位,然后遍历等待在事件对象上的事件等待列表,判断是否有任务的事件激活要求与当前事件对象标志值匹配,如果有,则唤醒该任务。简单来说,就是设置我们自己定义的事件标志位为1, 并且看看有没有任务在等待这个事件,有的话就唤醒它。

  • 函数原型
OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp, //事件标志组指针
                      OS_FLAGS      flags, //选定要操作的标志位
                      OS_OPT        opt,   //选项
                      OS_ERR       *p_err) //返回错误类型

flag 赋值有多种方法(这里是确定哪一位要操作,并不是置位复位)

//这是一种方法
#define KEY0_FLAG		0x01
#define KEY1_FLAG		0x02
//这是另一种方法
#define KEY1_EVENT  (0x01 << 0)//设置事件掩码的位0
#define KEY2_EVENT  (0x01 << 1)//设置事件掩码的位1

opt选项 (通过这个选项来确定标志位是置位还是复位)
决定对标志位的操作,有两种选项。
OS_OPT_POST_FLAG_SET 对标志位进行置位操作
OS_OPT_POST_FLAG_CLR 对标志位进行清零操作

  • 应用实例
	while (DEF_TRUE) {                                                     //任务体
		if( Key_ReadStatus ( macKEY1_GPIO_PORT, macKEY1_GPIO_PIN, 1 ) == 1 ) //如果KEY1被按下
		{		                                                    //点亮LED1
			printf("KEY1被按下\n");
			OSFlagPost ((OS_FLAG_GRP  *)&flag_grp,                             //将标志组的BIT0置1
                  (OS_FLAGS      )KEY1_EVENT,
                  (OS_OPT        )OS_OPT_POST_FLAG_SET,
                  (OS_ERR       *)&err);

		}

		if( Key_ReadStatus ( macKEY2_GPIO_PORT, macKEY2_GPIO_PIN, 1 ) == 1 ) //如果KEY2被按下
		{		                                                    //点亮LED2
			printf("KEY2被按下\n");
			OSFlagPost ((OS_FLAG_GRP  *)&flag_grp,                             //将标志组的BIT1置1
                  (OS_FLAGS      )KEY2_EVENT,
                  (OS_OPT        )OS_OPT_POST_FLAG_SET,
                  (OS_ERR       *)&err);

		}

		OSTimeDlyHMSM ( 0, 0, 0, 20, OS_OPT_TIME_DLY, & err );  //每20ms扫描一次
	}

等待事件标志组->OSFlagPend()

既然标记了事件的发生,那么我们怎么知道他到底有没有发生,这也是需要一个函数来获取事件是否已经发生,uCOS提供了一个等待指定事件的函数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)   //返回错误类型

选定要操作的标志位: 这个和发布事件对应的标志位一样就行
等待期限: 指定等待事件标志组的超时时间(时钟节拍数),如果在指定的超时时间内所等待的一个或多个事件没有发生,那么任务恢复运行。如果此值设置为0,则任务就将一直等待下去,直到一个或多个事件发生。
选项opt: 决定任务等待的条件是所有标志置位、所有标志清零、任意一个标志置位还是任意一个标志清零,具体的定义如下。

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			标志组不满足条件时挂起任务。
这里应该注意选项OS_OPT_ PEND_FLAG_CONSUME的使用方法,
如果我们希望任务等待事件标志组的任意一个标志置位,
并在满足条件后将对应的标志清零那么就可以搭配使用选项OS_OPT_PEND_FLAG_CONSUME。
消耗掉该事件标志位,即清零
  • 应用实例
/*
*********************************************************************************************************
*                                          PEND TASK
*********************************************************************************************************
*/
static  void  AppTaskPend ( void * p_arg )
{
	OS_ERR      err;
 	OS_FLAGS    flags_rdy;
	(void)p_arg;	 
	while (DEF_TRUE) {                                       //任务体
  //等待标志组的的BIT0和BIT1均被置1 
  flags_rdy =   OSFlagPend ((OS_FLAG_GRP *)&flag_grp,                 
							(OS_FLAGS     )( KEY1_EVENT | KEY2_EVENT ),
							(OS_TICK      )0,
							(OS_OPT       )OS_OPT_PEND_FLAG_SET_ALL |
										 OS_OPT_PEND_BLOCKING |
										OS_OPT_PEND_FLAG_CONSUME,
							(CPU_TS      *)0,
							(OS_ERR      *)&err);
    if((flags_rdy & (KEY1_EVENT|KEY2_EVENT)) == (KEY1_EVENT|KEY2_EVENT)) 
    {
      /* 如果接收完成并且正确 */
      printf ( "KEY1与KEY2都按下\n");		
      macLED1_TOGGLE();       //LED1	反转
    }
	}
}

删除事件标志组->OSFlagDel()

想要使用删除事件函数则必须将OS_CFG_FLAG_DEL_EN 宏定义配置为1

  • 函数原型
#if OS_CFG_FLAG_DEL_EN > 0u //如果使能了 OSFlagDel() 函数
OS_OBJ_QTY OSFlagDel (OS_FLAG_GRP *p_grp, 	//事件指针
					OS_OPT opt, 			//选项
					OS_ERR *p_err) 			//返回错误类型

opt选项:
OS_OPT_DEL_NO_PEND //如果只在没任务等待时进行删除
OS_OPT_DEL_ALWAYS //如果必须删除事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值