基于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. 基本功能
- 实时检测空气中烟雾浓度(0-100%)
- LCD1602显示当前浓度值
- 可设置报警阈值(0-100%)
- 浓度超过阈值时声光报警
2. 操作说明
-
上电后系统自动初始化
-
LCD显示"Smoke Detector"和当前浓度
-
按"设置"键进入阈值设置模式
-
在设置模式下:
- 按"加"键增加阈值
- 按"减"键减少阈值
-
再次按"设置"键退出设置模式
-
当浓度超过阈值时,蜂鸣器响,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. 校准步骤
- 将传感器置于清洁空气中,通电预热10分钟
- 记录此时ADC值作为基准值(0%浓度)
- 使用标准烟雾源(如香烟烟雾)产生已知浓度
- 调整转换公式,使显示值与实际浓度匹配
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请求...
}
九、使用注意事项
- 预热时间:MQ2传感器需要预热1-2分钟才能达到稳定状态
- 环境干扰:避免强风、水蒸气、酒精等干扰物
- 报警设置:根据实际环境调整报警阈值
- 定期校准:每3个月进行一次校准
- 安全使用:本系统为辅助检测工具,不能替代专业消防设备
十、项目总结
本系统实现了基于51单片机的MQ2烟雾检测功能,具有以下特点:
- 实时显示烟雾浓度(0-100%)
- 可设置报警阈值(0-100%)
- 声光报警功能
- 简洁的人机界面(LCD1602)
- 低功耗设计(待机电流<5mA)