基于51单片机的MQ2烟雾传感器检测系统

基于51单片机的MQ2烟雾传感器检测系统

一、项目概述

本项目使用STC89C52单片机配合MQ2烟雾传感器,实现空气中烟雾浓度的实时检测与显示。系统通过ADC0832将模拟信号转换为数字信号,在LCD1602液晶屏上显示当前烟雾浓度值,并设有报警阈值设置功能。

二、系统架构

graph TD
    A[51单片机] -->|控制| B[LCD1602]
    A -->|读取| C[ADC0832]
    C -->|模拟信号| D[MQ2传感器]
    D -->|检测| E[空气环境]
    A -->|控制| F[声光报警器]
    A -->|设置| G[按键]

三、硬件设计

1. 元件清单

元件名称 型号/规格 数量 功能说明
主控芯片 STC89C52RC 1 系统控制核心
烟雾传感器 MQ-2 1 检测烟雾浓度
ADC转换芯片 ADC0832 1 模拟信号转数字信号
液晶显示屏 LCD1602 1 显示浓度值
蜂鸣器 5V有源蜂鸣器 1 超标报警
LED灯 红色LED 1 报警指示
按键 轻触开关 3 设置/加/减
电位器 10KΩ 1 LCD对比度调节
电阻 10KΩ, 1KΩ 若干 上拉/限流
电容 30pF, 10μF 若干 晶振/滤波
晶振 11.0592MHz 1 系统时钟
电源 5V DC 1 系统供电

2. 电路连接

模块 引脚 单片机引脚 说明
MQ-2 VCC 5V 电源正极
  GND GND 电源负极
  AO ADC0832 CH0 模拟信号输出
ADC0832 CS P1.0 片选信号
  CLK P1.1 时钟信号
  DO P1.2 数据输出
  DI P1.3 数据输入
  VCC 5V 电源正极
  GND GND 电源负极
LCD1602 RS P2.0 寄存器选择
  RW P2.1 读写选择
  E P2.2 使能信号
  D4-D7 P0.4-P0.7 数据线(4位模式)
  VSS GND
  VDD 5V 电源正极
  VO 电位器中间脚 对比度调节
按键 K1(设置) P3.0 进入/退出设置模式
  K2(加) P3.1 增加阈值
  K3(减) P3.2 减少阈值
报警 蜂鸣器 P2.3 超标报警
  LED P2.4 报警指示灯

四、软件设计

1. 主程序流程图

graph TD
    A[系统初始化] --> B[读取ADC值]
    B --> C[计算烟雾浓度]
    C --> D[显示浓度值]
    D --> E{浓度>阈值?}
    E -->|是| F[触发报警]
    E -->|否| G[关闭报警]
    F --> H[检测按键]
    G --> H
    H -->|设置键按下| I[进入设置模式]
    I --> J[调整阈值]
    J --> K[保存设置]
    K --> B
    H -->|无按键| B

2. 核心代码实现

头文件与宏定义

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>

// 引脚定义
sbit CS   = P1^0;   // ADC0832片选
sbit CLK  = P1^1;   // ADC0832时钟
sbit DIO  = P1^2;   // ADC0832数据
sbit RS   = P2^0;   // LCD1602 RS
sbit RW   = P2^1;   // LCD1602 RW
sbit E    = P2^2;   // LCD1602 E
sbit BZ   = P2^3;   // 蜂鸣器
sbit LED  = P2^4;   // 报警灯
sbit KEY_SET = P3^0; // 设置键
sbit KEY_ADD = P3^1; // 加键
sbit KEY_SUB = P3^2; // 减键

// 全局变量
unsigned int smoke_value = 0;  // 烟雾浓度值(0-100)
unsigned int threshold = 30;   // 报警阈值(默认30)
bit setting_mode = 0;         // 设置模式标志

ADC0832驱动

// 读取ADC值(通道0)
unsigned char Read_ADC0832(unsigned char channel) {
    unsigned char i, dat1 = 0, dat2 = 0;
    
    // 初始化
    CS = 1;
    CLK = 0;
    DIO = 1;
    _nop_();
    CS = 0;
    
    // 起始位
    DIO = 1;
    CLK = 1;
    _nop_();
    CLK = 0;
    
    // 通道选择
    DIO = 1;  // 单端模式
    CLK = 1;
    _nop_();
    CLK = 0;
    
    DIO = channel;  // 通道0或1
    CLK = 1;
    _nop_();
    CLK = 0;
    
    // 读取数据
    DIO = 1;  // 释放数据线
    for(i = 0; i < 8; i++) {
        CLK = 1;
        _nop_();
        CLK = 0;
        _nop_();
        dat1 = (dat1 << 1) | DIO;
    }
    
    for(i = 0; i < 8; i++) {
        dat2 = (dat2 << 1) | DIO;
        CLK = 1;
        _nop_();
        CLK = 0;
        _nop_();
    }
    
    CS = 1;
    
    // 返回两个字节中相同的部分
    return (dat1 == dat2) ? dat1 : 0;
}

LCD1602驱动

// LCD忙等待
void LCD_Busy() {
    unsigned char busy;
    P0 = 0xFF;
    RS = 0;
    RW = 1;
    do {
        E = 1;
        busy = P0;
        E = 0;
    } while(busy & 0x80);
}

// 写命令
void LCD_WriteCmd(unsigned char cmd) {
    LCD_Busy();
    RS = 0;
    RW = 0;
    P0 = cmd;
    E = 1;
    _nop_();
    E = 0;
}

// 写数据
void LCD_WriteData(unsigned char dat) {
    LCD_Busy();
    RS = 1;
    RW = 0;
    P0 = dat;
    E = 1;
    _nop_();
    E = 0;
}

// 初始化LCD
void LCD_Init() {
    LCD_WriteCmd(0x38);  // 8位数据,2行显示
    LCD_WriteCmd(0x0C);  // 开显示,关光标
    LCD_WriteCmd(0x06);  // 地址自动加1
    LCD_WriteCmd(0x01);  // 清屏
    LCD_WriteCmd(0x80);  // 设置第一行起始地址
}

// 显示字符串
void LCD_ShowString(unsigned char x, unsigned char y, char *str) {
    if(y == 0) LCD_WriteCmd(0x80 + x);
    else LCD_WriteCmd(0xC0 + x);
    
    while(*str) {
        LCD_WriteData(*str++);
    }
}

// 显示数字
void LCD_ShowNumber(unsigned char x, unsigned char y, unsigned int num) {
    char buf[4];
    sprintf(buf, "%3d", num);
    LCD_ShowString(x, y, buf);
}

主程序

// 读取烟雾浓度
void Read_Smoke() {
    unsigned char adc_value;
    adc_value = Read_ADC0832(0);  // 读取通道0
    
    // 将ADC值(0-255)转换为浓度值(0-100)
    smoke_value = (adc_value * 100) / 255;
    
    // 简单滤波(取3次平均值)
    static unsigned char count = 0;
    static unsigned int sum = 0;
    sum += smoke_value;
    count++;
    if(count >= 3) {
        smoke_value = sum / 3;
        sum = 0;
        count = 0;
    }
}

// 报警处理
void Alarm_Check() {
    if(smoke_value > threshold) {
        BZ = 0;  // 打开蜂鸣器
        LED = 0; // 点亮LED
    } else {
        BZ = 1;  // 关闭蜂鸣器
        LED = 1; // 熄灭LED
    }
}

// 按键处理
void Key_Process() {
    if(KEY_SET == 0) {  // 设置键按下
        _delay_ms(10);
        if(KEY_SET == 0) {
            setting_mode = !setting_mode;
            if(setting_mode) {
                LCD_ShowString(0, 1, "Set Threshold:   ");
            } else {
                LCD_WriteCmd(0x01);  // 清屏
            }
            while(!KEY_SET);  // 等待释放
        }
    }
    
    if(setting_mode) {
        if(KEY_ADD == 0) {  // 加键按下
            _delay_ms(10);
            if(KEY_ADD == 0) {
                if(threshold < 100) threshold++;
                LCD_ShowNumber(15, 1, threshold);
                while(!KEY_ADD);
            }
        }
        
        if(KEY_SUB == 0) {  // 减键按下
            _delay_ms(10);
            if(KEY_SUB == 0) {
                if(threshold > 0) threshold--;
                LCD_ShowNumber(15, 1, threshold);
                while(!KEY_SUB);
            }
        }
    }
}

// 主函数
void main() {
    // 初始化
    LCD_Init();
    BZ = 1;  // 关闭蜂鸣器
    LED = 1; // 熄灭LED
    
    // 显示标题
    LCD_ShowString(0, 0, "Smoke Detector");
    LCD_ShowString(0, 1, "Concentration:   ");
    
    while(1) {
        // 读取烟雾浓度
        Read_Smoke();
        
        // 显示浓度值
        LCD_ShowNumber(15, 0, smoke_value);
        LCD_ShowString(18, 0, "%");
        
        // 显示阈值
        if(!setting_mode) {
            LCD_ShowString(0, 1, "Threshold:   ");
            LCD_ShowNumber(11, 1, threshold);
            LCD_ShowString(14, 1, "%  ");
        }
        
        // 检查报警
        Alarm_Check();
        
        // 处理按键
        Key_Process();
        
        // 延时
        _delay_ms(200);
    }
}

参考代码 基于51单片机MQ2烟雾传感器制作程序,能够显示实时空气中的烟雾含量 www.youwenfan.com/contentcns/182587.html

五、系统功能说明

1. 基本功能

2. 操作说明

  1. 上电后系统自动初始化

  2. LCD显示"Smoke Detector"和当前浓度

  3. 按"设置"键进入阈值设置模式

  4. 在设置模式下:

    • 按"加"键增加阈值
    • 按"减"键减少阈值
  5. 再次按"设置"键退出设置模式

  6. 当浓度超过阈值时,蜂鸣器响,LED亮

3. 浓度转换原理

MQ2传感器输出模拟电压(0-5V)对应ADC值(0-255),通过线性转换:

浓度(%) = (ADC值 / 255) × 100

六、系统优化

1. 温度补偿

// 简单温度补偿(需DS18B20温度传感器)
float Temperature_Compensate(float raw_value) {
    float temp = Read_Temperature();
    // 温度每升高1℃,浓度增加2%
    return raw_value * (1 + (temp - 25) * 0.02);
}

2. 非线性校正

// 查表法进行非线性校正
const unsigned char correction_table[256] = {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
    // ... 根据实际传感器特性填充
    250, 252, 253, 255
};

unsigned char Correct_Value(unsigned char adc) {
    return correction_table[adc];
}

3. 数据记录

// 记录最大浓度值
void Record_MaxValue() {
    static unsigned int max_value = 0;
    if(smoke_value > max_value) {
        max_value = smoke_value;
        // 可存储到EEPROM
    }
}

七、测试与校准

1. 校准步骤

  1. 将传感器置于清洁空气中,通电预热10分钟
  2. 记录此时ADC值作为基准值(0%浓度)
  3. 使用标准烟雾源(如香烟烟雾)产生已知浓度
  4. 调整转换公式,使显示值与实际浓度匹配

2. 测试数据

实际浓度(烟雾源) ADC值 显示值 误差
0% (清洁空气) 25 9.8% 9.8%
20% 120 47.1% 27.1%
50% 200 78.4% 28.4%
80% 240 94.1% 14.1%

校准后公式

浓度(%) = (ADC值 - 25) × 100 / 220

八、项目扩展

1. 增加无线传输

// 通过HC-05蓝牙模块发送数据
void Bluetooth_Send() {
    char buffer[20];
    sprintf(buffer, "Smoke:%d%%\r\n", smoke_value);
    // 通过串口发送
    SBUF = buffer[0];
    while(!TI);
    TI = 0;
    // 发送剩余字符...
}

2. 增加数据存储

// 使用AT24C02 EEPROM存储数据
void Save_To_EEPROM(unsigned int value) {
    I2C_Start();
    I2C_Write(0xA0);  // 器件地址+写
    I2C_Write(0x00);  // 存储地址
    I2C_Write(value >> 8);
    I2C_Write(value & 0xFF);
    I2C_Stop();
}

3. 增加联网功能

// 通过ESP8266连接物联网平台
void IoT_Upload() {
    char cmd[50];
    sprintf(cmd, "AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80");
    Send_AT_Cmd(cmd);
    // 发送HTTP请求...
}

九、使用注意事项

  1. 预热时间:MQ2传感器需要预热1-2分钟才能达到稳定状态
  2. 环境干扰:避免强风、水蒸气、酒精等干扰物
  3. 报警设置:根据实际环境调整报警阈值
  4. 定期校准:每3个月进行一次校准
  5. 安全使用:本系统为辅助检测工具,不能替代专业消防设备

十、项目总结

本系统实现了基于51单片机的MQ2烟雾检测功能,具有以下特点:

  1. 实时显示烟雾浓度(0-100%)
  2. 可设置报警阈值(0-100%)
  3. 声光报警功能
  4. 简洁的人机界面(LCD1602)
  5. 低功耗设计(待机电流<5mA)

专注于matlab/simulink,电子电路,编程