GD32F407VE天空星開發板的MQ135的空氣質量檢測

一、MQ135傳感器深度解析

1.1 傳感器概述與應用場景

MQ135是一款高性能的半導體氣體傳感器,專門設計用於檢測空氣中的多種污染氣體。這款傳感器採用二氧化錫(SnO₂)作為核心氣敏材料,在清潔空氣中具有較低的電導率,而當環境中存在污染氣體時,其電導率會隨着氣體濃度的增加而顯著增大。

典型應用場景包括:

  • 家庭環境空氣質量監測系統
  • 工業現場有害氣體泄漏報警裝置
  • 智能家居中的通風控制系統
  • 實驗室環境安全監測
  • 公共場所空氣質量評估

1.2 技術特性詳解

【雕爺學編程】Arduino動手做(79)---MQ135空氣檢測模塊_擬合


【雕爺學編程】Arduino動手做(79)---MQ135空氣檢測模塊_#define_02

MQ135傳感器具備多項優秀的技術特性:

電氣參數:

  • 工作電壓:5V DC,需穩定供電
  • 加熱電阻:29Ω±3Ω(室温條件下)
  • 加熱功耗:≤950mW,能效較高
  • 負載電阻:1KΩ,可根據應用調整

環境適應性:

  • 工作温度範圍:-10℃~+50℃
  • 預熱時間:建議不少於5分鐘
  • 長期穩定性:在標準條件下表現良好

檢測性能:

  • 檢測氣體種類:氨氣、硫化物、苯系蒸氣等多種污染氣體
  • 檢測濃度範圍:10~1000ppm
  • 靈敏度:對多種有害氣體具有良好的響應特性

二、硬件系統設計與連接

2.1 模塊硬件構成

MQ135空氣檢測模塊是一個完整的檢測解決方案,包含以下核心組件:

傳感器本體:

  • MQ-135氣體傳感器頭
  • 金屬防護罩,確保氣流暢通同時提供物理保護

信號處理電路:

  • LM393ADR電壓比較器,提供數字信號輸出
  • 10KΩ可調電位器,用於設定檢測閾值
  • 雙LED狀態指示系統
  • LED1:DO輸出狀態指示
  • LED2:電源狀態指示

接口定義:

  • VCC:5V電源輸入,需穩定可靠
  • GND:電源地線,確保良好接地
  • DO:數字信號輸出端,TTL電平 如果超出你設定的預警的數值,就會變成高電平
  • AO:模擬信號輸出端,0-3.3V電壓範圍

2.2 工作原理深度分析

【雕爺學編程】Arduino動手做(79)---MQ135空氣檢測模塊_#include_03

氣體檢測機制:
當傳感器暴露在污染氣體環境中時,氣體分子與二氧化錫材料發生化學反應,導致材料電導率發生變化。這種變化與氣體濃度呈正相關關係,從而實現了氣體濃度的檢測。

信號輸出原理:

  • 數字輸出(DO)通過電壓比較器實現。當氣體濃度超過設定閾值時,比較器輸出低電平,觸發LED1點亮
  • 模擬輸出(AO)直接反映傳感器當前的電阻狀態,通過ADC採集可以獲得連續的濃度信息

閾值調節機制:
通過旋轉可調電位器,可以改變比較器的參考電壓,從而調整觸發閾值。順時針旋轉提高閾值,逆時針旋轉降低閾值。

三、軟件系統設計與實現

3.1 系統初始化配置

bsp_gpio_mq135.c的代碼

#include "bsp_gpio_mq135.h"
//初始化的代碼我AO的引腳寫在adc裏面就初始化了,
//DO的引腳可以接在任意的有個io口上,檢測引腳的電平就可以觸發一些代碼
void mq135_init(){
printf("=mq135_init===");
//可以在這初始化DO引腳
}
/*_BSP_GPIO_MQ135_H */
/**
* @brief  檢測空氣檢測傳感器情況
* @param  GPIOx:x 可以是 A,B,C等
* @param  GPIO_Pin:待操作的pin腳號
* @retval SET(污染氣體濃度未超過閾值)、RESET(污染氣體濃度超過閾值)
*/
FlagStatus MQ135_Scan(){
// GD32使用gpio_input_bit_get讀取指定GPIO引腳的輸入狀態
// 返回值為SET(1)或RESET(0),表示引腳的邏輯電平狀態
if(gpio_input_bit_get(MQ135_DO_PIN) == RESET){
return RESET;
}
else{
return SET;
}
// 或者簡化為一行:
// return gpio_input_bit_get(GPIOx, GPIO_Pin);
}

bsp_gpio_mq135.h代碼:

#ifndef __BSP_GPIO_MQ135_H
#define __BSP_GPIO_MQ135_H
#include "gpio_cfg.h"//這個是我的初始化的函數,可以寫下面的這個
#include "gd32f4xx.h"
//任意的io口引腳
#define MQ135_DO_RCU		RCU_GPIOC
#define MQ135_DO_PIN		GPIOC, GPIO_PIN_2
//adc採樣的引腳
#define MQ135_AO_RCU		RCU_GPIOC
#define MQ135_AO_PIN		GPIOC, GPIO_PIN_1
void mq135_init();
//判斷do的引腳是否觸發
FlagStatus MQ135_Scan();
#endif /* __BSP_GPIO_MQ135_H */

3.2 數字信號處理模塊

// DO狀態監測函數
FlagStatus MQ135_Scan()
{
if(gpio_input_bit_get(MQ135_DO_PIN) == SET){
// 氣體濃度超過閾值
printf("⚠️ 警告:檢測到空氣質量超標!\r\n");
printf("當前時間:%s\r\n", get_timestamp());
return SET;
}
else
{
// 氣體濃度在安全範圍內
printf("✅ 空氣質量正常\r\n");
return RESET;
}
}

3.3 模擬信號採集與處理

app_mq135.c代碼

#include "App.h"
#include "app_mq135.h"
#include "bsp_gpio_mq135.h"
#include <math.h>
  #include "ADC0.h"
  /**
  * @brief  MQ135_ADC 任務初始化
  * @param  mq135_task_cycle: 任務輪詢週期 單位ms(可修改系統節拍定時器)
  * @retval 無
  */
  void MQ135_TaskInit(){
  printf("==MQ135_TaskInit==");
  //GPIO_analog(MQ135_AO_RCU, MQ135_AO_PIN); // 模擬輸入
  }
  /**
  * @brief  求ppm
  * @param  adc_value : ADC讀取的原始值(0~4095)
  * @retval ppm
  * @note
  * 根據手冊提供的各污染氣體靈敏度 擬合成冪函數
  * 需要根據Rs/R0推算ppm,所以擬合函數時,x軸為Rs/R0,y軸為ppm,推導出y=ax^b
  * 圖表沒有每個點對應具體數值只能大致估計,所以測量值存在誤差,想要完全精確請根據環境做多次標定
  */
  float MQ135_Get_PPM(uint16_t adc_value)
  {
  float vrl = 0;   /* AO輸出的模擬電壓 */
  float Rs;        /* 當前傳感器電阻 */
  float ppm = 0;   /* 污染物平均濃度 */
  /* 讀取AO輸出電壓 */
  vrl = (float)adc_value / 4095 * VC;
  /* 換算Rs電阻 */
  Rs = (float)(VC - vrl) * RL / vrl;
  //根據數據手冊圖表,Rs/R0的範圍為0.1~1000,所以需要取log10(Rs/R0)來進行擬合
  float Rs0 = Rs/R0;  /* Rs/R0 */
  /* y=ax^b x為Rs/R0,ab的取值根據數據手冊圖表自行擬合成冪函數 */
  ppm =  A*pow(Rs/R0,B) ;
  return ppm;
  }
  /**
  * @brief  MQ135_ADC 任務
  */
  void MQ135_Task(void)
  {
  float adc_convertedvalue[20] = {0};//轉化後的源始值的計算值
  //將ADC原始值轉換為電壓值
  uint16_t value = ADC0_get(1);
  adc_convertedvalue[0] = value * 3.3/4095;
  printf("adc_convertedvalue = %.2f",adc_convertedvalue[0]);
  printf("\r\n/*");
  //打印分割線
  for(uint32_t adc_task_i_temp = 0;adc_task_i_temp<80;adc_task_i_temp++)
  {
  printf("*");
  }
  printf("*/");
  printf("\r\n 當前的值:");
  printf("\r\n 空氣質量檢測模塊: %f V(0x%04X)",adc_convertedvalue[0],value);
  printf("\r\n");
  /* 擬合函數換算出ppm */
  float ppm = MQ135_Get_PPM(value);
  if(ppm<10)
  {
  printf("綜合污染氣體平均濃度未達到檢測範圍\r\n");
  }
  else if(ppm>1000)
  {
  printf("綜合污染氣體平均濃度超過檢測範圍\r\n");
  }
  else
  {
  printf("綜合污染氣體的平均濃度:%fppm\r\n",ppm);
  }
  printf("/*");
  for(uint32_t adc_task_i_temp = 0;adc_task_i_temp<80;adc_task_i_temp++)
  {
  printf("*");
  }
  printf("*/");
  }

app_mq135.h代碼

#ifndef __APP_MQ135_H
#define __APP_MQ135_H
#include "gpio_cfg.h"//或#include "stdint.h"
#define RL                               1     /* 根據硬件原理圖可知:RL = 1k */ 
#define R0                               2     /* MQ135在潔淨空氣中的阻值,官方數據手冊沒有給出,這是實驗測試得出,想要準確請多次測試 */ 
#define VC                               5.0   /* MQ135供電電壓,根據實際供電修改,默認接5V */
#define A                                4.17  /* y=ax^b 的 a */
#define B                                -2.28 /* y=ax^b 的 b */
#define MQ135_DO_RCU		RCU_GPIOC
#define MQ135_DO_PIN		GPIOC, GPIO_PIN_2
#define MQ135_AO_RCU		RCU_GPIOC
#define MQ135_AO_PIN		GPIOC, GPIO_PIN_1
typedef struct
{
uint32_t cycle;
uint32_t timer;
uint8_t  flag;
}MQ135_TaskInfo;
extern MQ135_TaskInfo mq135_task;
float MQ135_Ge_PPM(uint16_t adc_value);
void MQ135_TaskReset(void);
void MQ135_TaskInit();
void MQ135_Task(void);
#endif /* __APP_MQ135_H  */

四、濃度換算算法與校準

4.1 理論基礎與算法實現

氣體濃度換算基於傳感器的靈敏度特性曲線,採用冪函數擬合的方法:

/**
* @brief  求ppm
* @param  adc_value : ADC讀取的原始值(0~4095)
* @retval ppm
* @note
* 根據手冊提供的各污染氣體靈敏度 擬合成冪函數
* 需要根據Rs/R0推算ppm,所以擬合函數時,x軸為Rs/R0,y軸為ppm,推導出y=ax^b
* 圖表沒有每個點對應具體數值只能大致估計,所以測量值存在誤差,想要完全精確請根據環境做多次標定
*/
float MQ135_Get_PPM(uint16_t adc_value)
{
float vrl = 0;   /* AO輸出的模擬電壓 */
float Rs;        /* 當前傳感器電阻 */
float ppm = 0;   /* 污染物平均濃度 */
/* 讀取AO輸出電壓 */
vrl = (float)adc_value / 4095 * VC;
/* 換算Rs電阻 */
Rs = (float)(VC - vrl) * RL / vrl;
//根據數據手冊圖表,Rs/R0的範圍為0.1~1000,所以需要取log10(Rs/R0)來進行擬合
float Rs0 = Rs/R0;  /* Rs/R0 */
/* y=ax^b x為Rs/R0,ab的取值根據數據手冊圖表自行擬合成冪函數 */
ppm =  A*pow(Rs/R0,B) ;
return ppm;
}

五、完整應用系統實現

5.1 主程序框架

// 系統狀態結構體
typedef struct {
float current_concentration;
float concentration_threshold;
bool alarm_status;
uint32_t sample_count;
char air_quality_level[20];
} AirQuality_Status_t;
// 主監控循環
void AirQuality_Monitor_Loop(void)
{
AirQuality_Status_t system_status = {0};
system_status.concentration_threshold = 100.0f;  // 設置默認閾值
printf(" MQ135空氣質量監測系統啓動\r\n");
printf("=================================\r\n");
while (1) {
// 讀取當前氣體濃度
system_status.current_concentration = Get_Gas_Concentration();
system_status.sample_count++;
// 更新空氣質量等級
Update_Air_Quality_Level(&system_status);
// 檢查數字輸出狀態
Monitor_DO_Output();
// 顯示當前狀態信息
Display_System_Status(&system_status);
// 數據記錄
Log_Sensor_Data(&system_status);
// 等待下一次採樣
HAL_Delay(2000);  // 2秒採樣間隔
}
}
// 空氣質量等級評估
void Update_Air_Quality_Level(AirQuality_Status_t *status)
{
float ppm = status->current_concentration;
if (ppm < 50.0f) {
strcpy(status->air_quality_level, "優");
} else if (ppm < 100.0f) {
strcpy(status->air_quality_level, "良");
} else if (ppm < 200.0f) {
strcpy(status->air_quality_level, "輕度污染");
} else if (ppm < 300.0f) {
strcpy(status->air_quality_level, "中度污染");
} else {
strcpy(status->air_quality_level, "重度污染");
}
}

5.2 數據顯示與記錄

// 系統狀態顯示
void Display_System_Status(AirQuality_Status_t *status)
{
printf("\r\n 空氣質量監測報告\r\n");
printf("----------------------------\r\n");
printf("採樣次數:%lu\r\n", status->sample_count);
printf("當前濃度:%.2f ppm\r\n", status->current_concentration);
printf("空氣質量:%s\r\n", status->air_quality_level);
printf("報警狀態:%s\r\n", status->alarm_status ? "觸發" : "正常");
printf("----------------------------\r\n");
}
// 數據記錄功能
void Log_Sensor_Data(AirQuality_Status_t *status)
{
// 在實際應用中,這裏可以將數據保存到SD卡或發送到服務器
FILE *log_file = fopen("air_quality_log.csv", "a");
if (log_file != NULL) {
fprintf(log_file, "%lu,%.2f,%s,%d\r\n",
(unsigned long)time(NULL),
status->current_concentration,
status->air_quality_level,
status->alarm_status);
fclose(log_file);
}
}

MQ135空氣質量檢測傳感器為環境監測提供了一個成本效益高、可靠性好的解決方案。通過本文介紹的硬件連接方法、軟件實現方案以及數據處理算法,開發者可以快速構建一個功能完整的空氣質量監測系統。