5.2 FreeRTOS 二值信号量使用示例-笔记

FreeRTOS 二值信号量使用示例-笔记

系统设计背景

演示二值信号量在周期性ADC数据采集中的应用。在定时器中断服务程序中,每500毫秒进行一次ADC数据采集,转换结果被写入缓存变量并释放信号量。任务持续尝试获取信号量,成功后读取ADC转换结果并显示在LCD上。

二值信号量的核心价值

二值信号量本质上是一个长度为1的队列,只有0和1两种状态。它在系统中扮演着"事件通知"的角色,当ADC转换完成时释放信号量,显示任务获取信号量后执行数据处理,实现"数据就绪"的同步机制。

系统架构设计

系统采用以下架构实现:

  1. 定时器触发ADC转换
  2. ADC转换完成后触发中断
  3. 中断服务程序释放二值信号量
  4. 显示任务等待信号量,获取后处理数据

详细设计

系统频率设置


定时器定时触发ADC采样

在"Trigger event selection"部分,选择更新事件"update event"。


外部触发转换源设置为定时器3触发


要开启ADC的NVIC


创建一个二值信号量

/* 进程间同步,程序跑到ADC中断处肯定是有数据的,刚好释放二值信号量。到了显示任务,刚好获取到信号量数,数据已准备就绪,可以进行显示。 */

代码实现详解

1. 二值信号量的创建

c 复制代码
/* 创建二值信号量 */
BinSem_DataReadyHandle = osSemaphoreNew(1, 1, &BinSem_DataReady_attributes);

这里创建了一个初始值为1的二值信号量,表示"数据就绪"状态。

2. 定时器配置

在STM32CubeMX中配置定时器,设置"Trigger event selection"为"update event",使定时器每500毫秒触发一次ADC转换。

3. 中断服务程序处理

c 复制代码
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1)
    {
        /* 获取ADC转换结果并保存到全局变量 */
        adc_value = HAL_ADC_GetValue(hadc);
        
        /* 在中断服务例程中释放二值信号量,通知任务数据已准备就绪 */
        BaseType_t highTaskWoken = pdFALSE;
        if (BinSem_DataReadyHandle != NULL)
        {
        /*xSemaphoreGiveFromISR 用于释放一个信号量,从而通知等待该信号量的任务可以继续执行。它支持二进制信号量和计数信号量,但不支持互斥信号量(Mutex).返回值 pdTRUE: 表示信号量成功释放。*/
            xSemaphoreGiveFromISR(BinSem_DataReadyHandle, &highTaskWoken);
            portYIELD_FROM_ISR(highTaskWoken); // 申请一次任务调度
        }
    }
}

在ADC转换完成中断中,将转换结果保存到全局变量adc_value,并释放二值信号量。xSemaphoreGiveFromISR是专门用于中断中释放信号量的API,portYIELD_FROM_ISR用于判断是否需要进行任务调度。

4. 显示任务实现

c 复制代码
void AppTask_Show(void *argument)
{
    for (;;)
    {
        /* 等待数据准备就绪信号量,获取成功后显示ADC数据 */
        if (xSemaphoreTake(BinSem_DataReadyHandle, portMAX_DELAY) == pdTRUE)
        {
            uint8_t temp_str[20];
            /* 显示ADC原始数值 */
            sprintf(temp_str, "ADC Value = %d     ", adc_value);
            lcd_show_str(10, 10 + 1 * 30, 24, temp_str, RED);
            
            /* 显示转换后的电压值,ADC参考电压3.3V,12位精度 */
            sprintf(temp_str, "Voltage = %d mV     ", adc_value * 3300 >> 12);
            lcd_show_str(10, 10 + 2 * 30, 24, temp_str, RED);
        }
    }
}

显示任务持续等待二值信号量,当信号量被释放后,任务获取信号量并读取adc_value,在LCD上显示ADC原始值和转换后的电压值。

工作流程分析

  1. 定时器触发:定时器每500毫秒触发一次,启动ADC转换
  2. ADC转换:ADC开始转换模拟信号
  3. 转换完成:ADC转换完成后触发中断
  4. 信号量释放:中断服务程序中释放二值信号量
  5. 任务唤醒 :显示任务获取信号量,从adc_value读取数据
  6. 数据显示:在LCD上显示采集到的ADC值和计算出的电压值

优势分析

  1. 资源高效利用:显示任务在等待信号量时处于阻塞状态,不会占用CPU资源
  2. 实时响应:数据采集完成后立即通知显示任务,实现快速响应
  3. 代码简洁:通过二值信号量实现任务间同步,避免了轮询和全局标志位的使用
  4. 中断安全 :使用xSemaphoreGiveFromISRportYIELD_FROM_ISR确保中断安全
相关推荐
张祥6422889049 分钟前
RTKLIB源码和理论结合分析笔记三
笔记
日更嵌入式的打工仔18 分钟前
0欧电阻作用
笔记
wdfk_prog1 小时前
[Linux]学习笔记系列 -- [drivers][I2C]I2C
linux·笔记·学习
觉醒大王2 小时前
哪些文章会被我拒稿?
论文阅读·笔记·深度学习·考研·自然语言处理·html·学习方法
方安乐2 小时前
科普:股票 vs 债券的区别
笔记
傻小胖4 小时前
22.ETH-智能合约-北大肖臻老师客堂笔记
笔记·区块链·智能合约
浅念-4 小时前
C++入门(2)
开发语言·c++·经验分享·笔记·学习
张人玉5 小时前
VisionPro 定位与卡尺测量学习笔记
笔记·学习·计算机视觉·vsionprp
songyuc5 小时前
【BiFormer】BiFormer: Vision Transformer with Bi-Level Routing Attention 译读笔记
笔记·transformer
觉醒大王6 小时前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法