FreeRTOS操作系统学习


前言

信号量的目的:

1.共享资源访问
2.与任务同步

FreeRTOS信号量分为:

1.二值信号量
2.计数型信号量
3.互斥信号量
4.递归互斥信号量

所有的信号量都是使用队列来实现的。

一、信号量简介

信号量常常用于控制对共享资源的访问和任务同步。举一个很常见的例子,某个停车场有100 个停车位,这 100 个停车位大家都可以用,对于大家来说这 100 个停车位就是共享资源。假设现在这个停车场正常运行,你要把车停到这个这个停车场肯定要先看一下现在停了多少车了?还有没有停车位?当前停车数量就是一个信号量,具体的停车数量就是这个信号量值,当这个值到 100 的时候说明停车场满了。停车场满的时你可以等一会看看有没有其他的车开出停车场,当有车开出停车场的时候停车数量就会减一,也就是说信号量减一,此时你就可以把车停进去了,你把车停进去以后停车数量就会加一,也就是信号量加一。这就是一个典型的使用信号量进行共享资源管理的案例,在这个案例中使用的就是计数型信号量。

再看另外一个案例:
使用公共电话,我们知道一次只能一个人使用电话,这个时候公共电话就只可能有两个状态:
使用或未使用,如果用电话的这两个状态作为信号量的话,那么这个就是二值信号量。

信号量用于控制共享资源访问的场景相当于一个上锁机制,代码只有获得了这个锁的钥匙才能够执行。

信号量的另一个重要的应用场合就是任务同步,用于任务与任务或中断与任务之间的同步。在执行中断服务函数的时候可以通过向任务发送信号量来通知任务它所期待的事件发生了,当退出中断服务函数以后在任务调度器的调度
下同步的任务就会执行。

二、二值信号量简介

二值信号量通常用于互斥访问或同步,二值信号量和互斥信号量非常类似,但是还是有一些细微的差别,互斥信号量拥有优先级继承机制,二值信号量没有优先级继承。因此二值信号量更适合用于同步(任务与任务或任务与中断的同步),而互斥信号量适合用于简单的互斥访问。

和队列一样,信号量 API 函数允许设置一个阻塞时间,阻塞时间是当任务获取信号量的时候由于信号量无效从而导致任务进入阻塞态的最大时钟节拍数。如果多个任务同时阻塞在同一一个信号量上的话那么优先级最高的哪个任务优先获得信号量,这样当信号量有效的时候高优先级的任务就会解除阻塞状态。

二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

1.二值信号量的使用

2.创建二值信号量

vSemaphoreCreateBinary ()
动态创建 二 值 信 号 量 , 这 个 是 老 版 本
FreeRTOS 中使用的创建二值信号量的 API 函
数。(已经不使用了)
xSemaphoreCreateBinary()
动态创建二值信号量,新版 FreeRTOS 使用此
函数创建二值信号量。
xSemaphoreCreateBinaryStatic() 静态创建二值信号量。

函数 xSemaphoreCreateBinary()

使用此函数创建二值信号量的话信号量所需要的 RAM 是由 FreeRTOS 的内存管理部分来动态分配的。此函数创建好的二值信号量默认是空的,也就是说刚创建好的二值信号量使用函数 xSemaphoreTake()是获取不到的

SemaphoreHandle_t xSemaphoreCreateBinary( void )

返回值
NULL: 二值信号量创建失败。
其他值: 创建成功的二值信号量的句柄。

3.释放二值信号量

xSemaphoreGive() 任务级信号量释放函数
xQueueGiveFromISR()。中断级信号量释放函数

1、函数 xSemaphoreGive()
此函数用于释放二值信号量、计数型信号量或互斥信号量
阻塞时间为 0(宏 semGIVE_BLOCK_TIME 为 0),入队方式采用的后向入队。

BaseType_t xSemaphoreGive( xSemaphore )

参数:
xSemaphore:要释放的信号量句柄。
返回值:
pdPASS: 释放信号量成功。
errQUEUE_FULL: 释放信号量失败。

2、函数 xSemaphoreGiveFromISR()
此函数用于在中断中释放信号量,此函数只能用来释放二值信号量和计数型信号量,绝对不能用来在中断服务函数中释放互斥信号量!

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
 BaseType_t * pxHigherPriorityTaskWoken)

4.获取信号量

xSemaphoreTake() 任务级获取信号量函数
xSemaphoreTakeFromISR() 中断级获取信号量函数

同释放信号量的 API 函数一样,不管是二值信号量、计数型信号量还是互斥信号量,它们都使用以上两个函数获取信号量

1、函数 xSemaphoreTake()
此函数用于获取二值信号量、计数型信号量或互斥信号量

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,
 TickType_t xBlockTime)

xSemaphore:要获取的信号量句柄。
xBlockTime: 阻塞时间。
返回值:
pdTRUE: 获取信号量成功。
pdFALSE: 超时,获取信号量失败。

2、函数 xSemaphoreTakeFromISR ()
此函数用于在中断服务函数中获取信号量,此函数用于获取二值信号量和计数型信号量,绝 对 不 能 使 用 此 函 数 来 获 取 互 斥 信 号 量 !

BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
 BaseType_t * pxHigherPriorityTaskWoken)

参数:
xSemaphore: 要获取的信号量句柄。
pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换,这个变量的值由这三个函数来设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
pdPASS: 获取信号量成功。
pdFALSE: 获取信号量失败。

三、二值信号量实验

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
第一步:创建二值信号量
第二步:发送信号量
第三步:接收数据量
其代码结构就是以上三点,什么情况下发送,接收了后任务要执行什么功能等等

总结

信号量是连接任务与任务之间的桥梁,可以进行资源的访问与同步。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐