当前位置: 首页 > news >正文

FreeRTOS(二值信号量)

资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理)

目录

一、信号量的概念

1、信号量的基本概念

2、信号量的分类

二、二值信号量的定义与应用

1、二值信号量的定义

2、二值信号量的应用

三、二值信号量的运作机制

1、FreeRTOS任务间二值信号量的实现

2、FreeRTOS中断方式二值信号量的实现

四、二值信号量的常用API函数

1、使用二值信号量典型流程与API

2、二值信号量创建与删除

3、任务与中断中二值信号量释放

五、二值信号量编程

 1、信号量创建

2、避免串口误同步

3、任务释放信号量

 4、任务获取信号量

5、中断释放信号量

6、任务中获取中断释放的信号量


一、信号量的概念

1、信号量的基本概念

消息队列是实现任务与任务或任务与中断间通信的数据结构,可类比裸机编程中的数组

信号量是实现任务与任务或任务与中断间通信的机制,可以类比裸机编程中的标志位

信号量(semaphore)可以实现任务与任务或任务与中断间的同步功能(二值信号量)资源管理(计数信号量)临界资源的互斥访问(互斥信号量)

信号量是一个非负正数,二值信号量与互斥信号量取值范围为0-1计数信号量取值范围是0-N(N>1)

0:信号量为空,所有试图获取它的任务都将处于阻塞状态,直到超时退出或其他任务释放信号量

正数:表示有一个或多个信号量供获取

2、信号量的分类

二值信号量(同步应用)

计数信号量(资源管理)

互斥信号量(互斥访问)

递归互斥信号量(简要了解即可)

二、二值信号量的定义与应用

1、二值信号量的定义

当信号量被获取了,信号量值变为0;当信号量被释放了,信号量值变为1。 把这种取值只有0与1两种状态的信号量称之为二值信号量。创建二值信号量时,系统会为创建的二值信号量分配内存

二值信号量是一种长度为1,消息大小为0的特殊消息队列。  因为这个队列只有空或满两种状态,而且消息大小为0,因此在运用时,只需要知道队列中是否有消息即可,而无需关注消息是什么。

2、二值信号量的应用

在嵌入式操作系统中,二值信号量是任务与任务或任务与中断间同步的重要手段。二值信号量也可以用于临界资源的访问,但不建议,因为存在任务优先级翻转问题.

任务与任务中同步的应用场景:

假设有一个温湿度传感器,每1s采集一次数据,那么让它在液晶屏中显示数据,这个周期也是1s,如果液晶屏刷新的周期是100ms,那么此时的温湿度数据还没更新,液晶屏根本无须刷新,只需要在1s后温湿度数据更新时刷新即可,否则CPU就是白白做了多次的无效数据更新操作,造成 CPU 资源浪费。如果液晶屏刷新的周期是 10s,那么温湿度的数据都变化了10次,液晶屏才来更新数据,那么这个产品测得的结果就是不准确的,所以还是需要同步协调工作,在温湿度采集完毕之后进行液晶屏数据的刷新,这样得到的结果才是最准确的,并且不会浪费 CPU 的资源。

任务与中断中同步的应用场景:

在串口接收中,我们不知道什么时候有数据发送过来,但如果设置一个任务专门时刻查询是否有数据到来,将会浪费CPU资源,所以在这种情况下使用二值信号量是很好的办法:当没有数据到来时,任务进入阻塞态,不参与任务的调度;等到数据到来了,释放一个二值信号量,任务就立即从阻塞态中解除,进入就绪态,然后在运行时处理数据,这样系统的资源就会得到很好的利用。

三、二值信号量的运作机制

1、FreeRTOS任务间二值信号量的实现

任务间二值信号量的实现是指各个任务之间使用信号量实现任务的同步功能。

运行条件:

创建 2 个任务 Task1 和 Task2。 

创建二值信号量默认的初始值是 0,也就是没有可用资源。

运行过程描述如下:

任务 Task1 运行过程中调用函数 xSemaphoreTake 获取信号量资源,但是由于创建二值信号的初始值是 0,没有信号量可以用,任务 Task1 将由运行态转到阻塞状态。运行的过程中,任务 Task2 通过函数 xSemaphoreGive 释放信号量,任务 Task1 由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态,实现Task1与Task2的同步功能。

2、FreeRTOS中断方式二值信号量的实现

运行条件:

创建 1 个任务 Task1 和一个串口接收中断。 

二值信号量的初始值为 0,串口中断调用函数 xSemaphoreGiveFromISR 释放信号量,任务 Task1调用函数 xSemaphoreTake 获取信号量资源。

运行过程描述如下:

任务 Task1 运行过程中调用函数 xSemaphoreTake,由于信号量的初始值是 0,没有信号量资源可用,任务 Task1 由运行态进入到阻塞态。

Task1 阻塞的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中调用函数xSemaphoreGiveFromISR 释放信号量资源,信号量数值加 1,此时信号量计数值为 1,任务 Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态,任务 Task1 获得信号量后,信号量数值减 1,此时信号量计数值又变成了 0。 

再次循环执行时,任务 Task1 调用函数 xSemaphoreTake 由于没有资源可用再次进入到挂起态,等待串口释放二值信号量资源,如此往复循环。

实际应用中,中断方式的消息机制要注意以下四个问题:

 中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应

 实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行

 中断服务程序中一定要调用专用于二值信号量设置函数,即以 FromISR 结尾的函数

 如果 FreeRTOS 工程的中断函数中调用了 FreeRTOS 的二值信号量的 API 函数,退出的时候要检测是否有高优先级任务就绪,如果有就绪的,需要在退出中断后进行任务切换

四、二值信号量的常用API函数

1、使用二值信号量典型流程与API

> 创建二值信号量   xSemaphoreCreateBinary()

> 释放二值信号量    xSemaphoreGive() 与 xSemaphoreGiveFromISR() 

> 获取二值信号量    xSemaphoreTake()

> 删除二值信号量    vSemaphoreDelete()

2、二值信号量创建与删除

二值信号量控制块(句柄):二值信号量的句柄为消息队列的句柄,因为二值信号量是一种长度为1,消息大小为0的特殊消息队列

二值信号量创建

函数原型:SemaphoreHandle_t xSemaphoreCreateBinary(void)

函数描述:函数 xSemaphoreCreateBinary 用于创建二值信号量。 

 返回值,如果创建成功会返回二值信号量的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足,无法为此二值信号量提供所需的空间会返回 NULL。

此函数基于消息队列函数实现:

图片

 应用举例

图片

 二值信号量删除

函数原型:void vSemaphoreDelete(void)

函数描述:函数 vSemaphoreDelete可用于删除二值信号量。 

3、任务与中断中二值信号量释放

任务中二值信号量释放

函数原型:xSemaphoreGive( SemaphoreHandle_t xSemaphore ); /* 信号量句柄 */

函数描述:函数 xSemaphoreGive 用于在任务代码中释放信号量。

 第 1 个参数是信号量句柄。

 返回值,如果信号量释放成功返回 pdTRUE,否则返回 pdFALSE,因为信号量的实现是基于消息队列,返回失败的主要原因是消息队列已经满了。

使用这个函数要注意以下问题:

1. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是xSemaphoreGiveFromISR。

2. 使用此函数前,一定要保证用函数 xSemaphoreCreateBinary(), xSemaphoreCreateMutex() 或者xSemaphoreCreateCounting()创建了信号量。

3. 此函数不支持使用 xSemaphoreCreateRecursiveMutex()创建的信号量。

中断中二值信号量释放

函数原型:xSemaphoreGiveFromISR ( SemaphoreHandle_t xSemaphore, /* 信号量句柄 */

    signed BaseType_t *pxHigherPriorityTaskWoken /* 高优先级任务是否被唤醒的状态保存 */ )

函数描述:函数 xSemaphoreGiveFromISR 用于中断服务程序中释放信号量。

 第 1 个参数是信号量句柄。

 第 2 个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 pdTRUE,说明有高优先级任务要执行,否则没有。

 返回值,如果信号量释放成功返回 pdTRUE,否则返回 errQUEUE_FULL。

使用这个函数要注意以下问题:

1. 此函数是基于消息队列函数 xQueueGiveFromISR 实现的:#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )

2. 此函数是用于中断服务程序中调用的,故不可以任务代码中调用此函数,任务代码中中使用的是xSemaphoreGive。

3. 使用此函数前,一定要保证用函数 xSemaphoreCreateBinary()或者 xSemaphoreCreateCounting()创建了信号量。

4. 此函数不支持使用 xSemaphoreCreateMutex ()创建的信号量。

五、二值信号量编程

 1、信号量创建

2、避免串口误同步

STM32Cube生成的FreeRTos代码创建二值信号量时,默认为1,此处释放避免串口误同步

  xSemaphoreTake(myBinarySem01Handle,0);//STM32CubeMX生成的FreeRTos代码创建二值信号量时,默认为1,此处释放,避免串口误同步xSemaphoreTake(myBinarySemISRHandle,0);//STM32CubeMX生成的FreeRTos代码创建二值信号量时,默认为1,此处释放,避免串口误同步

3、任务释放信号量

void ReleaseSem_Task(void const * argument)
{/* USER CODE BEGIN ReleaseSem_Task */BaseType_t xResult;uint16_t GiveCnt=0;   //释放计数char buff[50];/* Infinite loop */for(;;){HAL_UART_Transmit(&huart2, (uint8_t *)"发送同步信号!!! \r\n",18, HAL_MAX_DELAY);xResult=xSemaphoreGive(myBinarySem01Handle);if(xResult==pdTRUE){sprintf(buff,"成功发送二值信号量同步信号,次数 = %u \r\n",++GiveCnt);HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen(buff), HAL_MAX_DELAY);}else{HAL_UART_Transmit(&huart2, (uint8_t *)"发送同步信号失败 \r\n\r\n", 17, HAL_MAX_DELAY);}osDelay(1000);}/* USER CODE END ReleaseSem_Task */
}

 4、任务获取信号量

void BinarySem_Syn_Task(void const * argument)
{/* USER CODE BEGIN BinarySem_Syn_Task */BaseType_t xResult;uint16_t TakeCnt=0;   //获取计数char buff[50];/* Infinite loop */for(;;){HAL_UART_Transmit(&huart2,(uint8_t *)"等待同步信号,无限等待 \r\n", 25, HAL_MAX_DELAY);xResult=xSemaphoreTake(myBinarySem01Handle,portMAX_DELAY);if(xResult==pdTRUE){sprintf(buff,"成功接收到二值信号量同步信号,次数 = %u \r\n\r\n",++TakeCnt);HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen(buff), HAL_MAX_DELAY);}}/* USER CODE END BinarySem_Syn_Task */
}

5、中断释放信号量

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{BaseType_t xHigherPriorityTaskWoken =pdTRUE;if(huart->Instance==huart2.Instance){xSemaphoreGiveFromISR(myBinarySemISRHandle,&xHigherPriorityTaskWoken);//如果有高优先级任务就绪,执行一次任务切换portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}
}

6、任务中获取中断释放的信号量

void BinarySemSyneISR_Task(void const * argument)
{/* USER CODE BEGIN BinarySemSyneISR_Task */BaseType_t xResult;uint16_t TakeCnt=0;   //获取计数char buff[50];char rxBuff[10];/* Infinite loop */for (;;){HAL_UART_Receive_IT(&huart2, (uint8_t*) rxBuff, strlen(rxBuff));HAL_UART_Transmit(&huart2, (uint8_t*) "等待串口中断同步信号,无限等待 \r\n", 21,HAL_MAX_DELAY);xResult = xSemaphoreTake(myBinarySemISRHandle, portMAX_DELAY);if (xResult == pdTRUE){sprintf(buff, "成功接收到二值信号量同步信号,次数 = %u \r\n\r\n", ++TakeCnt);HAL_UART_Transmit(&huart2, (uint8_t*) buff, strlen(buff),HAL_MAX_DELAY);sprintf(buff, "成功接收到串口数据: %s \r\n\r\n", rxBuff);HAL_UART_Transmit(&huart2, (uint8_t*) buff, strlen(buff),HAL_MAX_DELAY);}}/* USER CODE END BinarySemSyneISR_Task */
}

相关文章:

FreeRTOS(二值信号量)

资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、信号量的概念 1、信号量的基本概念 2、信号量的分类 二、二值信号量的定义与应用 1、二值信号量的定义 2、二值信号量的应用 三、二值信号量的运作机制 1、FreeRTOS任务间二值…...

leetcode面试题:动物收容所(考查对队列的理解和运用)

题目: 有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时…...

【Linux命令行与Shell脚本编程】第十八章 文本处理与编辑器基础

Linux命令行与Shell脚本编程 第十八章 文本处理与编辑器基础 文章目录 Linux命令行与Shell脚本编程第十八章 文本处理与编辑器基础 文本处理与编辑器基础8.1.文本处理8.1.1.sed编辑器8.1.1.1.在命令行中定义编辑器命令8.1.1.2.在命令行中使用多个编辑器命令8.1.1.3.从文件中读…...

2023牛客暑期多校训练营7

Beautiful Sequence 贪心,二进制,构造 Cyperation 模拟 ,数学 We Love Strings 分块,二进制枚举,二进制容斥dp Writing Books 签到 根据相邻两个异或值B,因为前小于等于后,故从高到低遍历B的每一…...

centos7升级glibc2.28

1 概述 centos7自带的glibc对于某些软件是太旧的,决定将glibc升级至2.28。 2 安装过程 2.1 下载glibc源码 mkdir -p /opt/third-party && cd /opt/third-party wget http://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.gz tar -xf glibc-2.28.tar.gz cd glibc…...

腾讯云香港服务器租用_2核2G20M_2核4G30M

腾讯云香港服务器租用费用表,目前中国香港地域轻量应用服务器可选配置2核2G20M、2核2G30M、2核4G30M,操作系统可选Windows和Linux,不只是香港云服务器,新加坡、硅谷、法兰克福和东京服务器均有活动,腾讯云服务器网分享…...

十三、ESP32PS2摇杆(ADC)

1. 运行效果 在上下左右操作PS2摇杆的时候,会检测到数据 2. 滑动电阻...

网络安全的相关知识点

网络安全威胁类型: 1.窃听:广播式网络系统。 2.假冒 3.重放:重复一份报文或者报文的一部分,以便产生一个被授权的效果。 4.流量分析 5.数据完整性破坏 6.拒绝服务 7.资源的非授权使用 8.陷门和特洛伊木马:木马病毒有客…...

算法练习(6):牛客在线编程06 递归/回溯

package jz.bm;import java.io.PushbackInputStream; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays;public class bm6 {/*** BM55 没有重复项数字的全排列*/ArrayList<ArrayList<Integer>> res new ArrayList<>()…...

C#使用OpenCv(OpenCVSharp)图像局部二值化处理实例

本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行局部二值化处理。 目录 图像二值化原理 局部二值化 自适应阈值 实例 效果...

MySQL多表关联查询

目录 1. inner join&#xff1a; 2. left join&#xff1a; 3. right join&#xff1a; 4.自连接 5.交叉连接&#xff1a; 6、联合查询 7、子查询 1. inner join&#xff1a; 代表选择的是两个表的交差部分。 内连接就是表间的主键与外键相连&#xff0c;只取得键值一致…...

flutter开发实战-CustomClipper裁剪长图帧动画效果

flutter开发实战-CustomClipper裁剪长图帧动画效果 在开发过程中&#xff0c;经常遇到帧动画的每一帧图显示在超长图上&#xff0c;需要处理这种帧动画效果。我这里使用的是CustomClipper 一、CustomClipper CustomClipper继承于Listenable abstract class CustomClipper e…...

CSS 中的优先级规则是怎样的?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐内联样式&#xff08;Inline Styles&#xff09;⭐ID 选择器&#xff08;ID Selectors&#xff09;⭐类选择器、属性选择器和伪类选择器&#xff08;Class, Attribute, and Pseudo-class Selectors&#xff09;⭐元素选择器和伪元素选择器…...

概率图模型(Probabilistic Graphical Model,PGM)

概率图模型&#xff08;Probabilistic Graphical Model&#xff0c;PGM&#xff09;&#xff0c;是一种用图结构来描述多元随机变量之间条件独立性的概率模型。它可以用来表示复杂的概率分布&#xff0c;进行有效的推理和学习&#xff0c;以及解决各种实际问题&#xff0c;如图…...

Oracle 知识篇+会话级全局临时表在不同连接模式中的表现

标签&#xff1a;会话级临时表、全局临时表、幻读释义&#xff1a;Oracle 全局临时表又叫GTT ★ 结论 ✔ 专用服务器模式&#xff1a;不同应用会话只能访问自己的数据 ✔ 共享服务器模式&#xff1a;不同应用会话只能访问自己的数据 ✔ 数据库驻留连接池模式&#xff1a;不同应…...

MySQL 数据库文件的导入导出

目录 数据库的导出 导出整个数据库 导出数据库中的数据表 导出数据库结构 导出数据库中表的表结构 导出多个数据库 导出所有数据库 数据库的导入 数据库的导出 mysqldump -h IP地址 -P 端口 -u 用户名 -p 数据库名 > 导出的文件名 用管理员权限打开cmd进入MySQL的bi…...

找不到资产文件project.assets.json

NuGet 在“obj”文件夹中写入名为 project.assets.json 的文件&#xff0c;.NET SDK 使用该文件来获取有关要传递到编译器的包的信息 。 如果在生成过程中找不到资产文件 project.assets.json&#xff0c;则会发生此错误。 1.执行命令的方式解决 点击工具&#xff0c;分别展开命…...

【python】python将json字符串导出excel | pandas处理json字符串保存为csv

如何将json转为csv 1、通过json直接转为csv 在Python中&#xff0c;你可以使用pandas库来处理DataFrame&#xff08;数据帧&#xff09;和将JSON数据转换为CSV格式。下面是一个简单的示例代码&#xff0c;展示了如何使用pandas库将JSON数据转换为CSV文件&#xff1a; import p…...

opencv 基础54-利用形状场景算法比较轮廓-cv2.createShapeContextDistanceExtractor()

注意&#xff1a;新版本的opencv 4 已经没有这个函数 cv2.createShapeContextDistanceExtractor() 形状场景算法是一种用于比较轮廓或形状的方法。这种算法通常用于计算两个形状之间的相似性或差异性&#xff0c;以及找到最佳的匹配方式。 下面是一种基本的比较轮廓的流程&…...

分布式系统理论

以前的架构...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...