FreeRtos开发之计数信号量

前面介绍过了计数信号量的定义取值只有0与1两种状态的信号量称之为二值信号量
取值大于1的信号量称之为计数信号量
计数信号量的取值也可以为1,但通常大于1,如果取值为1,相当于只有0与1两种状态,用二值信号量即可。
计数信号量应用场景:
计数信号量允许多个任务对其进行操作,但限制了任务的数量。比如有一个停车场,里面只有50个车位,那么只能停50辆车,相当于我们的计数信号量是50。假如一开始停车场的车位还有50个,那么每进去一辆车就要消耗一个停车位,车位的数量就要减1,相应地,我们的计数信号量在使用之后也需要减 1。当停车场停满了50 辆车时,此时的停车位数量为0,再来的车就不能停进去了,否则将没法停车了,也相当于我们的计数信号量为0,后面的任务对这个停车场资源的访问也无法进行。当有车从停车场离开时,车位又空余出来了,那么后面的车就能停进去了。信号量操作也是一样的,当我们释放了这个资源,后面的任务才能对这个资源进行访问。
在这里插入图片描述任务 Task1 运行过程中调用函数 xSemaphoreTake 获取信号量资源,如果信号量大于0,Task1 将直接获取资源。如果信号量为0,任务 Task1 将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数xSemaphoreGive 释放掉资源。
任务 Task2至TaskN 等N个任务运行过程中调用函数 xSemaphoreTake 获取信号量资源,如果信号量大于0,Task2至N 将直接获取资源。如果信号量为0,任务 Task2至N将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数 xSemaphoreGive释放掉资源。

计数信号量使用流程和常用的API函数

  1. 创建计数信号量 xSemaphoreCreateCounting()
  2. 释放计数信号量 xSemaphoreGive()与xSemaphoreGiveFromlSR()
  3. 获取计数信号量 xSemaphoreTake()
  4. 删除计数信号量 vSemaphoreDelete()
1、计数信号量创建与删除

1、计数信号量控制块(句柄)
如下图:计数信号量的句柄为消息队列的句柄,因为计数信号量是一种长度大于1,消息大小为0的特殊消息队列

//FreeRtos源码中定义的句柄
typedef QueueHandle_t semaphoreHandle_t,

在程序中定义计数信号量

//定义计数信号量
osSemaphoreId myCountingSem01Handle = NULL;

2、计数信号量创建
函数原型:

Semaphorelandle_t xSemaphoreCreateCounting(UBaseType_t uxllaxCount,/*支持的最大计数值 */UBascTypc_t uxInitialCount);/*初始计数值 */

函数描述:
函数 xSemaphoreCreateCounting 用于创建计数信号量。
第 1个参数是设置此计数信号量支持的最大计数值。
第 2 个参数是设置计数信号量的初始值。这里的初始值设置就是从0到第一个参数设置的最大计数值uxllaxCount
返回值,如果创建成功会返回消息队列的句柄,如果由于 FreeRTOSConfig.h 文件中heap 大小不足,无法为此消息队列提供所需的空间会返回 NULL

应用举例:

myCountingSem01Handle = xSemaphoreCreateCounting(2020)
if(myCountingSem01Handle == NULL)printf("创建计数信号量失败\r\n\r\n");
elseprintf("创建计数信号量成功\r\n\r\n");

3、计数信号量删除
函数原型:

void vSemaphoreDeete(SemaphoreHandle_t xSemaphore); /* 参数为计数信号量句枘 */

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

4、任务中计数信号量释放,当前计数值加加
函数原型:

xSemaphoreGive(SemaphoreHandle_t xSemaphore); /*参数使用计数信号量柄*/

函数描述:
函数 xSemaphoreGive 用于在任务代码中释放信号量。
参数是信号量句柄。
返回值,如果信号量释放成功返回 pdTRUE,否则返回 pdFALSE,因为信号量的实现是基于消息队列,返回失败的主要原因是消息队列已经满了。
使用这个函数要注意以下问题:
1.此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是xSemaphoreGiveFromISR.
2.使用此函数前,一定要保证用函数 xSemaphoreCreateBinary(),xSemaphoreCreate-Mutex() 或者xSemaphoreCreateCounting()创建了信号量。
3.此函数不支持使用 xSemaphoreCreateRecursiveMutex()创建的信号量。
应用举例:

printf("释放计数信号量,模拟车辆出库,让出停位");
xResult=xSemaphoreGive(myCountingSemlHandle);
if(xResult == pdTRUE)
{printf("释放成功,成功让出停车位,发送同步显示信号\r\n");
}
else
{printf("释放失败,停车位已空\r\n");
}

5、中断中计数信号量释放
函数原型:

xSemaphoreGiveFromISR(Semaphorellandle t xSemaphore,/* 信号量句柄*/
signed BaseType_t *pxHigherPriorityTaskWoken /* 高优先级任务是否被唤醒的状态保存 */)

函数描述:
函数 xSemaphoreGiveFromlSR 用于中断服务程序中释放信号量。
第 1个参数是信号量句柄。
第 2 个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 PdTRUE,说明有高优先级任务要执行,否则没有。返回值,如果信号量释放成功返回 pdTRUE,否则返回 errQUEUE FULL
使用这个函数要注意以下问题:
1.此函数是基于消息队列函数 xQueueGiveFromISR 实现的:#define xSemaphore-GiveFromlSR( xSemaphore, pxHigherPriorityTaskWoken ) \xQueueGiveFromlSR( (QueueHandle t )( xSemaphore ),( pxHigherPriorityTaskWoken ))
2.此函数是用于中断服务程序中调用的,故不可以任务代码中调用此函数,任务代码中中使用的是xSemaphoreGive。
3.使用此函数前,一定要保证用函数xSemaphoreCreateBinary()或者xSemaphoreCreateCounting()创建了信号量。
4.此函数不支持使用 xSemaphoreCreateMutex()创建的信号量.

6、计数信号量获取,计数值减减,计数值为0的话就获取不到
函数原型:

xSemaphoreTake( SemaphoreHandle_t xSemaphore,/*信号量句柄*/
TickType_t xTicksToWait ):/*等待信号量可用的最人等待时间 */

函数描述:
函数 xSemaphoreTake 用于在任务代码中获取信号量。
第1个参数是信号量句柄。
第 2 个参数是没有信号量可用时,等待信号量可用的最大等待时间,单位系统时钟节拍。
返回值,如果创建成功会获取信号量返回 pdTRUE,否则返回 pdFALSE。

使用这个函数要注意以下问题:
1.此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序使用的是xSemaphoreTakeFromISR。
2.如果消息队列为空且第 2 个参数为 0,那么此函数会立即返回。
3.如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1且第 2个参数配置为 portMAX_DELAY,那么此函数会永久等待直到信号量可用。

应用举例:

printf("获取计数信号量,拟车辆入库,申请停车位");
xResult=xSemaphoreTake(myCountingSem01Handle,0);  
//返回值为TRUE说明计数值不为0,但此时计数值会减1,为FLASE说明计数值为0,此时其他任务或中断还没有释放计数信号量,需要根据设置的时间进行等待
if(xResult == pdTRUE)
{printf("获取成功,成功申请停车位,发送同步显示信号\r\n");xSemaphoreGive(myBinarysem01Handle);myCountingSem_ucMessagesWaiting--;
}
elseprintf("获取失败,停车位已满\r\n");

计数信号量使用的案例

假设现在停车场有20个停车位

osSemaphoreId myCountingSem01Handle = NULL;
myCountingSem01Handle = xSemaphoreCreateCounting(2020)

这里就是设置第一个参数最大值为20,初始值为20
当有车要进来的时候,就会获取信号量(计数值减一),当有车出去的时候就会释放信号量(信号量加一)
这里为了方便查看还有多少个空位置,见了一个初始值为20的myCountingSem_ucMessagesWaiting变量,这个变量的值会在显示屏显示出来,当有车要进来的时候计数信号量获取会减减,此时会将这个变量减1,相反车出去时会加一,但是有一个问题,这个显示在另外一个任务中实现的,所以就需要使用二值信号量进行同步保护
按键检测任务

extern int myCountingSem_ucMessagesWaiting;  //外部引用
//KEY3处理
if(KEY.KeyCode == KEY3)
{printf("获取计数信号量,模拟车辆入库,申请停车位");xResult =xSemaphoreTake(myCountingSem01Handle,0);if(xResult == pdTRUE){printf("获取成功,成功申请停车位,发送同步显示信号\r\n");xSemaphoreGive(myBinarySem01Handle);  //使用二值信号量保护当前空余位置数量myCountingSem_ucMessagesWaiting--;}elseprintf("获取失败,停车位已满\r\n");
}
//KEY4处理
if(KEY.KeyCode == KEY4)
{printf("释放计数信号量,模拟车辆出库,让出停车位");xResult=xSemaphoreGive(myCountingSem01Handle);if(xResult == pdTRUE){printf("释放成功,成功让出停车位,发送同步显示信号\r\n");xSemaphoreGive(myBinarysem1Handle);myCountingSem_ucMessagesWaiting++;}elseprintf("释放失败,停车位已空\r\n");
}
int myCountingSem_ucMessagesWaiting;
void play()
{while(1){BaseType_t xResult;//获取二值信号量,成功会让二值信号量变为0,成功说明获取到了,如果为0,就需要等待其他任务或者中断将二值信号量释放xResult = xSemaphoreTake(myBinarySem01Handle,portMAX DELAY);  if(xResult == pdTRUE){screen_play(myCountingSem_ucMessagesWaiting);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/61593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Profinet转EtherNet/IP网关是如何解决西门子S7-1500PLC与AB PLC的通讯问题的

一、 案例背景 在一个工业现场,一端是AB的PLC,IP地址192.168.1.20;另一端西门子是S7-1500系列,IP地址192.168.2.248。AB的PLC内有 B3、N7、F8 三个寄存器文件涉及到通讯,分别对应西门子PLC的M、DB1、DB2三个存储区域。通过捷米特…

【C语言】扫雷游戏(一)

我们先设计一个简单的9*9棋盘并有10个雷的扫雷游戏。 1,可以用数组存放,如果有雷就用1表示,没雷就用0表示。 2,排查(2,5)这个坐标时,我们访问周围的⼀圈8个位置黄色统计周围雷的个数是1。排查(8,6)这个坐标时&#xf…

Unity开发FPS游戏之完结篇

这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏,感兴趣的朋友可以回顾一下。这个系列的文章如下: Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…

浅析RPC—基础知识

该文章会简单介绍一下 RPC 相关的基础概念。 什么是RPC? RPC(Remote Procedure Call) 即远程过程调用,通过名字我们就能看出 RPC 关注的是远程调用而非本地调用。 为什么要 RPC ? 因为,两个不同的服务器…

mysql数据库varchar截断问题

用了这么多年mysql数据库,才发现varchar是可以截断的,而且是在我们线上数据库。个人觉得dba的这个设置是非常有问题的,用户往数据库里存东西,就是为了以后用的,截断了存放,数据不完整,就用不了了…

EwoMail邮箱服务器软件安装教程

EwoMail是基于Linux的开源邮件服务器软件,集成了众多优秀稳定的组件,是一个快速部署、简单高效、多语言、安全稳定的邮件解决方案,帮助你提升运维效率,降低 IT 成本,兼容主流的邮件客户端,同时支持电脑和手机邮件客户端。 一、系统版本 二、关闭selinux vi /etc/sysconf…

【机器学习】机器学习的基本分类-监督学习-支持向量机(Support Vector Machine, SVM)

支持向量机是一种强大的监督学习算法,主要用于分类问题,但也可以用于回归和异常检测。SVM 的核心思想是通过最大化分类边界的方式找到数据的最佳分离超平面。 1. 核心思想 目标 给定训练数据 ,其中 是特征向量, 是标签&#xf…

Linux命令进阶·如何切换root以及回退、sudo命令、用户/用户组管理,以及解决创建用户不显示问题和Ubuntu不显示用户名只显示“$“符号问题

目录 1. root用户(超级管理员) 1.1 用于账户切换的系统命令——su 1.2 退回上一个用户命令——exit 1.3 普通命令临时授权root身份执行——sudo 1.3.1 为普通用户配置sudo认证 2. 用户/用户组管理 2.1 用户组管理 2.2 用户管理 2.2.1 …

Zero to JupyterHub with Kubernetes中篇 - Kubernetes 常规使用记录

前言:纯个人记录使用。 搭建 Zero to JupyterHub with Kubernetes 上篇 - Kubernetes 离线二进制部署。搭建 Zero to JupyterHub with Kubernetes 中篇 - Kubernetes 常规使用记录。搭建 Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s。 参考&…

《Python基础》之Python中可以转换成json数据类型的数据

目录 一、JSON简介 JSON有两种基本结构 1、对象(Object) 2、数组(Array) 二、将数据装换成json数据类型方法 三、在Python中,以下数据类型可以直接转换为JSON数据类型 1、字典(Dictionary&#xff09…

若依项目源码阅读

源码阅读 前端代码分析 代码生成器生成的前端代码有两个,分别是course.js用于向后端发送ajax请求的接口代码,另一个是index.vue,用于在浏览器展示课程管理的视图组件。前端的代码是基于vue3elementplus。 template用于展示前端组件别的标签…

C#tabcontrol如何指定某个tabItem为默认页

// Selects tabPage2 using SelectedTab.this.tabControl1.SelectedTab tabPage2; 参考链接 TabControl.SelectedTab 属性 (System.Windows.Forms) | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/api/system.windows.forms.tabcontrol.selectedtab?viewnetfr…

文件比较和文件流

文件比较和文件流 一、文本比较工具 diff1.基本用法1.1输出格式 2.常用选项 二、文件流1.文件的打开模式2.文件流的分类ifstreamofstreamfstrem区别 3.文件流的函数1. 构造函数2. is_open 用于判断文件是否打开3. open4. getline5. close6. get()7. read8. write9. put10. gcou…

【网络篇】HTTP知识

键入网址到网页显示,期间发生了什么? 浏览器第一步是解析URL,这样就得到了服务器名称和文件的路径名,然后根据这些信息生成http请求,通过DNS查询得到我们要请求的服务器地址,然后添加TCP头、IP头以及MAC头&…

【解决安全扫描漏洞】---- 检测到目标站点存在 JavaScript 框架库漏洞

1. 漏洞结果 JavaScript 框架或库是一组能轻松生成跨浏览器兼容的 JavaScript 代码的工具和函数。如果网站使用了存在漏洞的 JavaScript 框架或库,攻击者就可以利用此漏洞来劫持用户浏览器,进行挂马、XSS、Cookie劫持等攻击。 1.1 漏洞扫描截图 1.2 具体…

互联网基础

TCP/IP协议(协议组) 分层名称TCP/IP协议应用层HTTP,FTP,mDNS,WebSocket,OSC...传输层TCP,UDP网络层IP链路层(网络接口层)Ethernet,Wi-Fi... 链路层(网络接口层) 链路层的主要作用…

【分组去重】.NET开源 ORM 框架 SqlSugar 系列

💥 .NET开源 ORM 框架 SqlSugar 系列 🎉🎉🎉 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列…

hdlbits系列verilog解答(Exams/m2014 q4d)-89

文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 本节实现以下电路。 模块声明 module top_module ( input clk, input in, output out); 思路: 它的输入是一个组合逻辑异或门,将输入和输出异或后输入D触发器,这意味着输出与历史输出及当前输入都有关系,…

Cesium K-means自动聚合点的原理

Cesium K-means自动聚合点的原理 Cesium 是一个开源的 JavaScript 库,用于在 Web 环境中创建 3D 地球和地图应用。它能够处理地理空间数据,并允许开发者对大规模的地理数据进行可视化展示。在一些应用中,尤其是当处理大量地理坐标点时&#…

Kafka如何保证消息可靠?

大家好,我是锋哥。今天分享关于【Kafka如何保证消息可靠?】面试题。希望对大家有帮助; Kafka如何保证消息可靠? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka通过多种机制来确保消息的可靠性,主要包…