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); } ```

相关推荐
三佛科技-134163842123 小时前
FT32F103系列与APM32F103,STM32F103之间的对比,能否替换?
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
李永奉4 小时前
杰理可视化SDK开发-蓝牙的可发现可连接和回连
单片机·嵌入式硬件·物联网·语音识别
振浩微433射频芯片6 小时前
标签界的“千里眼”:VRT5312,150cm超远读写距离,重新定义RFID新可能!
科技·单片机·嵌入式硬件·物联网
染予7 小时前
定时器时钟源介绍
单片机·嵌入式硬件
时空自由民.7 小时前
ESP32编译固件内存信息解读
单片机·性能优化
LCMICRO-133108477468 小时前
长芯微LPS6288完全P2P替代TPS61288,是一款具有 15A 开关电流的全集成同步升压转换器
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·同步升压转换器
FreakStudio8 小时前
MicroPython对接大模型:uopenai + 火山方舟实现文字聊天和图片理解
python·单片机·ai·嵌入式·面向对象·电子diy
一路往蓝-Anbo9 小时前
第四章:STM32 CAN基础收发编程
stm32·单片机·嵌入式硬件
椰羊~王小美10 小时前
嵌入式 和 单片机
java·单片机·嵌入式硬件