当前位置: 首页 > article >正文

基于单片机设计的防煤气泄漏装置

一、前言

煤气泄漏是一个严重的安全隐患,可能导致火灾、爆炸以及对人体健康的威胁。为了提高家庭和工业环境中煤气泄漏的检测和预防能力,设计了一种基于单片机的防煤气泄漏装置。

单片机选择STC89C52作为主控芯片。为了检测煤气泄漏,采用了MQ4传感器,能够快速、准确地检测煤气浓度。通过采集MQ4传感器的模拟信号,使用PCF8591模数转换芯片将模拟信号转换为数字信号。采用IIC接口的OLED显示屏,将采集到的数据显示出来,方便用户获取检测结果。用户可以通过两个独立按键设置煤气泄漏的报警阈值,以适应不同环境的需求。

当检测到煤气泄漏超过设定的阈值时,装置会触发蜂鸣器进行报警,并同时打开换气扇进行通风换气,以迅速排除煤气并降低安全风险。

这种基于单片机设计的防煤气泄漏装置具有以下优点:高效可靠的煤气泄漏检测能力、灵活的报警阈值设置、直观清晰的数据显示以及及时的安全响应措施。可以广泛应用于家庭、工业和商业场所,提供有效的煤气泄漏监测和安全保护。

image-20230823165237872

image-20230823165325193

二、硬件选型

在设计基于单片机的防煤气泄漏装置时,硬件选型是非常关键的。以下是详细介绍硬件选型的相关内容:

【1】主控芯片选择:STC89C52 STC89C52是一款8051架构的单片机,具有丰富的接口资源、较高的性能和稳定可靠的工作特性,广泛应用于各种嵌入式系统中。具有8位数据总线、16位地址总线和4KB的内部存储器。STC89C52具备多个通用I/O口、定时器/计数器、串口等功能,非常适合本项目需求。

【2】煤气传感器选择:MQ4 MQ4传感器是一种能够检测多种可燃气体,如天然气、甲烷等的传感器。具有高灵敏度和快速响应的特点,能够准确地检测煤气泄漏情况。MQ4传感器的输出为模拟信号,需要通过模数转换器将其转换为数字信号供主控芯片处理。

【3】模数转换器选择:PCF8591 PCF8591是一款集成了8位模数/数模转换和4个模拟输入通道的模数转换器。采用IIC总线通讯接口,能够将模拟信号转换为数字信号,并通过IIC协议发送给主控芯片。本项目中,PCF8591用于采集MQ4传感器输出的模拟信号,并将其转换为数字信号供STC89C52处理。

【4】显示屏选择:0.96寸OLED显示屏(IIC接口) 本设计采用基于IIC接口的OLED显示屏,具有高亮度、对比度和快速响应的特点。通过简单的通讯方式,可以将煤气浓度信息实时显示在屏幕上。OLED显示屏使用面积小、功耗低,在嵌入式系统中应用广泛。

【5】按键选择:独立按键 本设计采用两个独立按键来设置报警的阀值。一个按键用于递增阀值,另一个按键用于递减阀值。独立按键具有简单可靠、使用方便等特点,适合本项目需求。

【6】报警装置选择:蜂鸣器和换气扇 当检测到煤气泄漏超过设定的报警阀值时,蜂鸣器将发出警报,用于提醒周围人员。同时,为了降低煤气浓度,需要启动换气扇进行通风换气。具体的报警和换气扇电路可以根据实际需求设计。

三、设计思路

软件设计思路如下:

【1】初始化:在程序开始时,进行主控芯片STC89C52的初始化设置,包括引脚配置、定时器设置等。同时,初始化PCF8591和OLED显示屏,确保它们可以正常工作。

【2】传感器检测:通过MQ4传感器检测煤气是否泄漏。将MQ4传感器与STC89C52的模拟输入引脚连接,通过读取该引脚的模拟电压值,获取煤气浓度数据。

【3】数据采集与处理:使用PCF8591模数转换芯片,将MQ4传感器的模拟输出信号转换为数字信号,并通过STC89C52的IIC接口与PCF8591进行通信,获取转换后的数字数据。

【4】数据显示:将采集到的煤气浓度数据通过IIC接口的OLED显示屏进行显示。使用STC89C52的IIC通信功能,将数据发送给OLED显示屏,通过显示屏将数据以可读的方式展示给用户。

【5】阈值设置:通过两个独立按键实现报警阈值的设置。将按键与STC89C52的GPIO引脚连接,通过读取按键状态来判断用户是否进行阈值设置操作。当按键按下时,进入设置模式,用户可以通过按键的不同组合来调整报警阈值,并将设置的值保存在相应的变量中。

【6】报警与通风控制:根据当前采集到的煤气浓度数据和用户设置的报警阈值进行比较。如果煤气浓度超过设定的阈值,触发蜂鸣器进行报警,并控制换气扇打开进行通风换气。反之,当煤气浓度低于或等于设定的阈值时,停止报警并关闭换气扇。

【7】循环监测:使用主循环结构,不断进行煤气泄漏检测、数据采集、数据显示和阈值比较等操作,以实现持续的监测和反馈。

四、项目模块代码

4.1 PCF8591采集代码

下面是使用STC89C52单片机通过PCF8591读取MQ4传感器的ADC数据的代码。使用IIC总线进行PCF8591之间的通信,使用了自定义的IIC总线函数。通过readADC()函数实现了读取MQ4传感器模拟量的ADC转换结果。

#include <reg52.h>

#define uchar unsigned char
#define uint unsigned int

sbit SDA = P2^0;    // IIC总线数据线
sbit SCL = P2^1;    // IIC总线时钟线

sbit MQ4_DOUT = P3^0;   // MQ4传感器数字输出引脚
sbit MQ4_AIN = P3^1;    // MQ4传感器模拟输入引脚

sfr IAP_DATA = 0xe2;    // 定义IAP_DATA寄存器
sfr IAP_ADDRH = 0xe3;   // 定义IAP_ADDRH寄存器
sfr IAP_ADDRL = 0xe4;   // 定义IAP_ADDRL寄存器
sfr IAP_CMD = 0xe5;     // 定义IAP_CMD寄存器
sfr IAP_TRIG = 0xe6;    // 定义IAP_TRIG寄存器
sfr IAP_CONTR = 0xe7;   // 定义IAP_CONTR寄存器

// 函数声明
void delay(uint ms);
void startIIC();
void stopIIC();
void sendByte(uchar dat);
uchar receiveByte();
void writeDAC(uchar dat);
uchar readADC();

void main() {
    uchar mq4Value;
    
    while (1) {
        mq4Value = readADC();  // 读取ADC转换结果
        
        // 处理mq4Value值,进行相应操作
        
        delay(100);  // 延时一段时间
    }
}

// 延时函数
void delay(uint ms) {
    uint i, j;
    for(i = ms; i > 0; i--) {
        for(j = 110; j > 0; j--);
    }
}

// IIC总线起始信号
void startIIC() {
    SDA = 1;
    _nop_();
    SCL = 1;
    _nop_();
    SDA = 0;
    _nop_();
    SCL = 0;
    _nop_();
}

// IIC总线停止信号
void stopIIC() {
    SDA = 0;
    _nop_();
    SCL = 1;
    _nop_();
    SDA = 1;
    _nop_();
}

// 发送一个字节的数据
void sendByte(uchar dat) {
    uchar i;
    for (i = 0; i < 8; i++) {
        SDA = dat >> 7;
        _nop_();
        SCL = 1;
        _nop_();
        SCL = 0;
        _nop_();
        dat <<= 1;
    }
    SDA = 1;
    _nop_();
    SCL = 1;
    _nop_();
    SCL = 0;
    _nop_();
}

// 接收一个字节的数据
uchar receiveByte() {
    uchar i, dat = 0;
    SDA = 1;
    for (i = 0; i < 8; i++) {
        dat <<= 1;
        SCL = 1;
        _nop_();
        dat |= SDA;
        SCL = 0;
        _nop_();
    }
    return dat;
}

// 写入DAC数值
void writeDAC(uchar dat) {
    startIIC();
    sendByte(0x90);  // 地址和写命令
    receiveByte();   // 接收应答
    sendByte(0x40);  // DAC通道A,并写入数据
    receiveByte();   // 接收应答
    sendByte(dat);   // DAC数据
    receiveByte();   // 接收应答
    stopIIC();
}

// 读取ADC转换结果
uchar readADC() {
    uchar adcValue;
    
    startIIC();
    sendByte(0x91);   // 地址和读命令
    receiveByte();    // 接收应答
    adcValue = receiveByte();  // 读取ADC数据
    stopIIC();
    
    return adcValue;
}

4.2 OLED显示屏代码

以下是通过STC89C52控制IIC接口的OLED显示屏显示ADC数据实现代码。

#include <reg51.h>

#define SCL P1_0   // IIC时钟线
#define SDA P1_1   // IIC数据线

#define OLED_ADDR 0x78   // OLED显示屏的IIC地址

// OLED显示屏初始化函数
void OLED_Init() {
    // 初始化OLED显示屏
    // ...

    // 发送初始化命令到OLED显示屏
    // ...
}

// IIC总线开始信号
void IIC_Start() {
    SDA = 1;
    SCL = 1;
    SDA = 0;
    SCL = 0;
}

// IIC总线停止信号
void IIC_Stop() {
    SDA = 0;
    SCL = 1;
    SDA = 1;
}

// IIC总线发送一个字节的数据
void IIC_WriteByte(unsigned char dat) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        SCL = 0;
        if (dat & 0x80)
            SDA = 1;
        else
            SDA = 0;
        SCL = 1;
        dat <<= 1;
    }
    SCL = 0;
    SDA = 1;
    SCL = 1;
}

// 设置OLED显示屏光标位置
void OLED_SetPos(unsigned char x, unsigned char y) {
    IIC_Start();
    IIC_WriteByte(OLED_ADDR);
    IIC_WriteByte(0xb0 + y);
    IIC_WriteByte(((x & 0xf0) >> 4) | 0x10);
    IIC_WriteByte((x & 0x0f) | 0x01);
    IIC_Stop();
}

// 在OLED显示屏上显示一个字符
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch) {
    unsigned char c = 0, i = 0;
    c = ch - ' ';   // 获取字符在字库中的偏移量
    if (x > 128 - 8 || y > 64 - 16)
        return;   // 超出屏幕范围,退出函数
    OLED_SetPos(x, y);
    for (i = 0; i < 8; i++) {
        IIC_Start();
        IIC_WriteByte(OLED_ADDR);
        IIC_WriteByte(0x40);
        IIC_WriteByte(*(OLED_CharSet + c * 16 + i));
        IIC_Stop();
        x++;
    }
}

// 在OLED显示屏上显示字符串
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *str) {
    while (*str) {
        OLED_ShowChar(x, y, *str);
        x += 8;
        str++;
    }
}

// ADC模拟数值转换为字符串
void ADC_ToString(unsigned int adcValue, unsigned char *str) {
    unsigned char i, j;
    unsigned int temp;

    temp = adcValue;
    for (i = 0; i < 4; i++) {
        str[i] = temp % 10 + '0';
        temp /= 10;
    }

    // 反转字符串
    i = 0;
    j = 3;
    while (i < j) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        i++;
        j--;
    }
    str[4] = '\0';   // 字符串结束符
}

// 主函数
void main() {
    unsigned int adcValue = 0;
    unsigned char str[5];

    // 初始化OLED显示屏
    OLED_Init();

    while (1) {
        // 读取ADC数据
        adcValue = ADC_Read();   // 假设使用的函数为ADC_Read(),用于读取ADC数据

        // 将ADC数据转换为字符串
        ADC_ToString(adcValue, str);

        // 在OLED显示屏上显示ADC数据
        OLED_ShowString(0, 0, "ADC Value:");
        OLED_ShowString(0, 2, str);
    }
}

4.3 主代码逻辑

#include <reg51.h>

#define SCL P1_0    // IIC时钟线
#define SDA P1_1    // IIC数据线

#define OLED_ADDR 0x78    // OLED显示屏的IIC地址
#define MQ4_PIN P2      // MQ4传感器连接的引脚

sbit Buzzer = P3^0;    // 蜂鸣器控制引脚
sbit VentilationFan = P3^1;    // 换气扇控制引脚

// 全局变量
unsigned int alarmThreshold = 100;    // 报警阈值,默认为100
unsigned int adcValue = 0;    // 保存ADC采集到的数值

// IIC总线开始信号
void IIC_Start() {
    SDA = 1;
    SCL = 1;
    SDA = 0;
    SCL = 0;
}

// IIC总线停止信号
void IIC_Stop() {
    SDA = 0;
    SCL = 1;
    SDA = 1;
}

// IIC总线发送一个字节的数据
void IIC_WriteByte(unsigned char dat) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        SCL = 0;
        if (dat & 0x80)
            SDA = 1;
        else
            SDA = 0;
        SCL = 1;
        dat <<= 1;
    }
    SCL = 0;
    SDA = 1;
    SCL = 1;
}

// 设置OLED显示屏光标位置
void OLED_SetPos(unsigned char x, unsigned char y) {
    IIC_Start();
    IIC_WriteByte(OLED_ADDR);
    IIC_WriteByte(0xb0 + y);
    IIC_WriteByte(((x & 0xf0) >> 4) | 0x10);
    IIC_WriteByte((x & 0x0f) | 0x01);
    IIC_Stop();
}

// 在OLED显示屏上显示一个字符
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch) {
    unsigned char c = 0, i = 0;
    c = ch - ' ';    // 获取字符在字库中的偏移量
    if (x > 128 - 8 || y > 64 - 16)
        return;    // 超出屏幕范围,退出函数
    OLED_SetPos(x, y);
    for (i = 0; i < 8; i++) {
        IIC_Start();
        IIC_WriteByte(OLED_ADDR);
        IIC_WriteByte(0x40);
        IIC_WriteByte(*(OLED_CharSet + c * 16 + i));
        IIC_Stop();
        x++;
    }
}

// 在OLED显示屏上显示字符串
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *str) {
    while (*str) {
        OLED_ShowChar(x, y, *str);
        x += 8;
        str++;
    }
}

// ADC转换函数
unsigned int ADC_Convert(unsigned char channel) {
    ADC_CONTR = ADC_POWER | ADC_START | channel | ADC_SPEED;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    while (!(ADC_CONTR & ADC_FLAG))
        ;
    ADC_CONTR &= ~ADC_FLAG;
    return (ADC_RES * 256 + ADC_RESL);
}

// ADC模拟数值转换为字符串
void ADC_ToString(unsigned int adcValue, unsigned char *str) {
    unsigned char i, j;
    unsigned int temp;

    temp = adcValue;
    for (i = 0; i < 4; i++) {
        str[i] = temp % 10 + '0';
        temp /= 10;
    }

    // 反转字符串
    i = 0;
    j = 3;
    while (i < j) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        i++;
        j--;
    }
    str[4] = '\0';    // 字符串结束符
}

 主函数
void main() {
    unsigned char str[5];

    // 初始化OLED显示屏
    OLED_Init();

    // 设置初始报警阈值
    SetAlarmThreshold();

    while (1) {
        // 读取MQ4传感器的ADC数值
        adcValue = ADC_Convert(0);    // 假设MQ4传感器连接到ADC的通道0

        // 将ADC数值转换为字符串
        ADC_ToString(adcValue, str);

        // 在OLED显示屏上显示ADC数值
        OLED_ShowString(0, 0, "Gas Level:");
        OLED_ShowString(0, 2, str);

        // 判断是否触发报警
        if (adcValue > alarmThreshold) {
            // 触发报警
            ActivateAlarm();
        } else {
            // 取消报警
            DeactivateAlarm();
        }

        // 检测是否按下设置阈值的按键
        if (IsThresholdButtonPressed()) {
            // 设置报警阈值
            SetAlarmThreshold();
        }

        // 检测是否按下通风换气的按键
        if (IsVentilationButtonPressed()) {
            // 控制通风换气
            ControlVentilation();
        }
    }
}

http://www.kler.cn/a/108274.html

相关文章:

  • 力扣662:二叉树的最大宽度
  • 2024年11月12日Github流行趋势
  • HBase理论_背景特点及数据单元及与Hive对比
  • 实现 MVC 模式
  • GxtWaitCursor:Qt下基于RAII的鼠标等待光标类
  • Sigrity SPEED2000 Power Ground Noise Simulation模式如何查看PDS系统的自阻抗操作指导
  • 阿里云核心产品list
  • kubectl资源管理命令-陈述式
  • 深度学习使用Keras进行多分类
  • docker的安装部署nginx和mysql
  • Vue图片路径问题(动态引入)
  • uniapp 页面间传参方法
  • C/C++跨平台构建工具CMake-----灵活添加库并实现开发和生产环境的分离
  • 树上形态改变统计贡献:1025T4
  • Java实现Fisher‘s Exact Test 的置信区间的计算
  • GZ035 5G组网与运维赛题第3套
  • MySQL主从复制(基于binlog日志方式)
  • 电子器件 二极管
  • 尚硅谷Flume(仅有基础)
  • SSM咖啡点餐管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
  • JEnv使用初体验
  • Netty6 揭开BootStrap 的神秘面纱
  • go语言,yaml实现简单的workflow工作流
  • 汇编学习(1)
  • 国密 SM2 SSL 证书 Nginx 安装指南 linux版
  • 宝塔安装脚本