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: 2. left join: 3. right join: 4.自连接 5.交叉连接: 6、联合查询 7、子查询 1. inner join: 代表选择的是两个表的交差部分。 内连接就是表间的主键与外键相连,只取得键值一致…...
flutter开发实战-CustomClipper裁剪长图帧动画效果
flutter开发实战-CustomClipper裁剪长图帧动画效果 在开发过程中,经常遇到帧动画的每一帧图显示在超长图上,需要处理这种帧动画效果。我这里使用的是CustomClipper 一、CustomClipper CustomClipper继承于Listenable abstract class CustomClipper e…...

CSS 中的优先级规则是怎样的?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐内联样式(Inline Styles)⭐ID 选择器(ID Selectors)⭐类选择器、属性选择器和伪类选择器(Class, Attribute, and Pseudo-class Selectors)⭐元素选择器和伪元素选择器…...

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

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

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

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

【python】python将json字符串导出excel | pandas处理json字符串保存为csv
如何将json转为csv 1、通过json直接转为csv 在Python中,你可以使用pandas库来处理DataFrame(数据帧)和将JSON数据转换为CSV格式。下面是一个简单的示例代码,展示了如何使用pandas库将JSON数据转换为CSV文件: import p…...

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

分布式系统理论
以前的架构...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...