UCOS操作系统

文章目录

  • UCOS操作系统
  • 前言
  • 一、事件标志组
  • 二、相关函数
    • 1.创建事件标志组
    • 2. 等待事件标志组
    • 3.向事件标志组发布标志
  • 三、事件标志组实验

前言

前面我们提到过可以使用信号量来完成任务同步,这里我们再说一下另外一种任务同步的方法,就是事件标志组,事件标志组用来解决一个任务和多个事件之间的同步

一、事件标志组

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

1、任务和 ISR(中断服务程序)都可以发布事件标志,但是,只有任务可以创建、删除事件标志组以及取消其他任务对事件标志组的等待。
2、任务可以通过调用函数 OSFlagPend()等待事件标志组中的任意个事件标志,调用函数OSFlagPend()的时候可以设置一个超时时间,如果过了超时时间请求的事件还没有被发布,那么任务就会重新进入就绪态。
3、我们可以设置同步机制为“或”同步还是“与”同步

二、相关函数

1.创建事件标志组

在使用事件标志组之前,需要调用函数 OSFlagCreate()创建一个事件标志组,OSFlagCreate()函数原型如下

void OSFlagCreate ( OS_FLAG_GRP *p_grp,CPU_CHAR *p_name,OS_FLAGS flags,OS_ERR *p_err)

p_grp: 指向事件标志组,事件标志组的存储空间需要应用程序进行实际分配,我们可以按照下面的例子来定义一个事件标志组。
OS_FLAG_GRP EventFlag;
p_name: 事件标志组的名字。
flags: 定义事件标志组的初始值。32位bit,一个bit代表一个事件标志组
p_err: 用来保存调用此函数后返回的错误码。

2. 等待事件标志组

等待一个事件标志组需要调用函数 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 或者 32 比他。比如任务需要等待时间标志组的 bit0和 bit1 时(无论是等待置位还是清零),flag 是的值就为 0X03。(你要请求的位数是二进制1,其他是0,然后转16进制)
timeout: 指定等待事件标志组的超时时间(时钟节拍数),如果在指定的超时时间内所等待的一个或多个事件没有发生,那么任务恢复运行。如果此值设置为 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。
p_ts: 指向一个时间戳,记录了发送、终止和删除事件标志组的时刻,如果为这个指针赋值 NULL,则函数的调用者将不会收到时间戳。
p_err: 用来保存调用此函数后返回的错误码

3.向事件标志组发布标志

调用函数 OSFlagPost()可以对事件标志组进行置位或清零,函数原型如下

OS_FLAGS OSFlagPost ( OS_FLAG_GRP *p_grp,OS_FLAGS flags,OS_OPT opt,OS_ERR *p_err)

p_grp: 指向事件标志组。
flags: 决定对哪些位清零和置位,当 opt 参数为 OS_OPT_POST_FLAG_SET 的时,参数
flags 中置位的位就会在事件标志组中对应的位也将被置位。当 opt 为OS_OPT_POST_FLAG_CLR 的时候参数 flags 中置位的位在事件标志组中对应的位将被清零。
opt: 决定对标志位的操作,有两种选项。
OS_OPT_POST_FLAG_SET 对标志位进行置位操作
OS_OPT_POST_FLAG_CLR 对标志位进行清零操作
p_err: 保存调用此函数后返回的错误码。

三、事件标志组实验

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "malloc.h"
#include "sram.h"
#include "beep.h"
#include "includes.h"//ÈÎÎñÓÅÏȼ¶
#define START_TASK_PRIO     3
//ÈÎÎñ¶ÑÕ»´óС
#define START_STK_SIZE      128
//ÈÎÎñ¿ØÖÆ¿é
OS_TCB StartTaskTCB;
//ÈÎÎñ¶ÑÕ»
CPU_STK START_TASK_STK[START_STK_SIZE];
//ÈÎÎñº¯Êý
void start_task(void *p_arg);//ÈÎÎñÓÅÏȼ¶
#define MAIN_TASK_PRIO      4
//ÈÎÎñ¶ÑÕ»´óС
#define MAIN_STK_SIZE       128
//ÈÎÎñ¿ØÖÆ¿é
OS_TCB Main_TaskTCB;
//ÈÎÎñ¶ÑÕ»
CPU_STK MAIN_TASK_STK[MAIN_STK_SIZE];
void main_task(void *p_arg);//ÈÎÎñÓÅÏȼ¶
#define FLAGSPROCESS_TASK_PRIO  5
//ÈÎÎñ¶ÑÕ»´óС
#define FLAGSPROCESS_STK_SIZE   128
//ÈÎÎñ¿ØÖÆ¿é
OS_TCB Flagsprocess_TaskTCB;
//ÈÎÎñ¶ÑÕ»
CPU_STK FLAGSPROCESS_TASK_STK[FLAGSPROCESS_STK_SIZE];
//ÈÎÎñº¯Êý
void flagsprocess_task(void *p_arg);//LCDË¢ÆÁʱʹÓõÄÑÕÉ«
int lcd_discolor[14]={ WHITE, BLACK, BLUE,  BRED,      GRED,  GBLUE, RED,   MAGENTA,            GREEN, CYAN,  YELLOW,BROWN,            BRRED, GRAY };ʼþ±êÖ¾×é//
#define KEY0_FLAG       0x01
#define KEY1_FLAG       0x02
#define KEYFLAGS_VALUE  0X00
OS_FLAG_GRP EventFlags;     //¶¨ÒåÒ»¸öʼþ±êÖ¾×é//¼ÓÔØÖ÷½çÃæ
void ucos_load_main_ui(void)
{POINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");   LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 12-1");LCD_ShowString(30,50,200,16,16,"Event Flags");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,90,200,16,16,"2015/3/19");POINT_COLOR = BLACK;LCD_DrawRectangle(5,130,234,314);  //»­¾ØÐÎPOINT_COLOR = BLUE;LCD_ShowString(30,110,220,16,16,"Event Flags Value:0");
}//Ö÷º¯Êý
int main(void)
{OS_ERR err;CPU_SR_ALLOC();delay_init();  //ʱÖÓ³õʼ»¯NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//ÖжϷÖ×éÅäÖÃuart_init(115200);   //´®¿Ú³õʼ»¯LED_Init();         //LED³õʼ»¯ LCD_Init();         //LCD³õʼ»¯ KEY_Init();         //°´¼ü³õʼ»¯BEEP_Init();        //³õʼ»¯·äÃùÆ÷my_mem_init(SRAMIN);//³õʼ»¯ÄÚ²¿RAMucos_load_main_ui();//¼ÓÔØÖ÷UIOSInit(&err);            //³õʼ»¯UCOSIIIOS_CRITICAL_ENTER(); //½øÈëÁÙ½çÇø             //´´½¨¿ªÊ¼ÈÎÎñOSTaskCreate((OS_TCB     * )&StartTaskTCB,       //ÈÎÎñ¿ØÖÆ¿é(CPU_CHAR   * )"start task",      //ÈÎÎñÃû×Ö(OS_TASK_PTR )start_task,             //ÈÎÎñº¯Êý(void     * )0,                   //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý(OS_PRIO    )START_TASK_PRIO,     //ÈÎÎñÓÅÏȼ¶(CPU_STK   * )&START_TASK_STK[0],   //ÈÎÎñ¶ÑÕ»»ùµØÖ·(CPU_STK_SIZE)START_STK_SIZE/10,    //ÈÎÎñ¶ÑÕ»Éî¶ÈÏÞλ(CPU_STK_SIZE)START_STK_SIZE,     //ÈÎÎñ¶ÑÕ»´óС(OS_MSG_QTY  )0,                  //ÈÎÎñÄÚ²¿ÏûÏ¢¶ÓÁÐÄܹ»½ÓÊÕµÄ×î´óÏûÏ¢ÊýÄ¿,Ϊ0ʱ½ûÖ¹½ÓÊÕÏûÏ¢(OS_TICK    )0,                   //µ±Ê¹ÄÜʱ¼äƬÂÖתʱµÄʱ¼äƬ³¤¶È£¬Îª0ʱΪĬÈϳ¤¶È£¬(void    * )0,                   //Óû§²¹³äµÄ´æ´¢Çø(OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //ÈÎÎñÑ¡Ïî(OS_ERR  * )&err);               //´æ·Å¸Ãº¯Êý´íÎóʱµÄ·µ»ØÖµOS_CRITICAL_EXIT();   //Í˳öÁÙ½çÇø     OSStart(&err);      //¿ªÆôUCOSIII
}//¿ªÊ¼ÈÎÎñº¯Êý
void start_task(void *p_arg)
{OS_ERR err;CPU_SR_ALLOC();p_arg = p_arg;CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0uOSStatTaskCPUUsageInit(&err);    //ͳ¼ÆÈÎÎñ
#endif#ifdef CPU_CFG_INT_DIS_MEAS_EN        //Èç¹ûʹÄÜÁ˲âÁ¿ÖжϹرÕʱ¼äCPU_IntDisMeasMaxCurReset();
#endif#if   OS_CFG_SCHED_ROUND_ROBIN_EN  //µ±Ê¹ÓÃʱ¼äƬÂÖתµÄʱºò//ʹÄÜʱ¼äƬÂÖתµ÷¶È¹¦ÄÜ,ʱ¼äƬ³¤¶ÈΪ1¸öϵͳʱÖÓ½ÚÅÄ£¬¼È1*5=5msOSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif  OS_CRITICAL_ENTER();    //½øÈëÁÙ½çÇø//´´½¨Ò»¸öʼþ±êÖ¾×é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);   OS_CRITICAL_EXIT(); //Í˳öÁÙ½çÇøOSTaskDel((OS_TCB*)0,&err); //ɾ³ýstart_taskÈÎÎñ×ÔÉí
}//Ö÷ÈÎÎñµÄÈÎÎñº¯Êý
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);}
}

main_task()函数为主任务的任务函数,函数里面主要是获取按键值,如果按下 KEY0 的话就调用 OSFlagPost()向事件标志组 EventFlags 发布标志 KEY0_FLAG,如果按下 KEY1 的话就向事件标志组 EventFlags 发布 KEY1_FLAG。 在 main_task()函数中每调用一次 OSFlagPost()就 在 LCD 上显示事件标志组 EventFlags 的当前值并且通过串口输出这个值,我们可以通过这个值的变化来观察事件标志组各个事件产生的过程。

flagsprocess_task()函数为事件标志组处理任务的任务函数,在这个函数中我们一直等待事
件标志组 Eventflags 中相应的事件发生,当等待的事件发生的话就刷新 LCD 下方方框的背景颜
色,并且控制 LED1 反转。

此时是没有现象的,当我们按下 KEY0 的时候

此时事件标志组 EventFlags 的值为 1,因为我们按下 KEY0 的话EventFlags 的 bit0 就会置 1,但是此时 KEY1 还没有按下因此下方方框内的背景还是为白色。此时我们再按下 KEY1 键

可以看出此时 EventFlags 的值为 0,这是因为我们按下 KEY1 后,任务flagsprocess_task 等待的事件都发生了就会刷新一次下方方框内背景,并且 LED1 会反转。我们在调用函数 OSFlagPend()的时候设定了参数 opt 为 OS_OPT_PEND_FLAG_SET_ALL 和OS_OPT_PEND_FLAG_CONSUME,因此会清除相应的标志的,因此此时的事件标志组的值就为 0 了。

注意!其实当我们按下 KEY1 的一瞬间事件标志组 EventFlags 的值应该为 3 的,但是很快会被任务 flagsprocess_task 刷新掉显示为 0,这个过程非常快,在 LCD 上是看不出来的,不过串口是可以看出来的

UCOS操作系统——事件标志组(十四)相关推荐

  1. RTX5 | 事件标志组01 - 创建事件标志组

    文章目录 一.前言 二.实验目的 三.API 3.1.osEventFlagsAttr_t 3.2.osEventFlagsNew 四.代码 4.1.main.h 4.2.main.c 五.Event ...

  2. FreeRTOS操作系统——任务通知模拟消息邮箱及事件标志组(十八)

    FreeRTOS操作系统学习 文章目录 FreeRTOS操作系统学习 一.消息邮箱API函数 二.消息邮箱实验 三.事件标志组实验 总结 一.消息邮箱API函数 任务通知也可用来向任务发送数据,但是相 ...

  3. FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)

    我们在前面单独介绍过FreeRTOS的任务通知和消息队列, 但是在FreeRTOS中任务间的通讯还有信号量,邮箱,事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 ..增 ...

  4. 【IoT】STM32 系统级开发之 ucosIII 或 freeRTOS 事件标志组详解

    1.轻型操作系统同步的方案详解 1)信号量 假设有两个任务 Task1 和 Task2,第一个任务进行按键的扫描,第二个任务进行LED灯的点亮 需求: 扫描到按键按下后点亮 LED 灯,也就是说第二个 ...

  5. 用事件标志组实现多事件的单向同步

    文章目录 1 用事件标志组实现多事件的单向同步 1 用事件标志组实现多事件的单向同步 问题需求: 某一任务等待事件中一个或多个事件同时发生. 解决方案: 事件发生时,设置指定事件标志位,任务4等待所有 ...

  6. 事件标志组解决任务间资源共享问题

    文章目录 1 事件标志组解决任务间资源共享问题 1.1 工作原理 1.2 分析 1 事件标志组解决任务间资源共享问题 1.1 工作原理 tinyOS的事件标志组实现: 代码: /*** @brief ...

  7. 事件标志组的删除与状态查询

    文章目录 1 事件标志组的删除与状态查询 1.1 设计实现 1 事件标志组的删除与状态查询 1.1 设计实现 事件标志组的删除: 状态查询: 参考资料: [李述铜]从0到1自己动手写嵌入式操作系统

  8. 事件标志组的等待与通知

    文章目录 1 事件标志组的等待与通知 1.1 设计需求 1.2 设计实现 1 事件标志组的等待与通知 1.1 设计需求 当事件标志位发生时: 没有任务等待,设置相应的事件标志. 有任务等待时,唤醒等待 ...

  9. 事件标志组的原理与创建

    文章目录 1 事件标志组的原理与创建 1.1 问题概述 1.2 设计原理 1.3 设计实现 1 事件标志组的原理与创建 1.1 问题概述 如何在中断ISR与任务之间传递多个事件标志? 可以通过事件标志 ...

最新文章

  1. 暴风前员工替冯鑫惋惜,是公司的老白兔员工害了他
  2. 深度学习处在大爆炸时代的边缘
  3. settimeout需要清除吗_钢结构抛丸机可以清理结构件上的焊渣吗?
  4. Lua应用——tables应用,查找是否为保留字
  5. 为什么我的文章没有被推荐?
  6. 算法竞赛入门与进阶 (一)枚举
  7. mysql ehcache_MyBatis使用Ehcache作为二级缓存
  8. NET比较常用的性能优化技巧
  9. SSKeychain
  10. 阿里技术专家浅谈微服务架构
  11. Hibernate的使用
  12. MacOS开发-给自己的 app 添加 URL Scheme(Xcode 9之后)
  13. 【小白】线性表的链式存储结构的实现(C语言版)
  14. css中“~”(波浪号)、“,”(逗号)、 “ + ”(加号)和 “ ”(大于号)是什么意思?
  15. Java开发必知Linux命令
  16. Python从入门到实战,我觉着拥有这三本书很有必要
  17. R语言Bonferroni校正的成对t检验进行事后检验(post hoc)实战:单因素方差分析告诉我们并不是所有的群体手段的效果是均等的,确切地找出哪些组彼此不同使用Bonferroni校正检验
  18. Daily English - go for it.
  19. 【渝粤题库】陕西师范大学164107 电子商务信息安全 作业(高起专)
  20. 2021-07-01:并查集,200岛屿问题,547朋友圈问题

热门文章

  1. 数据库概论知识点总结
  2. 广工物理实验-半导体热敏电阻温度特性的研究
  3. 中机软云亮相2021青岛国际软件融合创新博览会现场
  4. xss漏洞扫描器开发随想
  5. Linux学习笔记05、CentOS 7的中文输入法设置
  6. 如何将chatgpt接入微信
  7. 《iOS取证实战:调查、分析与移动安全》一1.3 取证审查方法
  8. photon 服务器操作系统,PhotonServer游戏服务器部署及日志输出之美
  9. java公告栏js资源_javascript制作滚动公告栏
  10. 相机上的WB、ISO、S、EV各是什么意思?