野火STM32_HAL库版课程笔记-空气、烟雾传感器公式换算

前置介绍

回顾

通过 ADC 多通道 + DMA 采集 空气, 烟雾传感器的 ADC 数据.

引出

但是 ADC 数据只是一个电压值, 该怎么得到空气和烟雾的浓度呢?

空气, 烟雾传感器公式换算

ADC 采集到的电压值是一个 "中间量" , 并不能直接反映气体浓度.

例: 读取电压为 1V, 但是却并不知道具体的浓度.

模块手册 - 烟雾传感器 - 程序流程
原理图 - 烟雾传感器
MQ2 - 数据手册与函数拟合 Excel 表

这里的预热时间对于我们做程序实验来说, 不需要满足预热 48 小时, 一分钟即可进行简单测量.

项目配置

代码部分

复制代码
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include <stdio.h>  // 使用 printf 函数
#include <math.h>   // 使用 pow(浮点幂运算)
#include <string.h> // 使用 strncmp

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* ===================== MQ135 参数 ===================== */
#define RL_MQ135      1.0f     /* 根据硬件原理图可知:RL = 1k */
#define R0_MQ135      2.0f     /* MQ135在洁净空气中的阻值 */
#define VC_MQ135      5.0f     /* MQ135供电电压,根据实际供电修改 */
#define A_MQ135       4.17f    /* y=ax^b 的 a */
#define B_MQ135      -2.28f    /* y=ax^b 的 b */

/* ===================== MQ2 参数 ===================== */
#define RL_MQ2       10.0f     /* 根据硬件原理图可知:RL = 10k */
#define R0_MQ2       20.0f     /* MQ2在洁净空气中的阻值 */
#define VC_MQ2        5.0f     /* MQ2供电电压,根据实际供电修改 */
#define A_MQ2        43.03f    /* y=ax^b 的 a */
#define B_MQ2        -1.66f    /* y=ax^b 的 b */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

uint16_t adc_val[2];  // 存储传感器 ADC 数值
float voltage[2];     // 存储传感器 ADC 电压

/* USER CODE END PV */

  /* USER CODE BEGIN 2 */
  
  // ADC 校准
  HAL_ADCEx_Calibration_Start(&hadc1);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    // 启动 ADC + DMA, adc_val 是数组(地址), 在 CubeMX 中配置了内存地址递增, 所以这里只需要给这个地址就可以了. 
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_val, 2);
    
    // 每 500ms 转换一次. 
    HAL_Delay(500);
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

/* USER CODE BEGIN 4 */

/**
  * @brief  根据ADC值计算指定气体传感器的ppm
  * @param  adc_value : ADC读取的原始值(0~4095)
  * @param  RL        : 负载电阻(kΩ)
  * @param  R0        : 传感器在洁净空气中的电阻(kΩ)
  * @param  VC        : 传感器供电电压(V)
  * @param  A         : 拟合公式系数 a
  * @param  B         : 拟合公式指数 b
  * @retval ppm
  * @note   y = A * (Rs/R0)^B
  */
float Get_PPM(uint16_t adc_value, float RL, float R0, float VC, float A, float B)
{
    float vrl;   /* AO输出的模拟电压 */
    float Rs;    /* 当前传感器电阻 */
    float ppm;   /* 气体平均浓度 */    

    /* 读取AO输出电压 */
    vrl = (float)adc_value / 4095.0f * VC;
	
    /* 换算Rs电阻 */
    Rs = (VC - vrl) * RL / vrl;
    
    /* y=ax^b,x为Rs/R0 */
    ppm = A * pow(Rs / R0, B);
    
    return ppm;
}

/**
 * @brief   ADC + DMA 转换完成回调函数 
 * @param   hadc 指向 ADC 句柄的指针
 * @retval  无
 * @note    当 ADC1 的规则通道转换完成并且DMA传输完成后被自动调用,用于计算电压值并打印显示 
 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if (hadc -> Instance == ADC1)
	{
		// 将 ADC 数值转换为电压(假设参考电压为 3.3V,12位精度)
		voltage[0] = (float)adc_val[0] / 4095 * 3.3f;
		voltage[1] = (float)adc_val[1] / 4095 * 3.3f;

		printf("\r\n空气(IN4): %.3f V,烟雾(IN5): %.3f V\r\n",
		voltage[0],voltage[1]);
		
		// 打印80个*的分隔线
		printf("\r\n/*");
		for (uint32_t i = 0; i < 80; i++) printf("*");
		printf("*/");

		// MQ135空气质量计算,基于传感器电阻与经验参数
		float ppm_air = Get_PPM(adc_val[0], RL_MQ135, R0_MQ135, VC_MQ135, A_MQ135, B_MQ135);
		if (ppm_air < 10)
				printf("\r\n空气质量:低于检测范围!");
		else if (ppm_air > 1000)
				printf("\r\n空气质量:高于检测范围!");
		else
				printf("\r\n空气质量:%.2f ppm!", ppm_air);

		// MQ2烟雾浓度计算
		float ppm_smoke = Get_PPM(adc_val[1], RL_MQ2, R0_MQ2, VC_MQ2, A_MQ2, B_MQ2);
		if (ppm_smoke < 300)
				printf("\r\n烟雾浓度:低于检测范围!");
		else if (ppm_smoke > 10000)
				printf("\r\n烟雾浓度:高于检测范围!");
		else
				printf("\r\n烟雾浓度:%.2f ppm!", ppm_smoke);

		// 结尾分隔线
		printf("\r\n/*");
		for (uint32_t i = 0; i < 80; i++) printf("*");
		printf("*/\r\n");
	}
}


/**
  * @brief  重定向 printf 的输出到串口
  * @param  ch 要发送的字符
  * @param  f  文件指针(标准库要求的参数,一般不使用)
  * @retval 返回发送的字符
  */
int fputc(int ch, FILE *f)
{
         HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
         return ch;
}

/* USER CODE END 4 */

程序现象

使用普通打火机, 轻按(不点火) 将丁烷朝烟雾或空气质量传感器释放, 可以检测到空气质量和烟雾浓度达到检测范围, 并显示 ppm 数值.

注意: 不要点着火!!!, 不要吸入过量丁烷!!!, 安全第一!!!
相关推荐
玻璃杯中水2 小时前
硬件知识总结梳理-1(电阻+电容)
单片机·嵌入式硬件
yuan199972 小时前
STM32F407 TIM3正交编码器应用指南
stm32·单片机·嵌入式硬件
m0_651562523 小时前
2026/3/26 学习笔记——终端复用工具screen
笔记·学习
sinat_255487813 小时前
JSON·学习笔记
java·开发语言·笔记·算法
Roselind_Yi3 小时前
从线性回归实战到Python依赖安装踩坑:我的机器学习入门排雷记
笔记·python·算法·机器学习·回归·线性回归·学习方法
宵时待雨3 小时前
C++笔记归纳15:红黑树
开发语言·数据结构·c++·笔记
lin辰傍边的风3 小时前
RS485收发架构移植要点
stm32·单片机·嵌入式硬件
π同学3 小时前
基于CH343的一种自动烧录模式电路设计分析
单片机·嵌入式硬件·eps32
轻赚时代4 小时前
零开发门槛!AI视频工具实操教程:图片/文字一键生成动态视频
人工智能·经验分享·笔记·音视频·创业创新·课程设计