文章目录

  • 一、消息队列
  • 二、信号量
  • 三、互斥量
  • 四、事件
  • 五、通知

一、消息队列

消息队列是一种常用于任务间通信的数据结构, 队列可以在任务与任务间、中断和任务间传递信息。读写队列均支持超时机制。

1、创建队列

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,//队列长度UBaseType_t uxItemSize );//队列中消息单元的大小,以字节为单位

2、删除队列

vQueueDelete()

3、队列发送

BaseType_t xQueueSend(QueueHandle_t xQueue,//队列句柄const void * pvItemToQueue,//指针,指向要发送到队列尾部的队列消息TickType_t xTicksToWait);//等待时间

4、在中断服务程序中使用的发送函数

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken//为一个可选参数, 可以设置为 NULL。);

5、向队列首发送消息

BaseType_t xQueueSendToFront( QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait );

6、用于在中断服务程序中向消息队列队首发送一个消息

BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);

7、接收队列
从一个队列中接收消息并把消息从队列中删除

BaseType_t xQueueReceive(QueueHandle_t xQueue,void *pvBuffer,TickType_t xTicksToWait);

8、在中断中接收

xQueueReceiveFromISR()

9、 消息队列应用实例

QueueHandle_t Test_Queue =NULL;
#define  QUEUE_LEN    4   /*消息队列长度*/
#define  QUEUE_SIZE   4   /*每个消息大小 *//
static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;
taskENTER_CRITICAL();     //进入临界区/* 创建Test_Queue */Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,(UBaseType_t ) QUEUE_SIZE);创建任务一:Send_Task创建任务二:Receive_TaskvTaskDelete(AppTaskCreate_Handle); taskEXIT_CRITICAL();
}///任务一:发送
static void Send_Task(void* parameter)
{    BaseType_t xReturn = pdPASS;uint32_t send_data1 = 1;uint32_t send_data2 = 2;while (1){xReturn = xQueueSend( Test_Queue,&send_data1,0 );       if(pdPASS == xReturn)printf("send_data1 发送成功!\n\n");vTaskDelay(20);}
}//任务二:接收
static void Receive_Task(void* parameter)
{   BaseType_t xReturn = pdTRUE;uint32_t r_queue;while (1){xReturn = xQueueReceive( Test_Queue, &r_queue,portMAX_DELAY); if(pdTRUE == xReturn)printf("收到数据%d\n\n",r_queue);elseprintf("没有收到数据0x%lx\n",xReturn);}
}

二、信号量

实现任务之间同步或临界资源的互斥访问

1、创建二值信号量

 xSemaphoreCreateBinary()

2、创建计数信号量

SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,//计数信号量的最大值UBaseType_t uxInitialCount//创建计数信号量的初始值);

3、信号量删除函数

vSemaphoreDelete()

4、信号量释放函数

释放的信号量对象必须是已经被创建的,可以用于二值信号量、计数信号量、互斥量的释放,但不能释放由函数xSemaphoreCreateRecursiveMutex()创建的递归互斥量。此外该函数不能在中断中使用

xSemaphoreGive( xSemaphore )

5、中断中释放信号量
用于释放一个信号量,带中断保护。它不能释放互斥量,这是因为互斥量
不可以在中断中使用。

xSemaphoreGiveFromISR()

6、信号量获取
获取一个信号量,可以是二值信号量、计数信号量、互斥量

xSemaphoreTake( xSemaphore, xBlockTime )

参数: xSemaphore:信号量句柄;xBlockTime:等待信号量可用的最大超时时间。

7、不带阻塞机制获取信号量的函数
不能用于互斥量

xSemaphoreTakeFromISR()

8、信号量应用实例

创建两个任务,一个是获取信号量任务,一个是释放互斥量任务

获取信号量任务是一直在等待信号量,其等待时间是 portMAX_DELAY,等到获取到信号量之后,任务开始执行任务代码。

SemaphoreHandle_t BinarySem_Handle =NULL;static void Receive_Task(void* parameter)
{   BaseType_t xReturn = pdPASS;while (1) {//获取二值信号量,没有获取则一直等待xReturn = xSemaphoreTake(BinarySem_Handle,portMAX_DELAY); if(pdTRUE == xReturn)printf("BinarySem_Handle  get successful |!\n\n");}
}static void Send_Task(void* parameter)
{    BaseType_t xReturn = pdPASS;while (1){if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ){xReturn = xSemaphoreGive( BinarySem_Handle );//给出信号量if( xReturn == pdTRUE )printf("BinarySem_Handle  释放成功\r\n");elseprintf("BinarySem_Handle  释放失败\r\n");} vTaskDelay(20);}
}static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;taskENTER_CRITICAL(); /* 创建二值信号量*/BinarySem_Handle = xSemaphoreCreateBinary();    if(NULL != BinarySem_Handle)printf("BinarySem_Handle create successful!\r\n");创建任务一:Receive_Task创建任务二:Send_TaskvTaskDelete(AppTaskCreate_Handle); taskEXIT_CRITICAL();
}

三、互斥量

它支持互斥量所有权、递归访问以及防止优先级翻转的特性,用于实现对临界资源的独占式处理,是用于保护资源的互锁。不能用于中断函数中

与信号量区别
二值信号量:用于实现同步(任务之间或者任务与中断之间)

应用场景
可能会引起优先级翻转的情况

递归互斥量更适用于:
任务可能会多次获取互斥量的情况下。这样可以避免同一任务多次递归持有而造成死锁的问题。

1、互斥量创建 ,只能被同一个任务获取一次
xSemaphoreCreateMutex()2、递归互斥量创建, 它可以被同一个任务获取很多次,获取多少次就需要释放多少次
xSemaphoreCreateRecursiveMutex()3、互斥量删除
vSemaphoreDelete()4、互斥量获取
xSemaphoreTake()5、递归互斥量获取函
xSemaphoreTakeRecursive( xMutex, xBlockTime )6、互斥量释放
xSemaphoreGive()7、递归互斥量释放
xSemaphoreGiveRecursive()

8、互斥量应用实例
实验验证了在低优先级任务运行的时候,中优先级任务无法抢占低优先级的任务。

SemaphoreHandle_t MuxSem_Handle =NULL;static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;/taskENTER_CRITICAL();  /* MuxSem */MuxSem_Handle = xSemaphoreCreateMutex();  if(NULL != MuxSem_Handle)printf("MuxSem_Handle 创建成功¦!\r\n");xReturn = xSemaphoreGive( MuxSem_Handle );//给出信号量创建任务一:LowPriority_Task创建任务二:MidPriority_Task创建任务三:HighPriority_TaskvTaskDelete(AppTaskCreate_Handle); taskEXIT_CRITICAL();
}static void LowPriority_Task(void* parameter)
{   static uint32_t i;BaseType_t xReturn = pdPASS;while (1){//获取信号量,没有则一直等待printf("LowPriority_Task获取互斥量\n");xReturn = xSemaphoreTake(MuxSem_Handle,portMAX_DELAY); if(pdTRUE == xReturn)printf("LowPriority_Task Running\n\n");for(i=0;i<2000000;i++)//占用低级任务互斥量{taskYIELD();//调度}printf("LowPriority_Task释放信号量!\r\n");xReturn = xSemaphoreGive( MuxSem_Handle );//释放信号量vTaskDelay(1000);}
}static void MidPriority_Task(void* parameter)
{    while (1){printf("MidPriority_Task Running\n");vTaskDelay(1000);}
}static void HighPriority_Task(void* parameter)
{   BaseType_t xReturn = pdTRUE;while (1){xReturn = xSemaphoreTake(MuxSem_Handle,portMAX_DELAY); printf("HighPriority_Task  获取互斥量!\r\n");                          if(pdTRUE == xReturn)printf("HighPriority_Task Running\n");printf("HighPriority_Task 释放互斥量!\r\n");xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量vTaskDelay(1000);}
}

输出打印

HighPriority_Task 获取互斥量
HighPriority_Task Running
HighPriority_Task 释放互斥量!MidPriority_Task RunningLowPriority_Task 获取互斥量
LowPriority_Task Running
LowPriority_Task 释放互斥量!HighPriority_Task 获取互斥量

四、事件

可以用事件来做标志位,判断某些事件是否发生了。

1、事件创建函数 xEventGroupCreate()2、事件删除函数 vEventGroupDelete()3、事件组置位函数 xEventGroupSetBits()(任务)4、事件组置位函数 xEventGroupSetBitsFromISR()(中断)5、等待事件函数 xEventGroupWaitBits()6、xEventGroupClearBits()与 xEventGroupClearBitsFromISR()

等待事件函数

EventBits_t xEventGroupWaitBits(const EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,//按位或的值const BaseType_t xClearOnExit,//pdRTUE 系统将清除由形参 uxBitsToWaitFor 指定的事件标志位const BaseType_t xWaitForAllBits,//pdFALSE:uxBitsToWaitFor 指定的位有其中任意一个置位;pdTRUE  uxBitsToWaitFor 指定的位都置位的时候 TickType_t xTicksToWait );//等待时间

设置函数

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet );//事件的标志位

7、 事件应用实例
创建两个任务,一个是设置事件任务,一个是等待事件任务

设置事件任务 通过检测按键的按下情况设置不同的事件标志位,
等待事件任务 则获取这两个事件标志位,并且判断两个事件是否都发生,若是则输出相应信息

static EventGroupHandle_t Event_Handle =NULL;#define KEY1_EVENT  (0x01 << 0)
#define KEY2_EVENT  (0x01 << 1) static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;taskENTER_CRITICAL(); /* 创建事件 Event_Handle */Event_Handle = xEventGroupCreate();  if(NULL != Event_Handle)printf("Event_Handle创建成功\r\n");创建任务一:LED_Task创建任务二:KEY_TaskvTaskDelete(AppTaskCreate_Handle); taskEXIT_CRITICAL();
}static void LED_Task(void* parameter)
{   EventBits_t r_event;while (1){r_event = xEventGroupWaitBits(Event_Handle, KEY1_EVENT|KEY2_EVENT,//事件pdTRUE,pdTRUE,  portMAX_DELAY);if((r_event & (KEY1_EVENT|KEY2_EVENT)) == (KEY1_EVENT|KEY2_EVENT)) {printf ( "收到事件\n");     }elseprintf ( "事件 错误\n"); }
}static void KEY_Task(void* parameter)
{    while (1){if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )  {xEventGroupSetBits(Event_Handle,KEY1_EVENT); //触发事件一                  }if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )  {xEventGroupSetBits(Event_Handle,KEY2_EVENT); 触发事件二              }vTaskDelay(20); }
}

五、通知

每个任务都有一个 32 位的通知值,在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件组,也可以替代长度为 1 的队列;任务通知的使用无需创建队列;

发送任务通知函数
xTaskGenericNotify()获取任务通知
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, //任务句柄uint32_t ulValue, //值eNotifyAction eAction ); eNotifyAction 的取值                                 * eNoAction = 0//通知任务而不更新其通知值* eSetBits//设置任务通知值中的值* eIncrement//增加任务的通道值* eSetvaluewithoverwrite//覆盖当前通知* eSetValueWithoutoverwrite//不覆盖当前通知等待任务通知
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,//uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,//值TickType_t xTicksToWait );//事件

1、 通知应用实例(代替消息队列)

static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;taskENTER_CRITICAL(); 创建任务一: Receive1_Task创建任务二 :Send_TaskvTaskDelete(AppTaskCreate_Handle);taskEXIT_CRITICAL();
}//接收任务
static void Receive1_Task(void* parameter)
{   BaseType_t xReturn = pdTRUE;uint32_t r_num;xReturn=xTaskNotifyWait(0x0,            //进入函数的时候不清除任务bitULONG_MAX,   //退出函数的时候清除所有bit(uint32_t *)&r_char,        //任务通知值portMAX_DELAY);    //阻塞事件if( pdTRUE == xReturn )printf("Receive1_Task 任务通知消息 %d \n",r_num);
}
//发送任务
static void Send_Task(void* parameter)
{    BaseType_t xReturn = pdPASS;uint32_t send1 = 1;while (1){if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ){xReturn = xTaskNotify( Receive1_Task_Handle, /*任务句柄*/(uint32_t)&test_str1, /*任务内容 */eSetValueWithOverwrite );/*覆盖当前通知*/if( xReturn == pdPASS )printf("Receive1_Task_Handle ÈÎÎñ֪ͨÏûÏ¢·¢Ëͳɹ¦!\r\n");} vTaskDelay(20);}
}

2、通知应用实例(代替信号量)

static void Receive1_Task(void* parameter)
{   while (1){//获取任务通知,没有则一直等待ulTaskNotifyTake(pdTRUE,portMAX_DELAY);printf("Receive1_Task !\n\n");}
}static void Send_Task(void* parameter)
{    BaseType_t xReturn = pdPASS;while (1){if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ){xReturn = xTaskNotifyGive(Receive1_Task_Handle);//任务句柄if( xReturn == pdTRUE )printf("Receive1_Task_Handle ÈÎÎñ֪ͨ·¢Ëͳɹ¦!\r\n");} vTaskDelay(20);}
}

FreeRTOS 通信方式相关推荐

  1. 9.FreeRTOS学习笔记-任务通知

    基本概念 每个任务都有一个 32 位的通知值 任务通知可以替代二值信号量.计数信号量.事件组,也可以替代长度为 1 的队列(可以保存一个 32位整数或指针值) 通知比通过信号量等 ICP 通信方式解除 ...

  2. STM32F4+FreeRTOS+FreeRTosTcpIp移植教程

    花了几天时间完成了FreeRTOS自带的TCP/IP协议栈在stm32F407上的移植,在此记录并分享,第一次写这个,写的不好的地方见谅. 硬件是stm32F407最小系统(内带phy控制器),所以还 ...

  3. FreeRTOS学习-队列管理

    1. 简介 在FreeRTOS中,提供了多种任务间通讯的机制,包括消息队列.信号量和互斥锁.事件组.任务通知,他们的总体特征如下图所示: 从图中可以看出,消息队列.信号量和互斥锁.事件组都是间接的任务 ...

  4. FreeRTOS消息队列

    全文字数9920,预计阅读时长12分钟 问题解答 曾经有人问我,FreeRTOS那么多API,到底怎么记住呢? 我想说,其实API不难记,就是有点难找,因为FreeRTOS的API很多都是带参宏,所以 ...

  5. ESP32使用freeRTOS的消息队列

    零. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:ESP-IDF基本介绍,主要会涉及模组,芯片,开发板的介绍,环境搭建,程序编译下载,启动流程等一些基本的操作,让你对 ...

  6. 1、野火freertos学习笔记

    野火freertos学习笔记 1.任务 1.1 栈 1.2 任务的切换 taskYIELD(); 1.3 临界段 2.空闲任务 3.任务优先级 4.任务延时的表现 5.时间片 5.1抢占式.协做式 6 ...

  7. FreeRTOS:一、入门知识

    文章目录 前言 二.FreeRTOS简介 三.FreeRTOS源码结构 1.关于各个c文件的主要用途: 2.四种内存分配方式比较: 3.优先级: 4.任务状态: 5.通信方式: 6.临界区 7.调度锁 ...

  8. FreeRTOS 常用函数详解

    提示:此内容涉及部分汇编+数据结构+计算机操作系统 目录 FreeRTOS调度机制 优先级与状态 FreeRTOS调度链表 相关函数 一.xTaskCreate 创建任务相关 三. QueueDefi ...

  9. FreeRTOS任务通知 基于STM32

    文章目录 一.任务通知简介 二.任务通知的运作机制 三.任务通知的函数接口讲解 1. xTaskGenericNotify() 2.xTaskNotifyGive() 3.vTaskNotifyGiv ...

最新文章

  1. Web测试需要了解的知识
  2. 中国增速第一!《全球数字经济白皮书》发布
  3. iphone7像素_iPhone 7能否再战三年?这几点因素你得考虑到!
  4. No bean named 'dataSource' is defined
  5. ps里面怎么插入流程图_photoshop cs6绘画带箭头简单流程图的操作步骤介绍
  6. python中变量作用域
  7. torch各个版本镜像_如何解决在cuda上安装torch后torch.cuda.is_available()返回False
  8. linux的文件权限前面的东西,linux 文件权限解析
  9. 每天Leetcode 刷题 初级算法篇-数学问题-3的幂
  10. 3. JavaScript Date 对象
  11. 智能汽车“增量部件”争夺战(一):以华为海思为样榜,比亚迪蔚来们的漫漫造芯路
  12. VSCode中插件Code Spell Checker
  13. html页面调节图片大小,怎么用css设置图片大小?
  14. 【概率论】【笔记】【@汤家凤】【数一】【第五章】
  15. 弦截法(Secant Method)迭代求根的python程序
  16. gitlab上创建新的分支并发布代码
  17. 微软官方出了一款吊打WPS的PPT插件
  18. 理解线性变换和基(坐标)变换
  19. 第5天-[21天学Python]-Python中自定义函数及调用的方法
  20. 软件测试需求管理系统,软件测试管理及工具应用

热门文章

  1. RationalDMIS 2020直线度评价
  2. JanusGraph环境搭建实战
  3. 2023最新姆町个人自动发卡系统源码+全开源的/功能丰富UI美观
  4. win11 HEVC 扩展
  5. [C语言]描述算法的工具——流程图
  6. Android接电话流程,JAVA部分
  7. 基于AIOT综合能源管控平台开发探讨
  8. 《触摸屏游戏设计》——4.1节 起名字
  9. vs2019键盘钩子_键盘钩子WH_KEYBOARD和WH_KEYBOARD_LL
  10. 九齐单片机应用-小家电开发(1)