freertos通讯-通知

本文深入探讨了FreeRTOS中通知机制的工作原理,包括通知获取与释放的四种版本,以及其在实时性和内存效率上的优势。文章指出,通过利用任务自身属性,通知机制能够显著提升系统性能,作者实测性能提升可达40%。

通知是什么?其实我们之前就见过,它就在任务结构体中.再来回顾下

    #if( configUSE_TASK_NOTIFICATIONS == 1 )
        volatile uint32_t ulNotifiedValue;
        volatile uint8_t ucNotifyState;
    #endif

就是这么一个东西,ulNotifiedValue表示要传递的数值.ucNotifyState表示状态

 

1.通知获取简单版本

1.如果通知值是0,更改到等待通知状态.把当前任务放入延时列表,进行上下文切换

2.获取通知数值,根据标志清空或者数值减1,更改到任务没有等待通知状态

 

2.通知释放简单版本

#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )

1.根据标志位设置通知数值

2.如果有任务在等待通知,则把任务从等待列表移除,并且加入就绪列表,根据优先级进行切换

 

3.通知获取普通版

1.任务通知状态不是通知接收,则设置为等待接收状态,然后把当前任务加入等待列表

2.获取通知数值,设置为非等待状态.

 

4.通知释放普通版

#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )

1.设置通知为通知接收状态,根据标志设置通知数值

2.源状态是等待通知状态,则从等待列表移植通知任务并加入就绪列表,根据优先级切换上下文

 

5.思考与总结

通知利用了任务自身的属性,实时效率和内存使用都有很大提高.freertos作者自测有百分之40.

但简单版本的通知只能用于一个任务

 

FreeRTOS 是一个开源的实时操作系统内核,在 FreeRTOS 中,多线程(更准确地说是多任务)之间的通讯方式主要有以下几种: ### 队列(Queue) 队列是 FreeRTOS 中最常用的任务间通讯方式之一。它可以实现任务之间的数据传递,支持不同任务向队列发送和接收数据。队列可以存储多个数据项,这些数据项可以是基本数据类型,也可以是结构体等复杂数据类型。例如,一个任务可以将传感器采集到的数据发送到队列中,另一个任务则可以从队列中读取这些数据进行处理。 以下是一个简单的使用队列进行任务间通讯的示例代码: ```c #include "FreeRTOS.h" #include "task.h" #include "queue.h" // 定义队列句柄 QueueHandle_t xQueue; // 发送任务 void vSenderTask( void *pvParameters ) { int value = 0; for( ;; ) { // 向队列发送数据 xQueueSend( xQueue, &value, portMAX_DELAY ); value++; vTaskDelay( pdMS_TO_TICKS( 1000 ) ); } } // 接收任务 void vReceiverTask( void *pvParameters ) { int receivedValue; for( ;; ) { // 从队列接收数据 if( xQueueReceive( xQueue, &receivedValue, portMAX_DELAY ) == pdPASS ) { // 处理接收到的数据 } } } void main( void ) { // 创建队列 xQueue = xQueueCreate( 5, sizeof( int ) ); if( xQueue != NULL ) { // 创建任务 xTaskCreate( vSenderTask, "Sender", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); xTaskCreate( vReceiverTask, "Receiver", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); // 启动调度器 vTaskStartScheduler(); } for( ;; ); } ``` ### 信号量(Semaphore) 信号量主要用于任务之间的同步和资源管理。信号量可以看作是一个计数器,任务可以通过获取和释放信号量来控制对共享资源的访问。常见的信号量类型有二进制信号量和计数信号量。二进制信号量通常用于任务之间的同步,而计数信号量则可以用于管理多个相同资源的访问。 以下是一个使用二进制信号量进行任务同步的示例代码: ```c #include "FreeRTOS.h" #include "task.h" #include "semphr.h" // 定义信号量句柄 SemaphoreHandle_t xSemaphore; // 任务 1 void vTask1( void *pvParameters ) { for( ;; ) { // 等待信号量 xSemaphoreTake( xSemaphore, portMAX_DELAY ); // 执行任务 vTaskDelay( pdMS_TO_TICKS( 1000 ) ); // 释放信号量 xSemaphoreGive( xSemaphore ); } } // 任务 2 void vTask2( void *pvParameters ) { for( ;; ) { // 等待信号量 xSemaphoreTake( xSemaphore, portMAX_DELAY ); // 执行任务 vTaskDelay( pdMS_TO_TICKS( 1000 ) ); // 释放信号量 xSemaphoreGive( xSemaphore ); } } void main( void ) { // 创建二进制信号量 xSemaphore = xSemaphoreCreateBinary(); if( xSemaphore != NULL ) { // 释放信号量,使其初始值为 1 xSemaphoreGive( xSemaphore ); // 创建任务 xTaskCreate( vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); xTaskCreate( vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); // 启动调度器 vTaskStartScheduler(); } for( ;; ); } ``` ### 事件组(Event Group) 事件组用于任务之间的事件同步。一个事件组可以包含多个事件位,每个事件位可以被设置或清除。任务可以等待一个或多个事件位被设置,当满足条件时,任务将被唤醒继续执行。事件组可以实现复杂的任务同步逻辑。 以下是一个使用事件组进行任务同步的示例代码: ```c #include "FreeRTOS.h" #include "task.h" #include "event_groups.h" // 定义事件组句柄 EventGroupHandle_t xEventGroup; // 任务 1 void vTask1( void *pvParameters ) { for( ;; ) { // 设置事件位 xEventGroupSetBits( xEventGroup, 0x01 ); vTaskDelay( pdMS_TO_TICKS( 1000 ) ); } } // 任务 2 void vTask2( void *pvParameters ) { EventBits_t uxBits; for( ;; ) { // 等待事件位被设置 uxBits = xEventGroupWaitBits( xEventGroup, 0x01, pdTRUE, pdTRUE, portMAX_DELAY ); if( ( uxBits & 0x01 ) != 0 ) { // 处理事件 } } } void main( void ) { // 创建事件组 xEventGroup = xEventGroupCreate(); if( xEventGroup != NULL ) { // 创建任务 xTaskCreate( vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); xTaskCreate( vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); // 启动调度器 vTaskStartScheduler(); } for( ;; ); } ``` ### 互斥量(Mutex) 互斥量主要用于保护共享资源,防止多个任务同时访问同一资源而导致数据不一致的问题。互斥量与二进制信号量类似,但它具有优先级继承机制,当一个低优先级任务持有互斥量时,高优先级任务在尝试获取互斥量时,低优先级任务的优先级会被临时提升,以避免优先级反转问题。 以下是一个使用互斥量保护共享资源的示例代码: ```c #include "FreeRTOS.h" #include "task.h" #include "semphr.h" // 定义互斥量句柄 SemaphoreHandle_t xMutex; // 共享资源 int sharedResource = 0; // 任务 1 void vTask1( void *pvParameters ) { for( ;; ) { // 获取互斥量 xSemaphoreTake( xMutex, portMAX_DELAY ); // 访问共享资源 sharedResource++; // 释放互斥量 xSemaphoreGive( xMutex ); vTaskDelay( pdMS_TO_TICKS( 1000 ) ); } } // 任务 2 void vTask2( void *pvParameters ) { for( ;; ) { // 获取互斥量 xSemaphoreTake( xMutex, portMAX_DELAY ); // 访问共享资源 sharedResource--; // 释放互斥量 xSemaphoreGive( xMutex ); vTaskDelay( pdMS_TO_TICKS( 1000 ) ); } } void main( void ) { // 创建互斥量 xMutex = xSemaphoreCreateMutex(); if( xMutex != NULL ) { // 创建任务 xTaskCreate( vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); xTaskCreate( vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); // 启动调度器 vTaskStartScheduler(); } for( ;; ); } ``` ### 直接任务通知(Direct Task Notifications) 直接任务通知FreeRTOS 从 V8.2.0 版本开始引入的一种轻量级的任务间通讯机制。每个任务都有一个 32 位的通知值,任务可以向另一个任务发送通知,设置或更新其通知值。接收任务可以等待通知的到来,并根据通知值进行相应的处理。直接任务通知可以替代信号量、队列和事件组,在某些场景下可以提高系统的性能和效率。 以下是一个使用直接任务通知进行任务间通讯的示例代码: ```c #include "FreeRTOS.h" #include "task.h" // 任务句柄 TaskHandle_t xReceiverTaskHandle; // 发送任务 void vSenderTask( void *pvParameters ) { for( ;; ) { // 向接收任务发送通知 xTaskNotify( xReceiverTaskHandle, 0x01, eSetBits ); vTaskDelay( pdMS_TO_TICKS( 1000 ) ); } } // 接收任务 void vReceiverTask( void *pvParameters ) { uint32_t ulNotificationValue; for( ;; ) { // 等待通知 if( xTaskNotifyWait( 0x00, ULONG_MAX, &ulNotificationValue, portMAX_DELAY ) == pdTRUE ) { if( ( ulNotificationValue & 0x01 ) != 0 ) { // 处理通知 } } } } void main( void ) { // 创建接收任务 xTaskCreate( vReceiverTask, "Receiver", configMINIMAL_STACK_SIZE, NULL, 1, &xReceiverTaskHandle ); // 创建发送任务 xTaskCreate( vSenderTask, "Sender", configMINIMAL_STACK_SIZE, NULL, 1, NULL ); // 启动调度器 vTaskStartScheduler(); for( ;; ); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值