FreeRTOS当中的Mail Queue使用教程(CMSIS_v1)

为什么要使用Mail Queue

以蜂鸣器举例:为什么要用邮箱,而不是直接 BeepOn()?

  1. 避免阻塞调用者

    蜂鸣器响需要时间,如果每个调用方自己去响蜂鸣器,它们都会被这个延时卡住。现在改成邮箱后,调用方发完请求就能继续干别的。

  2. 统一串行处理多个请求

    如果多个任务同时想蜂鸣器发声,邮箱会把这些请求排队,蜂鸣器任务按顺序处理,不会互相打架。

  3. 线程安全、职责清晰

    硬件操作只放在一个任务里做,其他任务只负责发消息,结构更稳,后续好维护。

让蜂鸣器请求变成一个异步队列,避免阻塞其他任务,并把硬件控制集中到一个地方。

什么是Mail Queue

FreeRTOS当中传统的Mailbox

对队列(Queue)的一种特殊用法

Mailbox = Queue(Queue length = 1)

特点:

只能存 1 条消息

新消息会覆盖旧消息

CMSIS_v1当中的Mail Queue

多消息缓存队列,带内存管理的消息传递机制

CMSIS Mail Queue = Queue + Memory Pool

内部结构:

内存池 → 存放多个 BeepMsg_t

↓

队列 → 存放指针(指向这些消息)

接口函数(CMSIS_v1)

以下我均以蜂鸣器使用举例子

初始化接口

osMailQDef --- 定义邮箱

c 复制代码
// 定义蜂鸣器消息队列,队列长度为10,消息类型为BeepMsg_t
osMailQDef(BeepMail, BEEP_MSG_QUENE_SIZE, BeepMsg_t);

osMailCreate --- 创建邮箱

c 复制代码
  // 创建邮箱队列,供外部调用接口使用
  BeepMail = osMailCreate(osMailQ(BeepMail), NULL);

外部调用接口

osMailAlloc --- 申请内存

c 复制代码
  // 从邮箱申请一个消息块,失败则直接丢弃本次请求
  p = osMailAlloc(BeepMail, 0);

osMailPut --- 消息投递

c 复制代码
// 将消息投递给蜂鸣器任务,由任务统一控制 IO 输出
osMailPut(BeepMail, p);

Task内部处理接口

osMailGet --- 阻塞等待

c 复制代码
// 阻塞等待蜂鸣器控制消息
evt = osMailGet(BeepMail, osWaitForever);

osMailFree --- 释放内存

c 复制代码
	// 释放消息块
  osMailFree(BeepMail, p); 

整体工程---beep.c

c 复制代码
osThreadId BeepTaskHandle;
osMailQId BeepMail;
// 定义蜂鸣器消息队列,队列长度为10,消息类型为BeepMsg_t
osMailQDef(BeepMail, BEEP_MSG_QUENE_SIZE, BeepMsg_t);

// 外部调用蜂鸣器
void Beep(uint8_t sound, uint8_t time)
{
  BeepMsg_t *p;
  // 从邮箱申请一个消息块,失败则直接丢弃本次请求
  p = osMailAlloc(BeepMail, 0);
  if (p != NULL)
  {
    p->sound = sound;
    p->time = time;
    // 将消息投递给蜂鸣器任务,由任务统一控制 IO 输出
    osMailPut(BeepMail, p);
  }
}

// 蜂鸣器任务入口
static void BeepTaskEntry(void const *argument)
{
  osEvent evt;
  BeepMsg_t *p; // 包含sound和time
  /* Infinite loop */
  // 任务启动时先关闭蜂鸣器,避免上电瞬间误响
  BeepOff();
  for (;;)
  {
    // 阻塞等待蜂鸣器控制消息
    evt = osMailGet(BeepMail, osWaitForever);
    if (evt.status == osEventMail)
    {
      p = evt.value.p;
      // 打开对应音色,保持指定时间后关闭
      BeepOn(p->sound);
      osDelay(p->time);

      osMailFree(BeepMail, p); // 释放消息块
      BeepOff();
    }
  }
}

// 定义蜂鸣器任务
osThreadDef(BeepTask, BeepTaskEntry, osPriorityAboveNormal, 0, 128);

// 创建蜂鸣器任务及其邮箱队列
void BeepTaskInit(void)
{
  // 创建邮箱队列,供外部调用接口使用
  BeepMail = osMailCreate(osMailQ(BeepMail), NULL);

  // 创建蜂鸣器任务
  BeepTaskHandle = osThreadCreate(osThread(BeepTask), NULL);
}
相关推荐
LCG米4 小时前
STM32串口接收卡死根因排查:ORE溢出标志陷阱、错误标志清除顺序与中断恢复实测
stm32·单片机·嵌入式硬件·串口·嵌入式
创界工坊工作室5 小时前
38-基于单片机的老人健康监测系统
单片机·嵌入式硬件·51单片机·proteus
三佛科技-134163842127 小时前
20W~200W副边反馈SSR隔离方案HN1562+碳化硅MOS(含光耦817,431)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
_Ningye11 小时前
STM32 — 11.5 硬件SPI读写W25Q64
stm32·单片机·嵌入式硬件
inrichtt11 小时前
第九课时:STM32 SPI实战:按键消抖与FLASH断电保护
stm32·单片机·嵌入式硬件
优信电子12 小时前
STM32 驱动 SHT35 温湿度传感器:从 I²C 通信到 CRC 校验的完整实战
单片机·嵌入式
艾iYYY13 小时前
【无标题】
linux·开发语言·网络·操作系统
女神下凡14 小时前
芯参谋(61):PMSM永磁同步电机驱动电路设计指南
arm开发·单片机·嵌入式硬件·硬件工程·设计规范
HRTOS14 小时前
HRTOS 4.0 中断嵌套注意事项:为什么不建议在嵌套中断中调用唤醒任务 API?
单片机·嵌入式硬件·51单片机
新晨单片机设计15 小时前
S023E-基于STM32单片机WIFI智能插座(温度、定时)【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·wifi智能电表