FreeRTOS的任务间通信方式

FreeRTOS的任务间通信方式提供了多种机制来帮助任务之间交换信息、同步执行和共享资源。以下是几种常见的通信方式及其典型应用场景:

1. 信号量(Semaphores)

应用场景:
资源互斥访问:例如,假设多个任务需要访问一个共享的ADC(模拟数字转换器),可以使用互斥信号量来确保一次只有一个任务可以访问ADC。
事件通知:一个任务完成某项工作后,可以通过信号量通知其他任务,如数据采集完成。

1.1 创建信号量:

#include "freertos/semphr.h"

SemaphoreHandle_t xSemaphore;

void vSemaphoreCreate()
{
    xSemaphore = xSemaphoreCreateBinary();
    configASSERT(xSemaphore);
}

1.2 使用信号量:

void vSemaphoreTake()
{
    if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE)
    {
        // 信号量获取成功,执行临界区代码
        // ...
        xSemaphoreGive(xSemaphore);
    }
}

2. 消息队列(Message Queues)

应用场景:
异步数据传输:一个任务采集传感器数据,并将其放入消息队列,另一个任务负责处理这些数据,从而实现异步通信。
命令响应:一个任务通过消息队列发送命令给另一个任务,接收任务处理命令后,再通过队列返回响应。

2.1 创建消息队列

#include "freertos/queue.h"

QueueHandle_t xQueue;

void vQueueCreate()
{
    xQueue = xQueueCreate(10, sizeof(uint32_t));
    configASSERT(xQueue);
}

2.2 发送消息队里

void vQueueSend()
{
    uint32_t ulValue = 123;
    xQueueSend(xQueue, &ulValue, portMAX_DELAY);
}

2.3 接收消息队列

void vQueueReceive()
{
    uint32_t ulReceivedValue;
    if (xQueueReceive(xQueue, &ulReceivedValue, portMAX_DELAY) == pdTRUE)
    {
        // 消息接收成功
    }
}

3. 事件组(Event Groups)

应用场景:
多事件组合:当一个任务需要等待多个事件中的任何一个或几个事件发生时,可以使用事件组。例如,一个任务可能需要等待网络连接建立或外部存储器准备好,可以使用事件组来同时监听这两种事件。

3.1 创建事件组

#include "freertos/event_groups.h"

EventGroupHandle_t xEventGroup;

void vEventGroupCreate()
{
    xEventGroup = xEventGroupCreate();
    configASSERT(xEventGroup);
}

3.2 设置事件

void vEventGroupSetBits()
{
    xEventGroupSetBits(xEventGroup, 1 << 0);
}

3.3 等待事件

void vEventGroupWaitBits()
{
    uint32_t ulBits;
    ulBits = xEventGroupWaitBits(xEventGroup, 1 << 0, pdFALSE, pdFALSE, portMAX_DELAY);
    if (ulBits & (1 << 0))
    {
        // 事件已发生
    }
}

4. 任务通知(Task Notifications)

应用场景:
轻量级通信:当一个任务需要简单地通知另一个任务某些事件已经发生时,可以使用任务通知,如任务完成、定时器到期或外部事件触发。

4.1 发送通知

void taskF(void *pvParameters)
{
    while(1)
    {
        xTaskNotify(taskGHandle, 0, eIncrement);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

4.2 接收通知

void taskG(void *pvParameters)
{
    while(1)
    {
        uint32_t ulNotificationValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        if(ulNotificationValue > 0)
        {
            // Notification received
            // ...
        }
    }
}

5. 互斥量(Mutexes)和递归互斥量(Recursive Mutexes)

应用场景:
保护共享资源:当多个任务需要访问共享内存或硬件资源时,可以使用互斥量来保证资源的独占访问。递归互斥量允许一个任务多次获取同一互斥量,这在任务内部需要多次访问共享资源时非常有用。

5.1 创建互斥量

#include "semphr.h"

SemaphoreHandle_t xMutex = NULL;

void createMutex(void)
{
    xMutex = xSemaphoreCreateMutex();
    configASSERT(xMutex != NULL);
}

5.2 使用互斥量

void taskA(void *pvParameters)
{
    while(1)
    {
        xSemaphoreTake(xMutex, portMAX_DELAY);
        // Critical section
        // Access shared resource here
        // ...
        xSemaphoreGive(xMutex);
    }
}

5.3 创建递归互斥量

SemaphoreHandle_t xRecursiveMutex = NULL;

void createRecursiveMutex(void)
{
    xRecursiveMutex = xSemaphoreCreateRecursiveMutex();
    configASSERT(xRecursiveMutex != NULL);
}

5.4 使用递归互斥量

void taskB(void *pvParameters)
{
    while(1)
    {
        xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY);
        // Critical section 1
        // Access shared resource here
        // ...

        // If this task needs to re-enter the critical section:
        xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY);
        // Critical section 2
        // Access shared resource again
        // ...

        // Release lock twice because it was taken twice
        xSemaphoreGiveRecursive(xRecursiveMutex);
        xSemaphoreGiveRecursive(xRecursiveMutex);
    }
}

6. 软件定时器(Software Timers)

虽然软件定时器本身不是直接的通信机制,但它们可以间接用于任务间的通信。

应用场景:
周期性任务执行:一个任务可以配置一个软件定时器,当定时器到期时,它会自动重新加载并执行回调函数,这可以用于定期执行任务,如数据上报、周期性维护等。
每种通信方式都有其优缺点和最适合的场景,选择合适的方法可以提高系统的效率和可靠性。在实际应用中,可能需要根据具体需求组合使用多种通信方式。例如,一个复杂的系统可能同时使用消息队列来传输数据,使用信号量来同步资源访问,以及使用事件组来处理多事件组合的情况。

6.1 定义软件定时器回调函数

static void prvTimerCallback(TimerHandle_t pxTimer)
{
    // This function will be called every 1 second (as specified in the timer creation).
    // You can put your code here that should run periodically.

    // Example: Print something to the console
    printf("Timer expired!\n");

    // Optionally, you can restart the timer from here if it's a one-shot timer.
    // xTimerReset(pxTimer, 0);
}

6.2 创建和配置软件定时器

#include "progtypes.h"
#include "timers.h"

static void prvTimerCallback(TimerHandle_t pxTimer);

void createTimer(void)
{
    TimerHandle_t xTimer = xTimerCreate(
        "DemoTimer",      /* Just a text name, not used by the RTOS kernel. */
        pdMS_TO_TICKS(1000), /* The rate at which the timer ticks. */
        pdFALSE,          /* The timer is not auto-reload (one-shot). */
        (void *)0,        /* The ID of the timer - not needed. */
        prvTimerCallback);/* The function to be called when the timer expires. */

    if(xTimer != NULL)
    {
        // Start the timer.
        if(xTimerStart(xTimer, 0) != pdPASS)
        {
            // Failed to start the timer.
        }
    }
}

6.3 创建和启动软件定时器

void main_task(void *pvParameters)
{
    // Create and start the timer.
    createTimer();

    // Your other tasks or code...
}

相关推荐

  1. FreeRTOS任务通信方式

    2024-07-10 04:20:03       43 阅读
  2. FreeRTOS任务通知

    2024-07-10 04:20:03       62 阅读
  3. 进程通信方式

    2024-07-10 04:20:03       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 04:20:03       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 04:20:03       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 04:20:03       90 阅读
  4. Python语言-面向对象

    2024-07-10 04:20:03       98 阅读

热门阅读

  1. 一个简单的spring+kafka生产者

    2024-07-10 04:20:03       22 阅读
  2. gradle安卓开发软件简介

    2024-07-10 04:20:03       27 阅读
  3. UE5.2 AI实时抠像(无需绿幕) + OBS推流直播 全流程

    2024-07-10 04:20:03       31 阅读
  4. 微软Edge浏览器全解析

    2024-07-10 04:20:03       31 阅读
  5. toString方法介绍

    2024-07-10 04:20:03       23 阅读
  6. LLM大语言模型知识点整理

    2024-07-10 04:20:03       24 阅读
  7. 使用Boost.Asio编写TCP通信程序框架(一)

    2024-07-10 04:20:03       42 阅读
  8. 导师好奇我为什么开发后端模版只花了一小时!

    2024-07-10 04:20:03       28 阅读