三种 FreeRTOS 通信方式

在嵌入式系统中,任务之间的通信是实现并发、同步和资源共享的关键。FreeRTOS 提供了多种通信机制,以满足不同的应用场景和性能要求。本文将重点介绍三种常用的通信方式:消息队列(Queue)邮箱(Semaphore)和任务通知(Task Notification),并通过代码示例分析其适用场景和使用方法。

一、消息队列(Queue)

概述

消息队列用于在任务之间传递消息或数据。它可以存储多个数据项,常用于任务与任务、中断与任务之间的通信,适合需要“带数据”传递的情况。

使用场景

  • 按钮中断向任务传递事件编号
  • 任务间传输传感器值、指令等

示例代码

// 定义一个整型队列
QueueHandle_t my_queue;

// 初始化队列,容量为10,每个元素是int类型
my_queue = xQueueCreate(10, sizeof(int));

// 消费者任务:从队列接收数据
void consumer_task(void *arg) {
    int received_data;
    while (1) {
        if (xQueueReceive(my_queue, &received_data, portMAX_DELAY)) {
            printf("Received value: %d\n", received_data);
            // 在此处理数据
        }
    }
}

// 中断服务程序:向队列发送数据
void EXTI_IRQHandler(void) {
    int data = 42;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(my_queue, &data, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

特点

  • ✅ 可传递任意数据类型
  • ✅ 可用于任务与中断间通信
  • ❌ 内存开销略大
  • ❌ 比任务通知慢一些

二、邮箱(Semaphore)

概述

邮箱本质上是一种二值信号量,主要用于任务同步,不承载数据。它常被用作“任务启动信号”或“事件通知”,而非传输数据。

使用场景

  • 通知任务“有事情要做了”,但不传递数据
  • 中断触发任务启动

示例代码

// 创建一个二值信号量
SemaphoreHandle_t binary_semaphore;

// 初始化
binary_semaphore = xSemaphoreCreateBinary();

// 任务:等待信号量
void led_task(void *arg) {
    while (1) {
        if (xSemaphoreTake(binary_semaphore, portMAX_DELAY)) {
            printf("Button pressed, toggle LED.\n");
            // 翻转 LED 状态
        }
    }
}

// 中断服务程序:发送信号量
void button_isr(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(binary_semaphore, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

特点

  • ✅ 简单高效
  • ✅ 适合事件同步(不含数据)
  • ❌ 无法携带数据
  • ✅ 支持中断触发

三、任务通知(Task Notification)

概述

任务通知是 FreeRTOS 中一种轻量级的任务间通信机制,每个任务有一个 32 位的“通知值”,可以在任务之间或中断中更新和读取。它支持传递一个整数值,效率高,是性能最优的通信方式。

使用场景

  • 单一任务之间快速通信
  • 按钮等中断触发简单事件通知
  • 替代低开销信号量和队列

示例代码

// 假设我们已经获得任务句柄 task_handle

// 任务:等待通知
void notify_task(void *arg) {
    uint32_t value;
    while (1) {
        // 阻塞等待通知,并获取通知值
        if (xTaskNotifyWait(0, 0, &value, portMAX_DELAY)) {
            printf("Received notify value: %lu\n", value);
            // 响应事件
        }
    }
}

// 中断服务程序:发送通知
void notify_isr(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xTaskNotifyFromISR(task_handle, 1, eSetValueWithOverwrite, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

特点

  • ✅ 传输单个整数值
  • ✅ 效率最高、开销最小
  • ❌ 每个任务只能有一个通知槽位
  • ✅ 适合中断触发事件通知

四、总结对比

特性消息队列邮箱(信号量)任务通知
是否传递数据✅ 是(任意类型)❌ 否(仅通知)✅ 是(单个整数)
是否支持中断调用✅ 是✅ 是✅ 是
通信效率最高
资源开销较大(占用内存)最小(无堆内存)
多对一通信支持✅ 支持(多个任务写入)✅ 支持❌ 单槽位,需注意覆盖
典型使用场景传输数据、任务调度同步任务、事件触发快速事件触发、ISR通信
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇