一文带你深度了解FreeRTOS——互斥信号量

这篇文章记录FreeRTOS的互斥信号量的知识,希望我的分享对你有所帮助!

目录

一、FreeRTOS互斥信号量简介

[二、 创建互斥信号量](#二、 创建互斥信号量)

1、创建互斥量的函数

(1)、动态创建互斥量的函数

(2)、静态创建互斥量的函数


一、FreeRTOS互斥信号量简介

FreeRTOS的互斥信号量是一种特殊的信号量,用于保护共享资源,防止多个任务同时访问。它确保一次只有一个任务可以获取信号量,从而避免资源冲突。互斥信号量在使用时可以阻塞其他请求的任务,直到资源可用。
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中。在互斥访问中互斥信号量相当于一个钥匙,当任务想要使用资源的时候就必须先获得这个钥匙,当使用完资源以后就必须归还这个钥匙,这样其他的任务就可以拿着这个钥匙去使用资源。

互斥信号量使用和二值信号量相同的API操作函数,所以互斥信号量也可以设置阻塞时间,不同于二值信号量的是互斥信号量具有优先级继承的特性。 当一个互斥信号量正在被一个低优先级的任务使用,而此时有个高优先级的任务也尝试获取这个互斥信号量的话就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级继承尽可能的降低了高优先级任务处于阻塞态的时间,并且****将已经出现的"优先级翻转"的影响降到最低。
优先级继承并不能完全的消除优先级翻转,它只是尽可能的降低优先级翻转带来的影响。硬实时应用应该在设计之初就要避免优先级翻转的发生。互斥信号量不能用于中断服务函数中,原因如下:

互斥信号量有优先级继承的机制,所以****只能用在任务中,不能用于中断服务函数。

中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

二、 创建互斥信号量

1、创建互斥量的函数

(1)、动态创建互斥量的函数

FreeRTOS动态创建互斥量的函数是xSemaphoreCreateMutex()

函数的原型如下:

复制代码
SemaphoreHandle_t xSemaphoreCreateMutex(void);

使用示例:

**Step1:**创建互斥信号量

复制代码
SemaphoreHandle_t xMutex;
xMutex = xSemaphoreCreateMutex();

**Step2:**获取互斥信号量

复制代码
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
    // 访问共享资源
    
    // 释放互斥信号量
    xSemaphoreGive(xMutex);
}

**Step3:**释放互斥信号量

释放时使用 xSemaphoreGive(xMutex)。

这里需要注意:

  • 确保在不再需要互斥信号量时使用 vSemaphoreDelete(xMutex) 释放它。
  • 使用互斥信号量时,要注意嵌套获取和释放的情况,避免死锁。

用法示例:

如何在 FreeRTOS 中使用互斥量来保护共享资源。我们将创建两个任务,它们会同时访问和修改一个共享计数器。通过互斥量来确保对该计数器的安全访问。

复制代码
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

// 定义共享资源
volatile int sharedCounter = 0;

// 定义互斥量句柄
SemaphoreHandle_t xMutex;

void vTask1(void *pvParameters) {
    for (int i = 0; i < 5; i++) {
        // 请求互斥量
        if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            // 临界区:安全地修改共享计数器
            sharedCounter++;
            printf("Task 1 incremented counter to %d\n", sharedCounter);
            // 释放互斥量
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 模拟处理时间
    }
    vTaskDelete(NULL);
}

void vTask2(void *pvParameters) {
    for (int i = 0; i < 5; i++) {
        // 请求互斥量
        if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            // 临界区:安全地修改共享计数器
            sharedCounter += 2;
            printf("Task 2 incremented counter to %d\n", sharedCounter);
            // 释放互斥量
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(150)); // 模拟处理时间
    }
    vTaskDelete(NULL);
}

int main(void) {
    // 创建互斥量
    xMutex = xSemaphoreCreateMutex();
    if (xMutex != NULL) {
        // 创建任务
        xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
        xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
        
        // 启动调度器
        vTaskStartScheduler();
    }

    // 如果一切正常,这里不会被执行
    for (;;);
    return 0;
}
  1. 共享资源:

    sharedCounter 是一个全局变量,表示共享的计数器。由于它可能被多个任务同时访问,因此定义为 volatile。

  2. 互斥量创建:

    在 main() 函数中,通过 xSemaphoreCreateMutex() 创建一个互斥量,用于保护对 sharedCounter 的访问。

  3. 任务实现:

    vTask1 每次增加计数器 1,并打印当前值。vTask2 每次增加计数器 2,并打印当前值。每个任务在进入临界区时请求互斥量,并在操作完成后释放互斥量。

  4. 任务调度:

    在 main() 中创建两个任务并启动调度器,系统将开始运行这两个任务。

运行该程序时,你会看到任务交替地输出其对计数器的增值结果:

Task 1 incremented counter to 1
Task 2 incremented counter to 3
Task 1 incremented counter to 4
Task 2 incremented counter to 6
...

每个任务在增加计数器时都确保了数据的一致性,因为它们在访问共享资源时使用了互斥量。这是多任务编程中保护共享资源的常见模式。

(2)、静态创建互斥量的函数

在 FreeRTOS 中,可以使用静态分配的方式创建互斥量,以便减少动态内存分配的需求。静态创建互斥量通常涉及以下步骤:

  1. 定义一个 StaticSemaphore_t 类型的变量。
  2. 使用 xSemaphoreCreateMutexStatic() 函数来创建互斥量。
  • xSemaphoreCreateMutexStatic() :
    • 功能: 创建一个静态互斥量。
    • 参数 :
      • pxMutexBuffer: 一个指向 StaticSemaphore_t 的指针,用于存储互斥量的控制数据。
    • 返回值 : 返回互斥量的句柄,如果创建失败则返回 NULL。

下面是一个简单的 FreeRTOS 示例,演示如何静态创建互斥量并在两个任务中使用它。

1、定义资源:

  • StaticSemaphore_t xMutexBuffer: 用于存储互斥量的静态控制信息。
  • SemaphoreHandle_t xMutex: 保存互斥量的句柄。

2、任务函数:

  • vTaskFunction: 这是两个任务的主体,每个任务尝试获取互斥量后进行处理,处理完毕后释放互斥量。

3、主函数:

  • 调用 xSemaphoreCreateMutexStatic 创建互斥量,将控制结构传入。这个函数不需要动态内存分配。
  • 使用 xTaskCreate 创建两个任务,分别执行同一个任务函数。

4、调度器启动:

  • 调用 vTaskStartScheduler() 启动 FreeRTOS 调度器,任务开始运行。

三、结语

关于FreeRTOS的互斥信号量的知识就分享到此了,希望我的分享对你有所帮助!

相关推荐
WD1372980155734 分钟前
WD5030L,为充电桩、工业设备、5G 基站、车载系统、消费电子提供电源,7-30V 的宽压输入
stm32·单片机·嵌入式硬件·5g·车载系统·51单片机
创界工坊工作室2 小时前
30-基于STM32的小麦烘干塔温度控制系统设计
stm32·单片机·嵌入式硬件·proteus
Zwawa3 小时前
先把轮子转稳,才不会烧心:编码器速度环 PID 怎么接回 PWM
c语言·单片机·嵌入式
smartpi_ai4 小时前
51 单片机写好了,大模型语音怎么接?17T 全驱动的现成方案、双板串口分工的边界与画板前的三项硬件确认
单片机·嵌入式硬件·学习
我先去打把游戏先4 小时前
NimBLE是什么-ESP32蓝牙协议栈详解
单片机·嵌入式硬件·ubuntu
Gongsion5 小时前
30V输入耐压|1.5μA超低静态电流|200mA输出,CSM52系列:线性稳压器LDO,12V母线转3.3V/5V传感器、MCU弱电支路可靠稳压方案
单片机·嵌入式硬件·车载系统·无人机·智能家居
芯岭技术9 小时前
XL2400T收发芯片,2.4G无线荧光棒控光解决方案,+PA距离可达700M
单片机·嵌入式硬件·物联网
艾芯微科技9 小时前
ETA1637S2G|钰泰同步升压 LED 背光驱动 SOT23-6,0.1% 超低占空比 PWM 调光
网络·单片机·嵌入式硬件·集成测试·51单片机
女神下凡10 小时前
芯参谋(55):LED 驱动 · 系统设计指南
arm开发·单片机·嵌入式硬件·硬件工程·设计规范
西城微科方案开发11 小时前
方案商|西城微科胎压计方案开发
单片机·嵌入式硬件