FreeRTOS 实时操作系统第十二讲 - 计数信号量

一、信号量的概念

1、信号量的基本概念

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

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

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

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

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

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

2、信号量的分类

  1. 二值信号量 (重点讲解同步应用)
  2. 技术信号量 (重点讲解资源管理)
  3. 互斥信号量 (重点讲解互斥访问)
  4. 递归互斥信号量 (简要了解即可)

二、计数信号量的定义与应用

1、计数信号量的定义

  取值只有 0 与 1 两种状态的信号量称之为二值信号量
  取值大于 1 的信号量称之为计数信号量
  Note:计数信号量的取值也可以为 1,但通常大于 1,如果取值为 1,相当于只有 0 与 1 两种状态,用二值信号量即可。
  创建计数信号量时,系统会为创建的计数信号量分配内存,计数信号量创建完成后的示意图如下:

  从上图可以看出,计数信号量是一种长度大于 1,消息大小为 0 的特殊消息队列。

  因为这个队列的消息大小为 0,因此在运用时,只需要知道队列中是否有消息即可,而无需关注消息是什么。

2、计数信号量的应用

  在嵌入式操作系统中,计数信号量是资源管理的重要手段,主要用于任务与任务间。

应用场景:

  计数信号量允许多个任务对其进行操作,但限制了任务的数量。比如有一个停车场,里面只有 50 个车位,那么只能停 50 辆车,相当于我们的信号量有 50 个。假如一开始停车场的车位还有 50 个,那么每进去一辆车就要消耗一个停车位,车位的数量就要减 1,相应地,我们的信号量在使用之后也需要减 1。当停车场停满了 50 辆车时,此时的停车位数量为 0,再来的车就不能停进去了,否则将没法停车了,也相当于我们的信号量为 0,后面的任务对这个停车场资源的访问也无法进行。当有车从停车场离开时,车位又空余出来了,那么后面的车就能停进去了。信号量操作也是一样的,当我们释放了这个资源,后面的任务才能对这个资源进行访问。

三、计数信号量的运作机制

FreeRTOS 任务间计数信号量的实现

  任务间信号量的实现是指各个任务之间使用信号量实现任务的同步或者资源共享功能。下面我们通过如下的框图来说明一下 FreeRTOS 计数信号量的实现,让大家有一个形象的认识。


运行条件:

  1. 创建 任务 Task1 和 Task2 至 N。
  2. 创建计数信号量可用资源为 N。

运行过程描述如下:

  • 任务 Task1 运行过程中调用函数 xSemaphoreTake 获取信号量资源,如果信号量大于 0,Task1 将直接获取资源。如果信号量为 0,任务 Task1 将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数 xSemaphoreGive 释放掉资源。

  • 任务 Task2 至 N 运行过程中调用函数 xSemaphoreTake 获取信号量资源,如果信号量大于 0,Task2 至 N 将直接获取资源。如果信号量为 0,任务 Task2 至 N 将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数 xSemaphoreGive 释放掉资源。

上面就是一个简单的 FreeRTOS 任务间计数信号量的使用过程。

四、计数信号量常用的 API 函数

1、使用计数信号量的典型流程如下:

  1. 创建计数信号量
  2. 释放计数信号量
  3. 获取计数信号量
  4. 删除计数信号量

2、常用 API 函数如下:

  1. xSemaphoreCreateCounting()
  2. xSemaphoreGive() 与 xSemaphoreGiveFromISR()
  3. xSemaphoreTake()
  4. vSemaphoreDelete()

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

二值信号量控制块 (句柄)

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

计数信号量创建

函数原型:

SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, /* 支持的最大计数值 */                             UBaseType_t uxInitialCount); /* 初始计数值 */

函数描述:
  函数 xSemaphoreCreateCounting 用于创建计数信号量。

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

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

应用举例:

计数信号量删除

函数原型:

void vSemaphoreDelete(void)

函数描述:

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

4、任务中计数信号量释放

函数原型:

xSemaphoreGive(SemaphoreHandle_t xSemaphore); /* 信号量句柄 */

函数描述:

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

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

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

  1. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是 xSemaphoreGiveFromISR。
  2. 使用此函数前,一定要保证用函数 xSemaphoreCreateBinary(), xSemaphoreCreateMutex() 或者 xSemaphoreCreateCounting() 创建了信号量。
  3. 此函数不支持使用 xSemaphoreCreateRecursiveMutex() 创建的信号量。

应用举例:

5、中断中计数信号量释放

函数原型:

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 () 创建的信号量。

6、计数信号量获取

函数原型:

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,那么此函数会永久等待直到信号量可用。

应用举例:

五、技术信号量的应用编程

视频讲解

串口输出信息:

STM32cubeMX 配置:



代码:


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

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

相关文章

银河麒麟Kylin-Server-V10-SP3使用ISO镜像搭建本地内网YUM/DNF源cdrom/http

机房服务器安装一般是内网环境,需要配置本地的YUM/DNF源。本文介绍通过ISO镜像搭建内网环境的UM/DNF源 准备工作: 提前准备好Kylin-Server-V10-SP3的ISO镜像文件。 本机IP地址:192.168.40.201 镜像存放目录/data/iso/Kylin-Server-V10-SP3-Ge…

Linux-端口、nmap命令、netstat命令

端口是设备与外界通讯交流的出入口,可分为物理端口和虚拟端口 物理端口实际存在可以看见,而虚拟端口是指计算机内部的端口,是不可见的,用来操作系统和外部交互使用。 IP地址不能锁定程序,所以可以通过端口&#xff0…

原生微信小程序如何动态修改svg图片颜色及尺寸、宽高(封装svgIcon组件)解决ios不显示问题

最终效果 前言 动态设置Svg图片颜色就是修改Svg源码的path中的fill属性, 通过wx.getFileSystemManager().readFile读取.xlsx文件 ios不显示需要把encoding设置 binary 把文件转成base64 封装svg-icon组件 1、在项目的components下新建svg-icon文件夹,新…

OA系统与工单系统的区别:功能、应用与优势对比

很多企业在选购系统的时候会陷入选择困难症的漩涡。市面上的各种系统,比如ERP系统、OA系统、工单系统等等让人眼花缭乱。想要选择一款合适的系统,前提是明确地知道自己需要用它来做什么,其次去了解每个系统的应用场景、功能等是否与自己的需求…

自动驾驶感知-预测-决策-规划-控制学习(3):感知方向文献阅读笔记

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、文章主题二、摘要阅读1.名词理解①点云是什么?②二维图像分割器③轻量化卷积网络提取特征④单模态表达和多模态特征融合的区别⑤基于ROS的多传感…

jetson deepstream 解码接入编码输出

不需要编解码输出画面的直接到7 使用就行 1 jetson主板编译工具 在jetson主板上安装gstreamer工具链,编译opencv sudo apt install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-rtsp python3-dev pytho…

安全与认证Week3 Tutorial+历年题补充

目录 1) 什么是重放攻击? 2)什么是Kerberos系统?它提供什么安全服务? 3)服务器验证客户端身份的一种简单方法是要求提供密码。在Kerberos中不使用这种身份验证,为什么?Kerberos如何对服务器和客户机进行身份验证? 4) Kerberos的四个要求是什么?Kerberos系…

C++日期类的实现

前言:在类和对象比较熟悉的情况下,我们我们就可以开始制作日期表了,实现日期类所包含的知识点有构造函数,析构函数,函数重载,拷贝构造函数,运算符重载,const成员函数 1.日期类的加减…

JetBrains Rider使用总结

简介: JetBrains Rider 诞生于2016年,一款适配于游戏开发人员,是JetBrains旗下一款非常年轻的跨平台 .NET IDE。目前支持包括.NET 桌面应用、服务和库、Unity 和 Unreal Engine 游戏、Xamarin 、ASP.NET 和 ASP.NET Core web 等多种应用程序…

面试题--消失的两个数字(困难)

个人主页:Lei宝啊 愿所有美好如期而遇 目录 本题链接 输入描述 输出描述 算法分析 触类旁通一:消失的数字 题目分析 图示 解题源码 触类旁通二:只出现一次的数字III 题目分析 图示 解题源码 本题分析 解题源码 本题链接 力…

Linux第19步_安装“Ubutun交叉编译工具链”

由于Ubuntu系统使用的GCC编译器,编译结果是X86文件,只能在X86上运行,不能在ARM上直接运行。因此,还要安装一个“Ubutun交叉编译工具链”,才可以在ARM上运行。 arm-none-linux-gnueabi-gcc是 Codesourcery 公司&#x…

PHP语言B/S架构医院(安全)不良事件上报系统源码

医院安全(不良)事件上报系统采用无责的、自愿的填报不良事件方式,有效地减轻医护人员的思想压力,实现以事件为主要对象,可以自动、及时、实际地反应医院的安全、不良、近失事件的情况,更好地掌握不良事件的…

【Docker】docker 服务相关命令

目录 1. 启动docker 服务 2.查看docker 服务的状态 3. 停止docker 服务 4.重启 docker 服务 5.开机自启动命令 1. 启动docker 服务 systemctl start docker 2.查看docker 服务的状态 systemctl status docker 3. 停止docker 服务 systemctl stop docker 此时再使用 syst…

C++八股学习心得.5

1.基类 & 派生类 一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下: class derived-class: acce…

网络摄像机的网络连接

网络摄像机的网络连接 1. 网络连接2. 网络直通线和网络交叉线的制作方法References 1. 网络连接 网络摄像机完成安装后,需要进行功能的配置及参数的设置,您可以通过浏览器进行相关功能的配置。 有线网络连接 左侧为通过网络直通线连接的示意图&#x…

阿里云服务器Centos安装宝塔面板

阿里云服务器Centos安装宝塔面板 1 背景1.1 aliyun1.2 Linux 2 安装步骤2.0 环境配置2.1 安装前准备2.2 宝塔安装2.3 建站 3 centos常用命令3.1 防火墙相关 1 背景 1.1 aliyun 阿里云服务器是阿里云提供的一项云计算服务,它能够帮助用户快速搭建网站、应用和服务&…

模板模式实现分布式锁实战

前言 分布式锁相信大家都有用过,常见的分布式锁实现方式例如redis、zookeeper、数据库都可以实现,而我们代码中强引用这些分布式锁的代码,那么当我们以后想替换分布式锁的实现方式时,需要修改代码的成本会很高,于是我…

OpenCV图像处理|1.1 OpenCV介绍与环境搭建

1.1.1 介绍 OpenCV(Open Source Computer Vision Library)开放源代码计算机视觉库,主要算法涉及图像处理、计算机视觉和机器学习相关方法。OpenCV 其实就是一堆 C 和 C语言的源代码文件,这些源代码文件中实现了许多常用的计算机视…

安装PyTorch及环境配置(应用于Python上的YOLO)

这个基本都是Bilibili网站里面叫“小手丫子”up的视频教程,此前自己需要装了好几次又卸载了好几次,现在根据视频教学整理出来自己所理解的文档。 注意事项 1.安装的pycharm版本和anaconda版本无要求。 2.运行pycharm尽量以管理员身份运行。 3.Cuda是独…

AWTK 开源串口屏开发(5) - MCU端 SDK 用法

AWTK 开源智能串口屏,不但开放了串口屏端全部源码,还提供了MCU 端 SDK,大大加快 MCU 软件的开发。本介绍一下 MCU 端 SDK 在不同平台上的用法。 完整示例可以参考下面的几个例子: 普通嵌入式系统 mcu/stm32/hmi_app/hmi_app.c 低…