STM32F407ZGT6-UCOSIII笔记12: 事件标志组

news2024/12/23 8:36:03

有时一个任务需要与多个事件同步,这就要用到事件标志组

 本文学习与程序编写基于 正点原子的 STM32F1 UCOS开发手册

文章提供测试代码讲解、完整工程下载、测试效果图

目录

事件标志组:

定义与初始化事件标志组:

 #include "Public.h"定义事件标志组

 #include"main.h"创建事件标志组

实验目标解释:

目前各个文件任务:

#include "main.h"

#include "Public.h" 

 #include "ComTask.h"

 #include "MessageTask.h"

 #include "CalculateTask.h"

测试效果截图: 

测试工程下载: 


事件标志组:

 

定义与初始化事件标志组:

 #include "Public.h"定义事件标志组

OS_FLAG_GRP EventFlags; //定义一个事件标志组

顺带有一些宏定义:

#define LED_GREEN_FLAG  0x01    //LED绿灯标志
#define EXTI15_10_IRQ_FLAG 0x02 //按键中断时间标志 
#define EventFlags_Value 0x00   //事件标志初始值 
extern OS_FLAG_GRP EventFlags; //定义一个事件标志组

 #include"main.h"创建事件标志组

在void start_task(void *p_arg) //开始任务函数 创建事件标志组:

	//创建一个事件标志组							
	OSFlagCreate((OS_FLAG_GRP *) &EventFlags, //指向事件标志组
							 (CPU_CHAR	* )"EventFlags", 	//名称
							 (OS_FLAGS ) EventFlags_Value,//事件标志组初始值
							 (OS_ERR *) &err
							 );

实验目标解释:

设计程序:

MessageTask 循环亮灯 打印自己运行次数,亮绿灯就发送绿灯 事件标志组

ComTask 循环检测外部中断标志,检测到就发送对应 事件标志,并打印此时的值

只有当MessageTask亮灯为绿色,且外部中断按键按下时,才运行CalculateTask

CalculateTask 开始打印自己运行次数

目前各个文件任务:

#include "main.h"

初始化各个任务: 初始化事件标志组:

#include "main.h"

void start_task(void *p_arg);//开始任务函数


int main(void)
{
	OS_ERR err;
	CPU_SR_ALLOC();
  Init_ALL();
	OSInit(&err);		//初始化UCOSIII
	
	OS_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

	while(1);
}

//开始任务函数
void start_task(void *p_arg)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;

	CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);  	//统计任务                
#endif
	
#ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();	
#endif

#if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif		
	//初始化 OS_Timer1_Periodic 软件定时器
	OSTmrCreate((OS_TMR *) &OS_Timer1_Periodic ,   //OS系统 软件定时器 1 周期模式 
							(CPU_CHAR *) "OS_Timer1_Periodic", //定时器名称
							(OS_TICK ) 100,  // 启动延时 为100*10 ms
							(OS_TICK ) 20,   // 周期为 20*10 ms
							(OS_OPT  ) OS_OPT_TMR_PERIODIC, //周期定时模式
							(OS_TMR_CALLBACK_PTR ) OS_Timer1_Periodic_callback,//回调函数
							(void * )  0,//参数为0
							(OS_ERR *) &err		
							);
	
	OS_CRITICAL_ENTER();	//进入临界区
	
创建消息队列 Message_Msg 							
//	OSQCreate( (OS_Q *) &Message_Msg,//消息队列 Message_Msg
//						 (CPU_CHAR	* )"Message_Msg", //名称
//						 (OS_MSG_QTY ) Message_Msg_NUM, //消息队列长度
//						 (OS_ERR *)	 &err   
//							);
创建消息队列 DATA_Msg							
//	OSQCreate( (OS_Q *) &DATA_Msg,//消息队列 DATA_Msg
//						 (CPU_CHAR	* )"DATA_Msg", //名称
//						 (OS_MSG_QTY ) DATA_Msg_NUM, //消息队列长度
//						 (OS_ERR *)	 &err   
//							);

	//创建一个事件标志组							
	OSFlagCreate((OS_FLAG_GRP *) &EventFlags, //指向事件标志组
							 (CPU_CHAR	* )"EventFlags", 	//名称
							 (OS_FLAGS ) EventFlags_Value,//事件标志组初始值
							 (OS_ERR *) &err
							 );
							 
	//创建ComTask任务
	OSTaskCreate((OS_TCB 	* )&COMTASKTaskTCB,		
				 (CPU_CHAR	* )"com task", 		
                 (OS_TASK_PTR )comTask, 			
                 (void		* )0,					
                 (OS_PRIO	  )COMTASK_TASK_PRIO,     
                 (CPU_STK   * )&COMTASK_TASK_STK[0],	
                 (CPU_STK_SIZE)COMTASK_STK_SIZE/10,	
                 (CPU_STK_SIZE)COMTASK_STK_SIZE,		
                 (OS_MSG_QTY  )0,					
                 (OS_TICK	  )0,					//之前为0 //2个时间片 2*5ms
                 (void   	* )0,					
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                 (OS_ERR 	* )&err);				
				 
	//创建MessageTask任务
	OSTaskCreate((OS_TCB 	* )&MessageTaskTaskTCB,		
				 (CPU_CHAR	* )"Message task", 		
                 (OS_TASK_PTR )MessageTask, 			
                 (void		* )0,					
                 (OS_PRIO	  )MessageTask_TASK_PRIO,     	
                 (CPU_STK   * )&MessageTask_TASK_STK[0],	
                 (CPU_STK_SIZE)MessageTask_STK_SIZE/10,	
                 (CPU_STK_SIZE)MessageTask_STK_SIZE,		
                 (OS_MSG_QTY  )TASK_Q_NUM,					
                 (OS_TICK	  )0,					//之前为0 //2个时间片 2*5ms
                 (void   	* )0,				
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, 
                 (OS_ERR 	* )&err);
				 
	//创建CalculateTask任务
	OSTaskCreate((OS_TCB 	* )&CalculateTaskTaskTCB,		
				 (CPU_CHAR	* )"Calculate task", 		
                 (OS_TASK_PTR )CalculateTask,	
                 (void		* )0,					
                 (OS_PRIO	  )CalculateTask_TASK_PRIO,     	
                 (CPU_STK   * )&CalculateTask_TASK_STK[0],	
                 (CPU_STK_SIZE)CalculateTask_STK_SIZE/10,	
                 (CPU_STK_SIZE)CalculateTask_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);				 
								 
//		//创建 Shared_Str共享全局资源 的 信号量							
//		OSSemCreate((OS_SEM *) &SEM_Shared_Str, //指向信号量
//								 (CPU_CHAR *) "SEM_Shared_Str", //信号量名称
//								  (	OS_SEM_CTR ) 1,     //信号量值为1
//								  (OS_ERR *)  &err
//								 );		
//								 
//		//创建 Shared_Str共享全局资源 的 互斥信号量							
//		OSMutexCreate((OS_MUTEX *) &MUTEX_Shared_Str, //指向互斥信号量
//								 (CPU_CHAR *) "MUTEX_Shared_Str", //互斥信号量名称
//								  (OS_ERR *)  &err
//								 );
								 
								 
	OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);		//挂起开始任务			 
	OS_CRITICAL_EXIT();	//进入临界区
}

#include "Public.h" 

外部中断的中断服务函数,用于置标志位,提示事件发生:


//外部中断0服务程序
void EXTI15_10_IRQHandler(void)
{
	 //OS_Timer1_Periodic_flag=1;   // 定时器状态 标志取1 
		EXTI15_10_IRQ_flag=!EXTI15_10_IRQ_flag; //外部中断标志取反
	  EXTI_ClearITPendingBit(EXTI_Line15); //清除LINE0上的中断标志位 
}	

 #include "ComTask.h"

#include "ComTask.h"

/*
	ComTask 
	打印系统节拍频率
	
	循环中:
	ComTask 计数 自己运行次数
	
	根据 外部中断 控制的 标志位 发送 外部中断 事件标志
	同时打印发送完后 EventFlags 事件标志组 的值 
	随后 置0 外部中断 事件标志,准备下次触发 
	
	延时50ms
*/

void comTask(void * p_arg)
{
	OS_ERR err;
	int i=0,OSTime_tickRate;

	
	p_arg = p_arg;
	OSTime_tickRate=OSCfg_TickRate_Hz;            //获取系统节拍频率,(该宏定义在 OS_CFG_APP.H)
	UsartPrintf(USART1, "OSCfg_TickRate_Hz = %d Hz \r\n",OSTime_tickRate);  //打印系统节拍频率
	UsartPrintf(USART1, "ComTask Print %d\r\n",i);	//打印 ComTask 运行次数
	
	while (DEF_TRUE)
	{
		i++;
		// EXTI15_10_IRQ_flag 置0 用于限制comTask 检测标志位动作只有一次
		if(EXTI15_10_IRQ_flag==1)
		{
			flag_num=OSFlagPost((OS_FLAG_GRP *)&EventFlags,
													(OS_FLAGS ) EXTI15_10_IRQ_FLAG,
													(OS_OPT ) OS_OPT_POST_FLAG_SET,
													(OS_ERR *) &err
													);
			UsartPrintf(USART1, "EventFlags Value %d\r\n",flag_num);	//打印 EventFlags 事件标志组的值 
			EXTI15_10_IRQ_flag=0;
		}
		
		OSTimeDlyHMSM(0,0,0,50,OS_OPT_TIME_HMSM_STRICT,&err); //延时50ms
	}

}

 #include "MessageTask.h"

#include "MessageTask.h"

/*
	MessageTask
	计数打印一次运行次数
	
	每隔 2s 切换一次灯状态
	当切换到绿灯时发送绿灯的事件标志 并打印此时事件标志组的值
	
*/
void MessageTask (void * p_arg)
{
	OS_ERR err;
	int i=0;
//	OS_MSG_SIZE size;
//	char *p;
//	CPU_SR_ALLOC();	
	
	p_arg = p_arg;
	while (DEF_TRUE)
	{
		i++;	
		UsartPrintf(USART1, "MessageTask Print %d\r\n",i);	//打印 MessageTask 运行次数
		
		LED_RED_L;LED_GREEN_H;LED_Blue_H;		//单独亮红灯
		OSTimeDlyHMSM(0,0,2,0,OS_OPT_TIME_HMSM_STRICT,&err);  //延时2s		
		UsartPrintf(USART1, "LED RED\r\n");	//打印 红灯	
		
		LED_Blue_L;LED_RED_H;LED_GREEN_H;		//单独亮蓝灯
		OSTimeDlyHMSM(0,0,2,0,OS_OPT_TIME_HMSM_STRICT,&err);  //延时2s
		UsartPrintf(USART1, "LED BLUE\r\n");	//打印 蓝灯 
		
		LED_GREEN_L;LED_RED_H;LED_Blue_H;	    //单独亮绿灯
		OSTimeDlyHMSM(0,0,2,0,OS_OPT_TIME_HMSM_STRICT,&err);  //延时2s
		UsartPrintf(USART1, "LED GREEN\r\n");	//打印 绿灯 
		
		flag_num=OSFlagPost((OS_FLAG_GRP *)&EventFlags,
													(OS_FLAGS ) LED_GREEN_FLAG,
													(OS_OPT ) OS_OPT_POST_FLAG_SET,
													(OS_ERR *) &err
													);
	  UsartPrintf(USART1, "EventFlags Value %d\r\n",flag_num);	//打印 EventFlags 事件标志组的值
		
	}
	
}

 #include "CalculateTask.h"

如果测试有问题,可尝试将 CalculateTask 的延时降低 

#include "CalculateTask.h"

/*	CalculateTask 
		等待事件标志
		打印自己运行次数 
		然后等待1000ms
*/
void  CalculateTask(void  *p_arg)
{
	OS_ERR err;
	int i=0;
	//int times;
	
	p_arg = p_arg;
	while (DEF_TRUE)
	{
		OSFlagPend((OS_FLAG_GRP *) &EventFlags,
								(OS_FLAGS ) LED_GREEN_FLAG+EXTI15_10_IRQ_FLAG,//表示俩个事件都要发生(无需同时)
								(OS_TICK )0,//无限制等待 事件标志组满足条件
								(OS_OPT) OS_OPT_PEND_FLAG_SET_ALL+OS_OPT_PEND_FLAG_CONSUME, //等待事件标志,满足条件后全部清零
								(CPU_TS *) 0, //时间戳
								(OS_ERR *) &err
							);
		i++;
		UsartPrintf(USART1, "CalculateTask Print %d\r\n",i);
		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时1000ms
	}
}


测试效果截图: 

这里需要注意的只有事件发生先后,事件标志组的值不一样

先发生绿灯事件,事件标志组的值是1

先发生按键中断事件,事件标志组的值是2

但肯定要满足俩事件相加,也就是事件标志组的值为3时,才会触发CalculateTask运行一次

CalculateTask运行一次后又会将 事件标志组 全部清零

 

 代码逻辑问题修改:

顺便说一下下载工程的小逻辑问题需要修改一下:

之前没有注意到灯语打印的逻辑不对版,发现是将打印状态放在了延时语句之后

这会导致蓝灯时打印RED,换到延时之前打印就行了,

测试工程下载: 

 工程包含一份程序设计框架说明,不明白可以看看:

https://download.csdn.net/download/qq_64257614/90158960

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聊一聊 C#前台线程 如何阻塞程序退出

一:背景 1. 讲故事 这篇文章起源于我的 C#内功修炼训练营里的一位朋友提的问题:后台线程的内部是如何运转的 ? ,犹记得C# Via CLR这本书中 Jeffery 就聊到了他曾经给别人解决一个程序无法退出的bug,最后发现是有一个 Backgrond…

JVM性能优化一:初识内存泄露-内存溢出-垃圾回收

本文主要是让你充分的认识到什么叫做内存泄露,什么叫做内存溢出,别再傻傻分不清了,别再动不动的升级服务器的内存了。 文章目录 1.基本概念1.1.内存泄露1.2.内存溢出1.3.垃圾回收1.4.内存泄露-垃圾回收-内存溢出三者的关系关系 2.代码示例2.…

为什么使用环形队列

1.看以下两种情况。第一种不会出现问题,当主流程读取次数比较慢时,数据会被覆盖。 2.扩大空间。不可取。 3.什么是队列

【WRF教程第3.6期】预处理系统 WPS 详解:以4.5版本为例

预处理系统 WPS 详解:以4.5版本为例 Geogrid/Metgrid 插值选项详解1. 插值方法的工作机制2. 插值方法的详细说明2.1 四点双线性插值(four_pt)2.2 十六点重叠抛物线插值(sixteen_pt)2.3 简单四点平均插值(av…

批量提取zotero的论文构建知识库做问答的大模型(可选)——含转存PDF-分割统计PDF等

文章目录 提取zotero的PDF上传到AI平台保留文件名代码分成20个PDF视频讲解 提取zotero的PDF 右键查看目录 发现目录为 C:\Users\89735\Zotero\storage 写代码: 扫描路径‘C:\Users\89735\Zotero\storage’下面的所有PDF文件,全部复制一份汇总到"C:\Users\89735\Downl…

Java模拟Mqtt客户端连接Mqtt Broker

Java模拟Mqtt客户端基本流程 引入Paho MQTT客户端库 <dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.mqttv5.client</artifactId><version>1.2.5</version> </dependency>设置mqtt配置数据 …

boost asio 异步服务器

boost网络框架使用方法 boost绑定 首先介绍io_context&#xff0c;可以理解为这是操作系统和应用层数据交互的桥梁。有了它不必关注内核态的缓冲区&#xff0c;只需要关注自己定义在用户态的缓冲区&#xff0c;因为它会通过桥梁运输到用户态的缓冲区。 boost::asio::io_contex…

图解HTTP-HTTP协议

HTTP HTTP是一种不保存状态&#xff0c;即无状态的协议。HTTP协议自身不对请求和响应之间的通信进行保存。为了保存状态因此后面也有一些技术产生比如Cookies技术。 HTTP是通过URI定位网上的资源&#xff0c;理论上将URI可以访问互联网上的任意资源。 如果不是访问特定的资源…

【Go】-限流器的四种实现方法

目录 关于限流和限流器 固定窗口限流器 滑动窗口限流器 漏桶限流器 令牌桶限流器 总结 关于限流和限流器 限流&#xff08;Rate Limiting&#xff09;是一种控制资源使用率的机制&#xff0c;通常用于防止系统过载和滥用。 限流器&#xff08;Rate Limiter&#xff09;是…

CTF_1

CTF_Show 萌新赛 1.签到题 <?php if(isset($_GET[url])){system("curl https://".$_GET[url].".ctf.show"); }else{show_source(__FILE__); }?> 和 AI 一起分析 1.if(isset($_GET[url]))检查GET请求中是否存在名为url的参数。 curl 2.curl…

[文献阅读] Unsupervised Deep Embedding for Clustering Analysis (无监督的深度嵌入式聚类)

文章目录 Abstract:摘要聚类深度聚类 KL散度深度嵌入式聚类(DEC)KL散度聚类软分配&#xff08;soft assignment&#xff09;KL散度损失训练编码器的初始化聚类中心的初始化 实验评估总结 Abstract: This week I read Unsupervised Deep Embedding for Clustering Analysis .It…

记录:virt-manager配置Ubuntu arm虚拟机

virt-manager&#xff08;Virtual Machine Manager&#xff09;是一个图形用户界面应用程序&#xff0c;通过libvirt管理虚拟机&#xff08;即作为libvirt的图形前端&#xff09; 因为要在Linux arm环境做测试&#xff0c;记录下virt-manager配置arm虚拟机的过程 先在VMWare中…

使用C语言编写UDP循环接收并打印消息的程序

使用C语言编写UDP循环接收并打印消息的程序 前提条件程序概述伪代码C语言实现编译和运行C改进之自由设定端口注意事项在本文中,我们将展示如何使用C语言编写一个简单的UDP服务器程序,该程序将循环接收来自指定端口的UDP消息,并将接收到的消息打印到控制台。我们将使用POSIX套…

Spring Boot 教程之三十六:实现身份验证

如何在 Spring Boot 中实现简单的身份验证&#xff1f; 在本文中&#xff0c;我们将学习如何使用 Spring设置和配置基本身份验证。身份验证是任何类型的安全性中的主要步骤之一。Spring 提供依赖项&#xff0c;即Spring Security&#xff0c;可帮助在 API 上建立身份验证。有很…

什么样的LabVIEW控制算自动控制?

自动控制是指系统通过预先设计的算法和逻辑&#xff0c;在无人工干预的情况下对被控对象的状态进行实时监测、决策和调整&#xff0c;达到预期目标的过程。LabVIEW作为一种图形化编程工具&#xff0c;非常适合开发自动控制系统。那么&#xff0c;什么样的LabVIEW控制算作“自动…

GFPS扩展技术原理(七)-音频切换消息流

音频切换消息流 Seeker和Provider通过消息流来同步音频切换能力&#xff0c;触发连接做切换&#xff0c;获取或设置音频切换偏好&#xff0c;通知连接状态等等。为此专门定义了音频切换消息流Message Group 为0x07&#xff0c;Message codes如下&#xff1a; MAC of Audio s…

视频直播点播平台EasyDSS与无人机技术的森林防火融合应用

随着科技的飞速发展&#xff0c;无人机技术以其独特的优势在各个领域得到了广泛应用&#xff0c;特别是在森林防火这一关键领域&#xff0c;EasyDSS视频平台与无人机技术的融合应用更是为传统森林防火手段带来很大的变化。 一、无人机技术在森林防火中的优势 ‌1、快速响应与高…

机器人路径规划和避障算法matlab仿真,分别对比贪婪搜索,最安全距离,RPM以及RRT四种算法

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1贪婪搜索算法原理 4.2最安全距离算法原理 4.3RPM 算法原理 4.4 RRT 算法原理 5.完整程序 1.程序功能描述 机器人路径规划和避障算法matlab仿真,分别对比贪婪搜索,最安全距离,RPM以及R…

【论文笔记】Visual Alignment Pre-training for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Visual Alignment Pre-tra…

【附源码】Electron Windows桌面壁纸开发中的 CommonJS 和 ES Module 引入问题以及 Webpack 如何处理这种兼容

背景 在尝试让 ChatGPT 自动开发一个桌面壁纸更改的功能时&#xff0c;发现引入了一个 wallpaper 库&#xff0c;这个库的入口文件是 index.js&#xff0c;但是 package.json 文件下的 type:"module"&#xff0c;这样造成了无论你使用 import from 还是 require&…