当前位置: 首页 > news >正文

FreeRTROS3——事件组和定时器

一、介绍事件组

跟其他信号量、互斥量的不同,它可以用来等待多个事件之一、多个事件都发生

场景一:

● 任务3:等待(等事情A与事情B)

● 任务1:做好事情A

● 任务2:做好事情B

我们有一个任务3,他可以等待:A或B,A与B

A、B就是一组事件

如果任务3等待A或B,A、B只要有一个,就可以唤醒任务3

如果任务3等待A与B,只有A和B同时都做好了,任务3就被唤醒

场景二:

唤醒多个任务:

● 任务3:等待(等到事情A与事情B)

● 任务4:等待(等到事情A与事情B)

● 任务1:做事情A

● 任务2:做事情B

这时,任务3、任务4都被唤醒!

可能有很多个任务在等待事件,

他们可能等待的事件各不相同,也有可能等待的事件相同

事件发生之后,满足条件的那些任务,都会被唤醒

在之前提到的队列、信号量、互斥量这些场景中,只会唤醒一个任务

2.事件组的主要特性:

● 位操作:每个事件组是一个 32 位整数,每位代表一个独立事件高效同步:任务可以等待单个或多个事件

● 零消耗等待:任务在等待事件时不会消耗 CPU 资源

● 广播机制:一个任务可以同时通知多个等待任务

3.函数接口

osEventFlagsNew() 创建新事件组

osEventFlagsWait() 等待事件位

osEventFlagsSet() 设置事件位

osEventFlagsDelete() 删除事件组

osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr);
功能
创建一个新的事件组对象,用于任务间的事件同步。参数
attr:指向事件组属性的指针,可为 NULL(使用默认属性)
typedef struct {const char *name;    // 事件组名称(调试用)void       *cb_mem;  // 控制块内存位置(通常为NULL)uint32_t   cb_size;  // 控制块大小
} osEventFlagsAttr_t;
返回值
成功:事件组 ID失败:NULL(内存不足或参数错误)
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags,uint32_t options,uint32_t timeout);
功能
等待事件组中指定的事件位被设置。参数
ef_id:事件组 ID
flags:要等待的事件位掩码(可以看后面的实例来理解,该参数比较难理解)
options:等待选项:osFlagsWaitAny:等待任意指定事件位被设置(默认)osFlagsWaitAll:等待所有指定事件位被设置osFlagsNoClear:等待成功后不清除事件位
timeout:超时时间(tick数):
0:不等待,立即返回
osWaitForever:无限等待//那就是阻塞函数
n:等待 n 个 tick
返回值
成功:触发等待的事件位值
失败:错误代码(最高位为1):
osErrorParameter:无效参数
osErrorResource:超时或事件组不可用
osErrorISR:在中断中调用
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags);
功能
设置事件组中的指定标志位(置1),并唤醒等待这些事件的任务。
//主要应用以及理解还是需要通过下面的实例
参数
ef_id:事件组 ID
flags:要设置的事件位掩码(例如:0x01 设置的是位0,0x05 设置的是位0和位2)
返回值
成功:事件组设置后的新标志值
失败:错误代码(最高位为1):
osErrorParameter:无效参数
osErrorResource:事件组不可用
osErrorISR:在中断中调用但未启用中断API
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id);
功能
删除事件组并释放相关资源。参数
ef_id:事件组 ID
返回值
osOK:删除成功
osErrorParameter:无效参数
osErrorResource:事件组不可用

4.应用:

/* USER CODE BEGIN FunctionPrototypes */
// 事件位定义
#define BUTTON_PRESSED (1UL << 0)
#define SENSOR_READY   (1UL << 1)
#define DATA_PROCESSED (1UL << 2)
#define  event_group  myEvent01Handle 
/* USER CODE END FunctionPrototypes *//* USER CODE BEGIN Header_SensorTask */
/**
* @brief Function implementing the SensorTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_SensorTask */
void SensorTask(void *argument)
{/* USER CODE BEGIN SensorTask *//* Infinite loop */for (;;) {// 模拟传感器数据采集osDelay(500);// 设置传感器就绪事件osEventFlagsSet(event_group, SENSOR_READY);}/* USER CODE END SensorTask */
}/* USER CODE BEGIN Header_DataTask */
/**
* @brief Function implementing the DataTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_DataTask */
void DataTask(void *argument)
{/* USER CODE BEGIN DataTask *//* Infinite loop */uint32_t events;for (;;) {// 等待按钮按下或传感器就绪events = osEventFlagsWait(event_group, BUTTON_PRESSED | SENSOR_READY, osFlagsWaitAny, osWaitForever);if (events & BUTTON_PRESSED) {// 处理按钮事件printf("Button pressed!\n");}if (events & SENSOR_READY) {// 处理传感器数据printf("Sensor data received\n");// 数据处理完成后设置标志osEventFlagsSet(event_group, DATA_PROCESSED);}}/* USER CODE END DataTask */
}/* USER CODE BEGIN Header_MonitorTask */
/**
* @brief Function implementing the MonitorTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_MonitorTask */
void MonitorTask(void *argument)
{/* USER CODE BEGIN MonitorTask *//* Infinite loop */for (;;) {// 等待数据被处理osEventFlagsWait(event_group, DATA_PROCESSED, osFlagsWaitAll, osWaitForever);printf("Data processing complete\n");}/* USER CODE END MonitorTask */
}/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{osEventFlagsSet(event_group, BUTTON_PRESSED);
}
/* USER CODE END Application */
二、软件定时器

1.概念

软件定时器就是 "闹钟", 可以通过设置闹钟:

1. 设定一个一次性闹钟: 18:00 提醒我去洗衣服

2. 设定一个周期性闹钟: 6:40 提醒我起床

将 " 闹钟 " 转换为 软件定时器来讲:

1. 在未来的某个时间点, 运行某个函数的功能(一次性的闹钟)

2. 周期性的去执行某个函数的功能(周期性)

2.函数接口

1.创建一个新的软件定时器
osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type,  void *argument, const osTimerAttr_t *attr)
参数:func: 该函数指针用于指定在定时器到期时执行的回调函数, 当定时器触发,会执行该函数//typedef void (*osTimerFunc_t) (void *argument);type:定时器的类型,可选择 单次 或 循环触发/*  typedef enum {/** 一次性定时器 **/osTimerOnce   = 0,/** 重复使用的定时器 **/osTimerPeriodic  = 1} osTimerType_t;argument:传入定时器的回调函数的指针,当定时器到期,回调函数将接收到此函数,不需要NULLattr:定时器对象指针(见下面2),用于指向特定的定时器属性,比如优先级,名称等,不需要为NULL     
2.启用定时器osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)参数:timer_id:定时器ID,用于指定要启动的定时器,通常需要先使用osTimerNew函数创建定时器对象ticks: 设置的定时值  ms为单位返回值:成功返回0,失败返回错误码(错误码<0)关于错误码的定义:typedef enum {osOK       =  0,          ///定时器成功启动osError   = -1,           ///定时器发生错误,未能成功启动osErrorTimeout   = -2,    ///超时错误osErrorResource  = -3,         ///资源不可用osErrorParameter   = -4,         ///参数错误osErrorNoMemory  = -5,         ///系统内存不足:无法为操作分配或保留内存。} osStatus_t;
osStatus_t osTimerStop (osTimerId_t timer_id);
功能  :停止定时器参数  :timer_id:要停止的定时器ID返回值  :操作状态
osStatus_t osTimerDelete (osTimerId_t timer_id);
功能  :删除定时器并释放资源参数  :timer_id:要删除的定时器ID返回值  :操作状态
uint32_t osTimerIsRunning (osTimerId_t timer_id);
功能  :检查定时器是否正在运行参数  :timer_id:要检查的定时器ID返回值  :0表示未运行,非0表示正在运行

3.注意事项

1) 软件定时器的精度取决于系统节拍频率

2)定时器回调函数应尽可能简短,避免长时间阻塞

3)不要在中断服务例程(ISR)中调用定时器函数(除osTimerStart和osTimerStop外)

4)多个定时器可以共享同一个回调函数,通过参数区分

5)不能无限次创建,最多16个

4.CubeMX配置:

http://www.dtcms.com/a/319005.html

相关文章:

  • QT的拖拽功能
  • Flutter开发 Slider组件(如音量控制)
  • 小程序省市级联组件使用
  • 【课题推荐】卡尔曼滤波,创新性的算法与应用:从非线性适用性、鲁棒抗差、自适应、金融与生物新应用等方面考虑
  • 项目构想|文生图小程序
  • idea开发工具中git如何忽略编译文件build、gradle的文件?
  • C5.1:共发射极组态
  • 【Day 18】Linux-DNS解析
  • 如何理解“信号集是位掩码,每个bit代表一个信号”这句话?
  • 怎么在本地引入字体
  • 构建在 OpenTelemetry eBPF 基础之上:详解 Grafana Beyla 2.5 新特性
  • 防火墙环境下的全网服务器数据自动化备份平台搭建:基于 rsync 的完整实施指南
  • CentOS 7 下通过 Anaconda3 运行llm大模型、deepseek大模型的完整指南
  • Express框架
  • 【JavaEE】(9) JVM
  • ElementUI之表格
  • 企业家 IP 发展态势剖析|创客匠人
  • 计算机网络1-5:计算机网络的性能指标
  • 【python 数据加密AES-GCM + 时间戳签名方案(带时间校验)】
  • vue3 el-select 加载触发
  • tcpdump问题记录
  • 软件运行时 ffmpeg.dll 丢失怎么办?从原因排查到完美修复的完整方案
  • 【Kafka系列】第二篇| Kafka 的核心概念、架构设计、底层原理
  • 什么是 TcpCommunicationSpi
  • HTML已死,HTML万岁——重新思考DOM的底层设计理念
  • 【音视频】WebRTC C++ native 编译
  • SpringAI动态调整大模型平台
  • 数据结构----栈和队列认识
  • Spring IoC 容器核心流程(面试必懂)
  • SpringMvc的原理深度剖析及源码解读