FreeRTOS互斥量实战:血氧监测系统设计

在FreeRTOS中,互斥量是保护共享资源、防止数据竞争的关键工具,下面结合血氧监测系统的设计来详细说明。

复制代码
/* 定义血氧数据结构体 */
typedef struct {
    uint32_t timestamp;   // 时间戳
    int16_t raw_ppg;      // 原始光电容积脉搏波
    uint8_t spo2;         // 血氧饱和度
    uint16_t heart_rate;  // 心率
} OxyData_t;

/* 共享的全局数据变量 */
OxyData_t currentOxyData;
SemaphoreHandle_t xOxyDataMutex; /* 互斥量句柄 */

/* 数据采集任务 */
void vDataAcquisitionTask(void *pvParameters) {
    OxyData_t localData; // 使用局部变量暂存数据
    for (;;) {
        /* 从传感器读取数据到局部变量... */
        read_sensors(&localData);
        
        /* 获取互斥量,保护对共享数据的写操作 */
        if (xSemaphoreTake(xOxyDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
            /* 进入临界区,将局部数据拷贝到共享全局变量 */
            memcpy(&currentOxyData, &localData, sizeof(OxyData_t));
            /* 操作完成后立即释放互斥量 */
            xSemaphoreGive(xOxyDataMutex);
        } else {
            /* 获取互斥量超时处理,例如记录错误或重试 */
        }
        vTaskDelay(pdMS_TO_TICKS(20)); // 假设每20ms采集一次
    }
}

/* 数据处理与显示任务 */
void vDataProcessingTask(void *pvParameters) {
    OxyData_t localCopy; // 用于存放共享数据的本地副本
    for (;;) {
        /* 获取互斥量,保护对共享数据的读操作 */
        if (xSemaphoreTake(xOxyDataMutex, portMAX_DELAY) == pdTRUE) {
            /* 进入临界区,快速将共享数据拷贝到本地 */
            memcpy(&localCopy, &currentOxyData, sizeof(OxyData_t));
            /* 拷贝完成后立即释放互斥量,减少持有时间 */
            xSemaphoreGive(xOxyDataMutex);
            
            /* 在临界区外对本地副本进行计算和显示操作 */
            calculate_spo2(&localCopy);
            update_display(&localCopy);
        }
        vTaskDelay(pdMS_TO_TICKS(100)); // 假设每100ms处理一次
    }
}

/* 主函数中创建互斥量和任务 */
int main(void) {
    /* 硬件初始化... */
    
    /* 创建互斥量 */
    xOxyDataMutex = xSemaphoreCreateMutex();
    if (xOxyDataMutex == NULL) {
        /* 互斥量创建失败,错误处理 */
    }
    
    /* 创建任务 */
    xTaskCreate(vDataAcquisitionTask, "Acq", 1024, NULL, 2, NULL);
    xTaskCreate(vDataProcessingTask, "Proc", 1024, NULL, 3, NULL); /* 赋予处理任务更高优先级 */
    
    vTaskStartScheduler();
    
    for (;;);
    return 0;
}

使用互斥量的重要注意事项

在设计血氧监测这类关键系统时,以下几点尤为重要:

  • 尽快释放互斥量​:获取互斥量后,应只执行最基本的共享资源操作,然后立即释放。这能最大限度地减少对其他任务的阻塞时间。

  • 防止死锁​:如果一个任务需要获取多个互斥量,要确保所有任务都以相同的顺序获取它们。例如,总是先获取互斥量A,再获取互斥量B,避免循环等待。

  • 不得在中断服务程序中使用 ​:互斥量的获取和释放操作绝对不能在中断服务程序中调用。如果需要在中断中同步,应使用专用的二进制信号量。

  • 考虑递归互斥量 ​:如果一个任务可能会多次获取同一个互斥量(例如,在调用链中多个函数都需要访问受保护的资源),则应使用 xSemaphoreCreateRecursiveMutex()创建的递归互斥量,并配套使用 xSemaphoreTakeRecursive()xSemaphoreGiveRecursive(),以避免任务自身死锁。

相关推荐
Hello_Embed1 天前
FreeRTOS 入门(二十六):队列创建与读写 API 实战解析
笔记·学习·操作系统·嵌入式·freertos
云雾J视界1 天前
当AI下沉到MCU:嵌入式开发者的“能力护城河”正在被重写
人工智能·单片机·嵌入式硬件·mcu·freertos·岗位技能
路弥行至2 天前
FreeRTOS任务管理详解中: FreeRTOS任务创建与删除实战教程(动态方法)
c语言·开发语言·笔记·stm32·操作系统·freertos·入门教程
rechol2 天前
pendsv任务切换
嵌入式·freertos·任务切换
rechol2 天前
CPU中断异常
单片机·异常·嵌入式软件·中断
一枝小雨3 天前
【OTA专题】12 APP中移植EEprom、W25Q驱动
stm32·单片机·嵌入式·freertos·ota·bootloader
一枝小雨3 天前
【OTA专题】11 进一步优化OTA后台无感下载架构
stm32·单片机·架构·嵌入式·freertos·ota·bootloader
高旭的旭7 天前
一文读懂RDS AF跳转与EON TA跳转:广播信号的“稳定器”与“交通摆渡车”
嵌入式软件·fm·rds·radio
无人装备硬件开发爱好者7 天前
Doxygen 在嵌入式软件开发中的深度应用(中):从基础到无人机电调 / 汽车 FOC 控制器实战
嵌入式软件·doxygen·无人机电调·汽车 foc 控制器
小曹要微笑7 天前
PCA9555 I/O扩展芯片驱动详解
c语言·单片机·嵌入式硬件·freertos·io扩展芯片·pca9555