FreeRTOS(计数信号量)

FreeRTOS计数信号量详解:多任务间的资源管理
本文详细介绍了FreeRTOS中的计数信号量,包括其定义、应用、运作机制和常用API函数,重点展示了如何在多任务环境中管理资源,如停车场车位的模拟例子。

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

目录

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

1、计数信号量的定义

2、计数信号量的应用

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

1、任务间计数信号量的实现

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

 1、计数信号量典型流程与API函数

2、计数信号量创建与删除

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

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

5、计数信号量获取

四、计数信号量编程

1、启用计数信号量

 2、创建计数信号量

 3、重要代码


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

1、计数信号量的定义

①取值只有0与1两种状态的信号量称之为二值信号量;取值大于1的信号量称之为计数信号量

②计数信号量是一种长度大于1,消息大小为0的特殊消息队列。  

③计数信号量的取值也可以为1,但通常大于1,如果取值为1,相当于只有0与1两种状态,用二值信号量即可。

④创建计数信号量时,系统会为创建的计数信号量分配内存,计数信号量创建完成后的示意图如下:

图片

2、计数信号量的应用

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

应用场景:

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

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

1、任务间计数信号量的实现

任务间信号量的实现是指各个任务之间使用信号量实现任务的同步或者资源共享功能。

①运行条件:

 创建 任务 Task1 和 Task2至N。 

 创建计数信号量可用资源为N。

②运行过程描述如下:

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

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

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

 1、计数信号量典型流程与API函数

创建计数信号量   xSemaphoreCreateCounting()

释放计数信号量   xSemaphoreGive() 与 xSemaphoreGiveFromISR() 

获取计数信号量   xSemaphoreTake()

删除计数信号量    vSemaphoreDelete()

2、计数信号量创建与删除

①计数信号量控制块(句柄)

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

### FreeRTOS 计数信号量的使用教程 #### 什么是计数信号量计数信号量是一种用于任务间通信和同步的机制。它允许多个任务等待同一个事件的发生,并且可以通过增加或减少信号量的值来进行控制[^1]。 #### 创建计数信号量FreeRTOS 中,`xSemaphoreCreateCounting` 函数用于创建一个计数信号量。其原型如下: ```c SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); ``` - `uxMaxCount`: 表示信号量的最大计数值。 - `uxInitialCount`: 表示信号量的初始计数值。 当调用这个函数时,如果成功,则返回一个有效的句柄;否则返回 NULL[^3]。 #### 删除计数信号量 通过 `vSemaphoreDelete` 可以删除不再使用的信号量对象。这有助于释放内存资源。 ```c void vSemaphoreDelete(SemaphoreHandle_t xSemaphore); ``` #### 增加计数信号量 要向计数信号量添加单位数量,可以使用 `xSemaphoreGive` 或者 `xSemaphoreGiveFromISR`(如果是从中断上下文中操作)。这些函数会尝试将信号量计数器增一。 ```c BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore); ``` 对于中断环境下的情况: ```c BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken); ``` #### 获取计数信号量 为了消耗或者占用一个单位的数量,可采用 `xSemaphoreTake` 方法。此方法会在指定时间内阻塞当前的任务直到获得信号量为止。 ```c BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait); ``` 同样地,在中断环境中应该使用 `xSemaphoreTakeFromISR`. ```c BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken); ``` #### 示例代码 下面展示了一个简单的例子,演示如何利用计数信号量实现两个任务间的同步。 ```c #include "FreeRTOS.h" #include "task.h" #include "semphr.h" // 定义全局变量存储信号量句柄 SemaphoreHandle_t xBinarySemaphore; void TaskA(void* pvParameters){ while(1){ // 执行某些工作... // 发送信号给其他任务 if(xSemaphoreGive(xBinarySemaphore) != pdTRUE){ // 错误处理逻辑 } vTaskDelay(pdMS_TO_TICKS(100)); // 模拟延迟 } } void TaskB(void* pvParameters){ while(1){ // 等待来自另一个任务的通知 if(xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdFALSE){ // 超时错误处理 }else{ // 收到通知后的动作 } vTaskDelay(pdMS_TO_TICKS(200)); } } int main(){ // 初始化硬件... // 创建二进制信号量 xBinarySemaphore = xSemaphoreCreateCounting(1, 0); if(xBinarySemaphore != NULL){ xTaskCreate(TaskA,"Task A",configMINIMAL_STACK_SIZE,NULL,tskIDLE_PRIORITY+1,NULL); xTaskCreate(TaskB,"Task B",configMINIMAL_STACK_SIZE,NULL,tskIDLE_PRIORITY+1,NULL); vTaskStartScheduler(); } for(;;){} // 如果调度失败则进入死循环 } ``` 上述程序展示了如何设置一个基本的任务同步场景,其中 `TaskA` 和 `TaskB` 使用计数信号量进行协调[^4]。 --- ### 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhang丶&|!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值