FreeRtos信号量

一、信号量的基本概念

        FreeRtos信号量包括二值信号量、计数型信号量、互斥信号量和递归互斥信号量。 信号量用于实现任务间的同步或临界资源的互斥访问《相当于一个上锁机制,代码只有获得了这个锁的钥匙才能够执行。信号量类似于我们在裸机编写中断服务函数中给予标志位赋值的操作,然后根据标志位所对应的函数让其执行。当某个任务需要获得对应的指令才能开始执行时,因为主程序不可能一直等待对应指令的产生而不去执行其它的任务,这时信号量便可保证其它任务能够正常运行的同时也能兼顾到指令一旦发出对应程序能够立马执行。在使用Rtos系统时我们可以借助信号量来完成这个操作,当中断发生的时候就释放信号量,中断服务函数不作任何处理,当任务获取到信号量的时候,就会开始完成对相应任务的处理。这样做的好处是中断执行时间非常短且更节省内存。信号量的使用不仅使用与任务与中断之间的同步,也可以同时实现任务与任务之间的同步。 

1.二值信号量

        二值信号量(Binary Semaphore)是一种特殊的信号量,其值只能为0或1,0代表获取,1代表释放,因此也被称为互斥二进制信号量(尽管它与传统的互斥锁或互斥量在细节上有所不同)。二值信号量在操作系统、嵌入式系统以及多任务环境中被广泛应用,主要用于任务同步、中断同步以及控制对共享资源的访问。任务同步:信号量在刚被创建时置为空,任务一未获取到信号量而处于阻塞状态,当任务二在某种条件成立下而开始执行并释放信号量,此时任务一获取到信号量由阻塞态阻塞态转为就绪态。如果任务一的优先级是最高的,那么任务会立马执行,从而达到两个任务间的同步。同样的,在中断 服务函数中释放信号量,任务 1 也会得到信号量,从而达到任务与中断间的同步。在FreeRtos当中可以将二值信号量看作一个消息队列,无需关心消息的内容,只需查看队列内是否有消息即可。

二.计数信号量

        计数信号量类似于公共停车场,该停车场有50个车位可以供车辆停车,停车场每停放一辆汽车,停车场便减少一个车位,直到停满50辆汽车,该停车场便无法容纳更多车辆。FreeRtos中的计数信号量亦是如此,一个个信号量视为一辆辆汽车,当任务执行时会取走对应的信号量,车辆驶出停车场时,原本的计数值对应减一,停车场的停车位就空出一个。当计数值为50代表着可容纳50个信号量,0个则代表着无位置可容纳更多的信号量,也就代表着系统没有更多的资源给任务去使用,停车场没有更多停车位给其他车辆停放。

三.互斥信号量

        互斥信号量是特殊的二值信号量,其特有的优先级继承制机制从而使它更适用于简单的互锁,也就是保护临界资源。(临界资源是指任何时刻都只允许一个任务进行访问),当任务需要访问临界资源时,先获取互斥信号量,使其为空,这样可以使其它任务要使用临界资源时无法获取到信号量而进入阻塞,从而保证了临界资源的单一任务访问。当任务在访问临界资源时,就会给临界资源建立一个标志位,当其它任务想要使用临界资源时会先查询这个标志位,若该标志位不为空则代表临界资源正在被占用,其它任务则进入阻塞态,这样使临界资源得到有效的保护。

4.递归信号量     

        递归信号量,见文知义,递归嘛,就是可以重复获取调用的,本来按照信号量的特性, 每获取一次可用信号量个数就会减少一个,但是递归则不然,对于已经获取递归互斥量的任务可以重复获取该递归互斥量,该任务拥有递归信号量的所有权。任务成功获取几次递 归互斥量,就要返还几次,在此之前递归互斥量都处于无效状态,其他任务无法获取,只 有持有递归信号量的任务才能获取与释放。

二、二值信号量的运作机制

        当任务获取想要信号量时,若获取的信号量无效,则说明对应的任务或中断未释放信号量,此时获取信号的任务就处于阻塞态,若对应的任务或中断释放信号量,则该任务获取到信号量便由阻塞态转为就绪态,若该任务的优先级最高则开始执行。

 

                                                图1———信号量无效

                                                图2———信号量有效

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

        计数信号量可以运用于资源管理,允许多个任务获取信号量来访问共享资源,但会限制最大任务访问数目。当任务访问的数目达到最大值,则会阻塞其它任务通过获取信号量来访问共享资源,直到正在访问资源的任务释放信号量结束对共享资源的访问,此时其它的任务才能通过获取信号量来访问共享资源。

<think>我们正在讨论FreeRTOS信号量的使用。根据引用内容,信号量FreeRTOS中用于任务间同步和资源管理的重要机制。引用[1]提到信号量可以解决资源共享和任务同步问题,引用[4]详细解释了信号量的P、V操作(即获取和释放)。此外,引用[3]和引用[5]提供了创建和删除信号量的函数示例。用户要求提供使用教程和示例代码。因此,我将按照以下步骤组织回答:1.介绍信号量的基本概念和类型(二进制信号量、计数信号量)。2.说明如何创建信号量。3.展示如何在任务中获取(take)和释放(give)信号量。4.提供示例代码,展示信号量用于资源管理和任务同步的两种典型场景。5.注意事项(如避免优先级反转、正确删除信号量等)。根据引用[2],需要注意互斥信号量和二进制信号量的区别:互斥信号量具有优先级继承,且必须归还;而用于同步的信号量通常获取后不归还(取决于设计)。引用[5]提供了删除信号量的函数。下面开始逐步回答:</think>### FreeRTOS 信号量使用教程 #### 一、信号量基础概念 信号量FreeRTOS 实现**任务同步**和**资源共享**的核心机制,本质是带保护的计数器。主要类型包括: 1. **二进制信号量**:值仅 0 或 1,用于互斥访问(如共享外设) 2. **计数信号量**:值 ≥0,用于资源池管理(如缓冲区槽位) 3. **互斥信号量**:带优先级继承的二进制信号量,解决优先级反转问题[^2] 信号量操作遵循 **P/V 操作**原则: - **P 操作 (xSemaphoreTake)**:申请资源,信号量值减 1 - **V 操作 (xSemaphoreGive)**:释放资源,信号量值加 1 当信号量为负时,表示等待资源的任务数量[^4] --- #### 二、关键 API 函数 | 函数 | 作用 | 参数说明 | |------|------|----------| | `xSemaphoreCreateBinary()` | 创建二进制信号量 | 返回信号量句柄 | | `xSemaphoreCreateCounting(uxMaxCount, uxInitialCount)` | 创建计数信号量 | 最大计数值/初始值 | | `xSemaphoreTake(xSemaphore, xBlockTime)` | 获取信号量 | 阻塞时间(ticks) | | `xSemaphoreGive(xSemaphore)` | 释放信号量 | - | | `vSemaphoreDelete(xSemaphore)` | 删除信号量 | - | --- #### 三、典型应用场景与示例代码 ##### 场景 1:资源互斥(二进制信号量) 保护 UART 串口避免多任务同时写入: ```c SemaphoreHandle_t uartMutex; // 全局信号量句柄 void Task1(void *params) { while(1) { if(xSemaphoreTake(uartMutex, portMAX_DELAY)) { HAL_UART_Transmit(&huart1, "Task1\n", 6, 100); xSemaphoreGive(uartMutex); // 必须释放! } vTaskDelay(pdMS_TO_TICKS(100)); } } void main() { uartMutex = xSemaphoreCreateBinary(); xSemaphoreGive(uartMutex); // 初始化为可用状态 xTaskCreate(Task1, "Task1", 128, NULL, 2, NULL); vTaskStartScheduler(); } ``` > 📌 **关键点**:互斥信号量使用后必须释放[^2],否则会导致死锁 ##### 场景 2:任务同步(计数信号量) 生产者-消费者模型: ```c #define BUFFER_SIZE 5 SemaphoreHandle_t dataSemaphore; void ProducerTask(void *params) { while(1) { produce_data(); // 生产数据 xSemaphoreGive(dataSemaphore); // 释放信号量(资源+1) vTaskDelay(pdMS_TO_TICKS(200)); } } void ConsumerTask(void *params) { while(1) { if(xSemaphoreTake(dataSemaphore, portMAX_DELAY)) { consume_data(); // 消费数据 } } } void app_main() { // 创建计数信号量(最大5,初始0) dataSemaphore = xSemaphoreCreateCounting(BUFFER_SIZE, 0); xTaskCreate(ProducerTask, "Prod", 128, NULL, 1, NULL); xTaskCreate(ConsumerTask, "Cons", 128, NULL, 2, NULL); } ``` > ⚡ **同步机制**:生产者释放信号量唤醒消费者,初始值 0 使消费者阻塞直至数据就绪[^3] --- #### 四、最佳实践 1. **超时设置**:避免永久阻塞,例如 `xSemaphoreTake(sem, pdMS_TO_TICKS(100))` 2. **优先级继承**:互斥场景优先使用 `xSemaphoreCreateMutex()` 3. **中断安全**: - 中断中释放信号量用 `xSemaphoreGiveFromISR()` - 配合 `portYIELD_FROM_ISR()` 触发任务切换 4. **删除保护**:确保无任务等待时再调用 `vSemaphoreDelete()`[^5] > 💡 **调试技巧**:FreeRTOS 的 `uxSemaphoreGetCount()` 可实时查看信号量计数值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值