FreeRTOS 通知学习

FreeRTOS 通知学习

概述

FreeRTOS 通知提供了一种机制,使得任务之间可以发送和接收简单的数据项(通常是整数)。通知可以作为一种轻量级的消息传递或任务间同步的方式。它们特别适用于在任务之间发送简单信号或少量数据,而无需使用队列或信号量的开销。

通知类型

1. 二值信号量

二值信号量用于指示事件的发生。一个任务可以发送通知,这会设置一个标志,另一个任务可以接收通知,这会清除该标志。

实现
void Send_Task(void *pvParameters)
{
    while (1)
    {
        if (Key_Scan(GPIOA, GPIO_PIN_10) == 1)
        {
            BaseType_t xReturn = xTaskNotifyGive(Receive1_Task_Handle); // 发送通知
            if (xReturn == pdPASS)
            {
                printf("Send_Task Notify to Receive1_Task\r\n");
            }
        }
        if (Key_Scan(GPIOB, GPIO_PIN_4) == 1)
        {
            BaseType_t xReturn = xTaskNotifyGive(Receive2_Task_Handle); // 发送通知
            if (xReturn == pdPASS)
            {
                printf("Send_Task Notify to Receive2_Task\r\n");
            }
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 延时100毫秒
    }
}

void Receive1_Task(void *pvParameters)
{
    while (1)
    {
        printf("Receive1_Task Waiting for Notify...\r\n");
        // 等待通知,清除通知值
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // 等待通知
        printf("Receive1_Task Notify\r\n");
    }
}

void Receive2_Task(void *pvParameters)
{
    while (1)
    {
        printf("Receive2_Task Waiting for Notify...\r\n");                   // 示例通知值
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);                             // 等待通知
        printf("Receive2_Task Notify\r\n");
    }
}
实验结果
FreeRTOS STM32F1xx Example
Receive1_Task Waiting for Notify...
Send_Task Notify to Receive2_Task
Receive2_Task Notify
Receive2_Task Waiting for Notify...
Send_Task Notify to Receive2_Task
Receive2_Task Notify
Receive2_Task Waiting for Notify...
Send_Task Notify to Receive1_Task
Receive1_Task Notify
Receive1_Task Waiting for Notify...
Send_Task Notify to Receive2_Task
Receive2_Task Notify
Receive2_Task Waiting for Notify...
Send_Task Notify to Receive1_Task
Receive1_Task Notify
Receive1_Task Waiting for Notify...

2. 计数信号量

计数信号量允许一个任务发送多个通知,另一个任务可以接收这些通知,每次接收时减少计数。

实现
void GIVE_Task(void *pvParameters)
{
    while (1)
    {
        if (Key_Scan(GPIOA, GPIO_PIN_10) == 1)
        {
            BaseType_t xReturn = xTaskNotifyGive(TAKE_Task_Handle); // 发送通知
            if (xReturn == pdPASS)
            {
                printf("GIVE_Task Notify to TAKE_Task\r\n");
            }
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 延时100毫秒
    }
}

void TAKE_Task(void *pvParameters)
{
    while (1)
    {
        uint32_t r_num = ulTaskNotifyTake(pdFALSE, 0); // 等待通知
        printf("TAKE_Task Notify to Receive2_Task, current counting is %d\r\n", r_num);
        vTaskDelay(pdMS_TO_TICKS(100)); // 延时100毫秒
    }
}
实验结果
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
TAKE_Task Notify to Receive2_Task, current counting is 8
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
TAKE_Task Notify to Receive2_Task, current counting is 15
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
GIVE_Task Notify to TAKE_Task
TAKE_Task Notify to Receive2_Task, current counting is 22
TAKE_Task Notify to Receive2_Task, current counting is 21
TAKE_Task Notify to Receive2_Task, current counting is 20
TAKE_Task Notify to Receive2_Task, current counting is 19
TAKE_Task Notify to Receive2_Task, current counting is 18
TAKE_Task Notify to Receive2_Task, current counting is 17
TAKE_Task Notify to Receive2_Task, current counting is 16
TAKE_Task Notify to Receive2_Task, current counting is 15
TAKE_Task Notify to Receive2_Task, current counting is 14
TAKE_Task Notify to Receive2_Task, current counting is 13
TAKE_Task Notify to Receive2_Task, current counting is 12
TAKE_Task Notify to Receive2_Task, current counting is 11
TAKE_Task Notify to Receive2_Task, current counting is 10
TAKE_Task Notify to Receive2_Task, current counting is 9
TAKE_Task Notify to Receive2_Task, current counting is 8
TAKE_Task Notify to Receive2_Task, current counting is 7
TAKE_Task Notify to Receive2_Task, current counting is 6
TAKE_Task Notify to Receive2_Task, current counting is 5
TAKE_Task Notify to Receive2_Task, current counting is 4
TAKE_Task Notify to Receive2_Task, current counting is 3
TAKE_Task Notify to Receive2_Task, current counting is 2
TAKE_Task Notify to Receive2_Task, current counting is 1
TAKE_Task Notify to Receive2_Task, current counting is 0

3. 数值通知

数值通知允许一个任务向另一个任务发送一个整数值。接收任务可以检索这个值。

实现
void Send_Task(void *pvParameters)
{
    while (1)
    {
        if (Key_Scan(GPIOA, GPIO_PIN_10) == 1)
        {
            BaseType_t xReturn = xTaskNotify(Receive1_Task_Handle, 11111, eSetValueWithOverwrite); // 发送通知
            if (xReturn == pdPASS)
            {
                printf("Send_Task Notify to Receive1_Task\r\n");
            }
        }
        if (Key_Scan(GPIOB, GPIO_PIN_4) == 1)
        {
            BaseType_t xReturn = xTaskNotify(Receive2_Task_Handle, 22222, eSetValueWithOverwrite); // 发送通知
            if (xReturn == pdPASS)
            {
                printf("Send_Task Notify to Receive2_Task\r\n");
            }
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 延时100毫秒
    }
}

void Receive1_Task(void *pvParameters)
{
    while (1)
    {
        uint32_t ulValue = 0;   
        printf("Receive1_Task Waiting for Notify...\r\n");
        // 等待通知,清除通知值
        BaseType_t xReturn = xTaskNotifyWait(0, 0, &ulValue, portMAX_DELAY); // 等待通知
        printf("Receive1_Task Notify: %d\r\n", ulValue);
    }
}

void Receive2_Task(void *pvParameters)
{
    while (1)
    {
        uint32_t ulValue = 0;
        printf("Receive2_Task Waiting for Notify...\r\n");                   // 示例通知值
        BaseType_t xReturn = xTaskNotifyWait(0, 0, &ulValue, portMAX_DELAY); // 等待通知
        printf("Receive2_Task Notify: %d\r\n", ulValue);
    }
}
实验结果
Send_Task Notify to Receive1_Task
Receive1_Task Notify: 11111
Receive1_Task Waiting for Notify...
Send_Task Notify to Receive1_Task
Receive1_Task Notify: 11111
Receive1_Task Waiting for Notify...
Send_Task Notify to Receive2_Task
Receive2_Task Notify: 22222
Receive2_Task Waiting for Notify...
Send_Task Notify to Receive1_Task
Receive2_Task Notify: 22222
Receive2_Task Waiting for Notify...
Send_Task Notify to Receive1_Task
Receive1_Task Notify: 11111
Receive1_Task Waiting for Notify...
Send_Task Notify to Receive1_Task
Receive1_Task Notify: 11111
Receive1_Task Waiting for Notify...

4. 事件组

事件组允许多个任务同时等待多个事件。每个事件由一个32位值中的一个位表示。

实现
void Key_Task(void *pvParameters)
{
    while (1)
    {
        if (Key_Scan(GPIOA, GPIO_PIN_10) == 1)
        {
            xTaskNotify(Event_Task_Handle, KEY1_EVENT, eSetBits); // 通知Event_Task
            printf("Key1_Task Notify to Event_Task\r\n");
        }
        if (Key_Scan(GPIOB, GPIO_PIN_4) == 1)
        {
            xTaskNotify(Event_Task_Handle, KEY2_EVENT, eSetBits); // 通知Event_Task
            printf("Key2_Task Notify to Event_Task\r\n");
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 延时100毫秒
    }
}

void Event_Task(void *pvParameters)
{
    uint32_t last_notifiedValue = 0; // 上次通知的值
    while (1)
    {
        uint32_t notifiedValue;
        BaseType_t x_Return = xTaskNotifyWait(0, 0xffffffff, &notifiedValue, portMAX_DELAY); // 等待通知
        if (x_Return == pdTRUE)
        {
            last_notifiedValue |= notifiedValue; // 将当前通知值与上次通知值进行或运算
            if (last_notifiedValue == (KEY1_EVENT | KEY2_EVENT))
            {
                // 如果当前通知值与上次通知值相同,或者两个事件都发生了,则处理事件
                printf("All events received---------\r\n");
                last_notifiedValue = 0; // 重置上次通知的值
            }
        }
    }
}
实验结果
FreeRTOS STM32F1xx Example
Key1_Task Notify to Event_Task
Key2_Task Notify to Event_Task
All events received---------
Key1_Task Notify to Event_Task
Key2_Task Notify to Event_Task
All events received---------
Key1_Task Notify to Event_Task
Key2_Task Notify to Event_Task
All events received---------
Key1_Task Notify to Event_Task
Key2_Task Notify to Event_Task
All events received---------

关键函数

xTaskNotifyGive(TaskHandle_t xTaskToNotify)

  • 用途: 向任务发送通知,增加任务的通知计数。
  • 参数:
    • xTaskToNotify: 要通知的任务的句柄。

ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait)

  • 用途: 等待来自其他任务的通知。
  • 参数:
    • xClearCountOnExit: 如果为 pdTRUE,则任务的通知计数会被清零。
    • xTicksToWait: 最大等待时间。

xTaskNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction)

  • 用途: 向任务发送通知,可选地设置或添加一个值。
  • 参数:
    • xTaskToNotify: 要通知的任务的句柄。
    • ulValue: 要发送的值。
    • eAction: 执行的动作 (eSetValueWithOverwrite, eSetValueWithoutOverwrite, eIncrement, eNoAction)。

xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait)

  • 用途: 等待来自其他任务的通知,可选地清除任务的通知值中的位。
  • 参数:
    • ulBitsToClearOnEntry: 进入时要清除的位。
    • ulBitsToClearOnExit: 退出时要清除的位。
    • pulNotificationValue: 存储接收到的通知值的指针。
    • xTicksToWait: 最大等待时间。

最佳实践

  1. 使用通知进行简单信号传递: 通知最适合用于任务间的简单信号传递。对于更复杂的数据交换,考虑使用队列或信号量。
  2. 避免无限期阻塞: 总是为 ulTaskNotifyTakexTaskNotifyWait 指定超时时间,以避免无限期阻塞。
  3. 检查返回值: 总是检查通知函数的返回值,以便适当地处理错误。
  4. 文档化通知使用: 清晰地记录通知的目的和使用方式,以提高代码的可读性和可维护性。

结论

FreeRTOS 通知提供了一种轻量级且高效的机制,用于任务间通信。通过理解不同类型的通知及其使用场景,你可以有效地使用它们来同步和通信任务之间的活动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值