目录

1. 任务通知的理论讲解

1.1 任务通知的核心

1.2 怎么传递信息

2. 任务通知使用_轻量级信号量

3. 任务通知使用_轻量级队列

4. 任务通知使用_轻量级事件组


1. 任务通知的理论讲解

1.1 任务通知的核心

本节源码:22_freertos_example_tasknotify_semaphore,来自15_freertos_example_semaphore,下一节视频才修改。

理解任务通知的核心在于TCB结构体中有这两项:

ucNotifyState有3种取值:

  • taskNOT_WAITING_NOTIFICATION:任务没有在等待通知

  • taskWAITING_NOTIFICATION:任务在等待通知

  • taskNOTIFICATION_RECEIVED:任务接收到了通知,也被称为pending(有数据了,待处理)

使用流程:使用ucNotifyState来切换任务状态(阻塞、就绪),使用ulNotifiedValue来传递信息。

  • 任务A被创建出来时,ucNotifyState为taskNOT_WAITING_NOTIFICATION

  • 它想等待通知的话

    • 调用ulTaskNotifyTakexTaskNotifyWait,进入taskWAITING_NOTIFICATION

    • 表示在等待通知,任务进入阻塞状态

  • 任务B可以调用这两个函数来通知A:xTaskNotifyGivexTaskNotify

    • 任务A的ucNotifyState就变为taskNOTIFICATION_RECEIVED

    • 表示收到了通知,待处理

  • 任务A从阻塞状态变为就绪态,它运行时

    • ulTaskNotifyTakexTaskNotifyWait得到数值并返回

    • 返回之前把ucNotifyState恢复为taskNOT_WAITING_NOTIFICATION


  1. 使用任务通知的时候,就是“通知任务”,目标明确。发送者、接受者是多对1的关系。使用任务通知时,只能通知指定的任务。
  2. 使用任务通知时,假设任务A通知任务B,任务A发出通知时不会阻塞;任务A等待通知时,可以等待。
  3. TCB结构体里没有list让发送者阻塞在上面,所以发送者不会阻塞。

两者的对比

使用队列、信号量、事件组时,双方通过中间的结构体通信

任务通知

1.2 怎么传递信息

函数原型如下:

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
​
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
发送函数 作用 接收函数 作用
xTaskNotifyGive val++ ulTaskNotifyTake val-- 或 val = 0
xTaskNotify xTaskNotifyWait
不使用val,只起通知作用 可以在函数进入时清除val的某些位 可以在函数退出前清除val的某些位 可以取得val的值
val |= (bits)
val++
val = xxx 不覆盖, 当ucNotifyState表示在等待才起效
val = xxx 覆盖

eNotifyAction参数说明:

eNotifyAction取值 说明
eNoAction 仅仅是更新通知状态为"pending",未使用ulValue。 这个选项相当于轻量级的、更高效的二进制信号量。
eSetBits 通知值 = 原来的通知值 | ulValue,按位或。 相当于轻量级的、更高效的事件组。
eIncrement 通知值 = 原来的通知值 + 1,未使用ulValue。 相当于轻量级的、更高效的二进制信号量、计数型信号量。 相当于xTaskNotifyGive()函数。
eSetValueWithoutOverwrite 不覆盖。 如果通知状态为"pending"(表示有数据未读), 则此次调用xTaskNotify不做任何事,返回pdFAIL。 如果通知状态不是"pending"(表示没有新数据), 则:通知值 = ulValue。
eSetValueWithOverwrite 覆盖。 无论如何,不管通知状态是否为"pendng", 通知值 = ulValue。

2. 任务通知使用_轻量级信号量

本节源码:22_freertos_example_tasknotify_semaphore,来自15_freertos_example_semaphore

函数对比:

信号量 使用任务通知实现信号量
创建 SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount );
Give xSemaphoreGive( SemaphoreHandle_t xSemaphore ); BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
Take xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xBlockTime ); uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );

main.c

static int sum = 0;
static volatile int flagCalcEnd = 0;
static volatile int flagUARTused = 0;static SemaphoreHandle_t xSemCalc;
static SemaphoreHandle_t xSemUART;static TaskHandle_t xHandleTask2;void Task1Function(void * param)
{volatile int i = 0;while (1){for (i = 0; i < 10000; i++)sum++;//printf("1");for (i = 0; i < 10; i++){// xSemaphoreGive(xSemCalc);xTaskNotifyGive(xHandleTask2);}vTaskDelete(NULL);}
}void Task2Function(void * param)
{int i = 0;int val;while (1){//if (flagCalcEnd)flagCalcEnd = 0;//xSemaphoreTake(xSemCalc, portMAX_DELAY);val = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);flagCalcEnd = 1;printf("sum = %d, NotifyVal = %d, i = %d\r\n", sum, val, i++);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xSemCalc = xSemaphoreCreateCounting(10, 0);xSemUART = xSemaphoreCreateBinary();xSemaphoreGive(xSemUART);xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, &xHandleTask2);//xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);//xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

运行结果

函数返回前是否清零:

val = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);

pdFALSE:如果通知值大于0,则把通知值减一

main.c::Task2Function

如果修改代码如下:val = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

pdTRUE:把通知值清零

运行结果:

3. 任务通知使用_轻量级队列

本节源码:23_freertos_example_tasknotify_queue,来自13_freertos_example_queue

函数对比:

队列 使用任务通知实现队列
创建 QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );
发送 BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait ); BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
接收 BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ); BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );

main.c

static int sum = 0;
static volatile int flagCalcEnd = 0;
static volatile int flagUARTused = 0;
static QueueHandle_t xQueueCalcHandle;
static QueueHandle_t xQueueUARTcHandle;static TaskHandle_t xHandleTask2;void Task1Function(void * param)
{volatile int i = 0;while (1){for (i = 0; i < 10000; i++)sum++;//printf("1");//flagCalcEnd = 1;//vTaskDelete(NULL);for (i = 0; i < 10; i++){//xQueueSend(xQueueCalcHandle, &sum, portMAX_DELAY);xTaskNotify(xHandleTask2, sum, eSetValueWithoutOverwrite);//xTaskNotify(xHandleTask2, sum, eSetValueWithOverwrite);sum++;}vTaskDelete(NULL);//sum = 1;}
}void Task2Function(void * param)
{int val;int i = 0;while (1){//if (flagCalcEnd)flagCalcEnd = 0;//xQueueReceive(xQueueCalcHandle, &val, portMAX_DELAY);xTaskNotifyWait(0, 0, &val, portMAX_DELAY);flagCalcEnd = 1;printf("sum = %d, i = %d\r\n", val, i++);}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");xQueueCalcHandle = xQueueCreate(10, sizeof(int));if (xQueueCalcHandle == NULL){printf("can not create queue\r\n");}InitUARTLock();xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, &xHandleTask2);//xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);//xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

运行结果 :

不覆盖

main.c::Task1Function

修改代码如下: xTaskNotify(xHandleTask2, sum, eSetValueWithOverwrite);

覆盖

4. 任务通知使用_轻量级事件组

本节源码:24_freertos_example_tasknotify_event_group,来自20_freertos_example_event_group

假设有3个任务:

  • 任务1做事件1

  • 任务2做事件2

  • 任务3等待事件1、事件2都发生

可以使用事件组来编写程序,也可以使用任务通知来编写程序。

函数对比:

事件组 使用任务通知实现事件组
创建 EventGroupHandle_t xEventGroupCreate( void )
设置事件 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
等待事件 EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ); BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );

main.c

static int sum = 0;
static int dec = 0;
static volatile int flagCalcEnd = 0;
static volatile int flagUARTused = 0;
static QueueHandle_t xQueueCalcHandle;static EventGroupHandle_t xEventGroupCalc;
static TaskHandle_t xHandleTask3;void Task1Function(void * param)
{volatile int i = 0;while (1){for (i = 0; i < 100000; i++)sum++;xQueueSend(xQueueCalcHandle, &sum, 0);/* 璁剧疆浜嬩欢0 *///xEventGroupSetBits(xEventGroupCalc, (1<<0));xTaskNotify(xHandleTask3, (1<<0), eSetBits);printf("Task 1 set bit 0\r\n");vTaskDelete(NULL);}
}void Task2Function(void * param)
{volatile int i = 0;while (1){for (i = 0; i < 1000000; i++)dec--;xQueueSend(xQueueCalcHandle, &dec, 0);/* 璁剧疆浜嬩欢1 *///xEventGroupSetBits(xEventGroupCalc, (1<<1));xTaskNotify(xHandleTask3, (1<<1), eSetBits);printf("Task 2 set bit 1\r\n");vTaskDelete(NULL);}
}void Task3Function(void * param)
{int val1, val2;int bits;while (1){/*绛夊緟浜嬩欢  *///xEventGroupWaitBits(xEventGroupCalc, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY);xTaskNotifyWait(0, 0, &bits, portMAX_DELAY);if ((bits & 0x3) == 0x3){vTaskDelay(20);xQueueReceive(xQueueCalcHandle, &val1, 0);xQueueReceive(xQueueCalcHandle, &val2, 0);printf("val1 = %d, val2 = %d\r\n", val1, val2);}else{vTaskDelay(20);printf("have not get all bits, get only 0x%x\r\n", bits);}}
}/*-----------------------------------------------------------*/int main( void )
{TaskHandle_t xHandleTask1;#ifdef DEBUGdebug();
#endifprvSetupHardware();printf("Hello, world!\r\n");/* 鍒涘缓浜嬩欢缁?*/xEventGroupCalc = xEventGroupCreate();xQueueCalcHandle = xQueueCreate(2, sizeof(int));if (xQueueCalcHandle == NULL){printf("can not create queue\r\n");}xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);xTaskCreate(Task3Function, "Task3", 100, NULL, 1, &xHandleTask3);/* Start the scheduler. */vTaskStartScheduler();/* Will only get here if there was not enough heap space to create theidle task. */return 0;
}

运行结果

九、freeRTOS_任务通知的使用相关推荐

  1. MVC北京络捷斯特第三方物流系统技术解析(九)到货通知

    MVC北京络捷斯特第三方物流系统技术解析(九)到货通知 对于客户要求自提的货物(在订单录入中钩选"是否取送"中的"送货"),当货物到达目的站后,客服通知客户来场 ...

  2. 各类型土地利用图例_划重点!国土空间总体规划——土地利用

    四.土地利用 (一) ​土地利用是否协调匹配 国土空间规划的要素和资源,最终都要落到土地上,土地利用自然成为国土空间规划需要研究的关键问题.所谓土地利用,是指人类通过特定的行为,以土地作为劳动对象或手 ...

  3. FreeRTOS及其应用,万字长文,基础入门

    嵌入式系统不只是ARM+Linux,不是只有安卓,凡是电子产品都可称为嵌入式系统.物联网行业的兴起,也提升了FreeRTOS市场占有率.本文就是介绍FreeRTOS基础及其应用,只是个人整理,可能存在 ...

  4. AndroidStudio 开发基础知识【翻译完成】

    协议:CC BY-NC-SA 4.0 尔曹身与名俱灭,不废江河万古流.--杜甫<戏为六绝句·其二> 在线阅读 在线阅读(Gitee) ApacheCN 学习资源 目录 AndroidStu ...

  5. Spring框架(中) AOP

    Spring(中) AOP (一)代理模式 1.静态代理 静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类. 举例: package co ...

  6. c++ qt5范例开发大全_237页建设工程监理内业资料全套范例,附百份案例表格,快拿走...

    237页建设工程监理内业资料全套范例,附百份案例表格,快拿走 监理内业资料的规范程度能充分体现一个监理项目部的管理水平,监理资料规范与否不是资料员一个人的事情,需要项目部全体人共同努力. 今天给大家整 ...

  7. Android 5.1 Lollipop Phone工作流程浅析(十三)__InCallActivity启动Performance浅析

    前置文章: < Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划> <Android 4.4 Kitkat Phone工作流程浅析(二)__UI结 ...

  8. 书1_JavaEE概念/项目_22/5/29

    <轻量级Java EE企业应用开发实战>-5.29-华 读书 Java EE/写课后习题 一.Java EE 概述 1-简述Java EE 的概念和发展简史. JavaEE(J2EE)(J ...

  9. Spring学习详细代码+图片解释笔记

    闲聊虾扯蛋: O(∩_∩)O哈哈~,终于到了上传博客的时候了,该Spring笔记写于寒假疫情期间,但家中网络属实让我哭笑不得,所以时隔一个寒假(9个月),现在将自己的笔记上传到此.以此留作纪念.革命尚 ...

最新文章

  1. 计蒜客NOIP模拟赛(2) D2T2紫色百合
  2. 以太坊智能合约简介(Solidity)
  3. DbLookUpCombobox的使用方法
  4. Vue + Element UI——搜索框DEMO
  5. SSD安装及训练自己的数据集
  6. unity 继承会调用start吗_【浅入浅出】Unity 雾效
  7. jQuery之高级选择器
  8. gentoo 安装时的网络配置
  9. Ajax实践之用户是否存在
  10. 9-4:C++多态之单继承和多继承中的虚函数表
  11. IDEA上传本地项目到SVN
  12. 运维管理中的制度和流程
  13. 合上More Exceptional C++的瞬间
  14. linux系统之上搭建maven 之nexus服务篇
  15. JAVAEE框架数据库技术之12_oracle常用函数和高级查询子查询
  16. 头条号个人中心登录_注册登录系统
  17. Elasticsearch-拼音分词/排序
  18. 防火墙多选路出口(ISP选路、策略路由、智能选路)
  19. 韩国票房:“蜘蛛侠”挤掉“美队”称王
  20. 线程池:酷我音乐网站热歌排行榜里面的歌曲!

热门文章

  1. 重庆交通大学2020级程序设计方法期末考试 题解
  2. https协议和Htt协议
  3. augment()图像增强库
  4. python agg
  5. 韩国计划扩展网络道德课程
  6. 2014年全球手游市场发展的六大趋势
  7. 【BYM】Android 仿百度搜索列表滑动效果,flutter环境搭建
  8. 取消选中单选框radio的三种方式
  9. 【转发摘要】微服务架构设计
  10. proc_mkdir与proc_create