IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于51单片机和MQ135的室内空气检测净化系统设计 -> 正文阅读

[嵌入式]基于51单片机和MQ135的室内空气检测净化系统设计

1、前言

设计了一个基于51单片机的室内空气净化系统,所选用单片机型号为STC89C52,硬件部分包括字符型液晶显示屏lcd1602,空气检测传感器MQ135,小功率步进电机,排气扇,蜂鸣警报器,独立按键等。将程序烧入单片机进行验证,达到了预期的效果。

2、设计思路

本系统主要由4个模块所组成:
(1)数据采集模块
(2)数据/阈值显示模块
(3)阈值设置模块
(4)蜂鸣报警模块

系统设计简图如下图所示:
在这里插入图片描述
系统工作的主要流程如下:传感器MQ135采集数据接入单片机上的外部模拟量数据采集引脚(AIN3),经由xpt2046芯片进行AD模数转换,STC89C52对采集的数据作进一步处理转化成气体浓度(ppm)。当前环境下的气体浓度会与程序设计的阈值一并显示在LCD1602字符型液晶显示屏上。当所监测气体浓度超出阈值时,蜂鸣报警模块开始工作,发出蜂鸣警报声并开启排气扇进行排气。此外也可以人为地对阈值进行设置,以满足不同环境下的需求。

3、 系统硬件设计

3.1、MQ135传感器

1、简述:NQ135是一款对氨气、硫化物、苯系蒸汽等均有着高灵敏度的半导体气敏元件。其凭借着成本低、电路结构简单、功耗低等优点被广泛应用于日常生活生产中。
MQ135传感器实物图如下(背面):
在这里插入图片描述
2、重要技术指标:MQ135传感器的重要技术指标如下图所示:
在这里插入图片描述
3、引脚功能:从上文关于MQ135的实物图我们可以看出,MQ135一共有4个外接引脚,这4个引脚的功能分别是:
VCC:接5V直流电源输入
GND:接地
DO:模拟信号输出
AO:数字信号(TTL)输出
在本项目中,需要用杜邦线将VCC和GND引脚与单片机电源的正负极相接,DO引脚与开发板AIN3引脚相接(只采集模拟量),AO引脚不需要与任何引脚相接。
4、使用注意事项:在实际使用中应该考虑以下两点:(1)VCC与GND引脚不用与电源正负极反接,否则容易烧坏芯片。(2)从上文标准测试条件中可以看出,在使用MQ135之前应该先将MQ135传感器进行预热(即插电工作一段时间)后方可正常工作。

3.2、LCD1602液晶

1、简述:作为各类单片机实物设计的常用显示屏,LCD1602是一种专门用于显示字母、数字、符号等点阵式LCD,其1602是指LCD显示的内容为16X2,即可以显示两行,每行16个字符(1个汉字占用2个字符)。
2、LCD1602关键引脚说明:
RS :0=输入指令,1=输入数据
RW :0=向LCD写入指令或数据;1=从LCD读取信息
E :使能信号,1时读取信息,1->0(下降沿)执行指令
3、LCD1602基本操作时序:
1.1读状态:输入:RS=L,RW=H,E=H
----输出:D0~D7=状态字
1.2写指令:输入:RS=L,RW=L,D0~D7=指令码,E=高脉冲—>低脉冲
----输出:无
1.3读数据:输入:RS=H,RW=H,E=H
----输出:D0~D7=数据
1.4写数据:输入:RS=H,RW=L,D0~D7=数据码,E=高脉冲—>低脉冲
----输出:无

控制时序图:
(1)读操作时序图:
在这里插入图片描述
(2)写操作时序图:
在这里插入图片描述
4、LCD1602常用指令
LCD在使用的过程中,可以在RS=0、RW=0的情况下,向LCM写入一个字节的控制指令。使用的控制指令一共六个类别

(1)01H:清除DDRAM(显示数据存储器)的所有单元,光标被移动到屏幕左上角。
(2)02H:DDRAM所有单元的内容不变,光标移至左上角。
(3)输入方式设置(EnterModeSet),这些指令规定了两个方面:一是写入一个DDRAM单元后,地址指针如何改变(加一还是减一);二是屏幕上的内容是否滚动。
04H:写入DDRAM后,地址指针减一,比如第一个字符写入8FH,则下一个字符会写入8EH;屏幕上的内容不滚动。
05H:写入DDRAM后,地址指针减一,同上一种情况;每一个字符写入以后,屏幕上的内容向右滚动一个字符位。
06H:写入DDRAM后,地址指针加一,比如第一个字符写入80H,则下一个字符会写入81H;屏幕上的内容也是不滚动。这应该是最常用的一种显示方式。
07H:写入DDRAM后,地址指针加一,同上一种情况;每一个字符写入以后,屏幕上的内容向左滚动一个字符位。
(4)屏幕开关、光标开关、闪烁开关。
08H、09H、0AH、0BH:关闭显示屏,实质上是不把DDRAM中的内容对应显示在屏幕上,对DDRAM的操作还是在进行的,执行这条指令,接着对 DDRAM进行写入,屏幕上没有任何内容,但是接着执行下面的某条指令,就能看到刚才屏幕关闭期间,对DDRAM操作的效果了。
0cH:打开显示屏,不显示光标,光标所在位置的字符不闪烁。
0dH:打开显示屏,不显示光标,光标所在位置的字符闪烁。
0eH:打开显示屏,显示光标,光标所在位置的字符不闪烁。
0fH:打开显示屏,显示光标,光标所在位置的字符闪烁。
关于光标的位置:光标所在的位置指示了下一个被写入的字符所处的位置,加入在写入下一个字符前没有通过指令设置DDRAM的地址,那么这个字符就应该显示在光标指定的地方。
(5)设置光标移动(本质就是AC的增加还是减少)、整体画面是否滚动。
10H:每输入一次该指令,AC就减一,对应了光标向左移动一格。整体的画面不滚动。
14H:每输入一次该指令,AC就加一,对应了光标向右移动一格。整体的画面不滚动。
18H:每输入一次该指令,整体的画面就向左滚动一个字符位。
1CH:每输入一次该指令,整体的画面就向右滚动一个字符位。画面在滚动的时候,每行的首尾是连在一起的,
也就是每行的第一个字符,若左移25次,就会显示在该行的最后一格。在画面滚动的过程中,AC的值也是变化的。
(6)显示模式设定指令,设定了显示几行,显示什么样的点阵字符,数据总线占用几位。
20H:4位总线,单行显示,显示5×7的点阵字符。
24H:4位总线,单行显示,显示5×10的点阵字符。
28H:4位总线,双行显示,显示5×7的点阵字符。
2CH:4位总线,双行显示,显示5×10的点阵字符。
30H:8位总线,单行显示,显示5×7的点阵字符。
34H:8位总线,单行显示,显示5×10的点阵字符。
38H:8位总线,双行显示,显示5×7的点阵字符。这是最常用的一种模式。
3CH:8位总线,双行显示,显示5×10的点阵字符。

3.3、XPT2046芯片

1、简述:XPT2046芯片是一款典型的逐次逼近型模数转换器(SAR ADC),包含了采样/保持、模数转换、串口数据输出等功能。
2、典型应用电路:
在这里插入图片描述
3、重要引脚功能描述:
CS:片选信号,控制转换时序和使能串行输入输出寄存器,当CS为低电平时芯片正常工作。
DIN:串行数据输入端,当CS为低电平时,数据在DCLK上升沿时串行输入。
DCLK:外部时钟信号输入
DOUT:串行数据输出端,当CS为低电平时,数据在DCLK下降沿时串行输出。
4、典型工作方式:
XPT2046芯片的典型工作方式如下图所示:
在这里插入图片描述
工作方式解析:前 8 个时钟用来通过DIN引脚输入控制字节,接着的12 个时钟周期将完成真正的模数转换,剩下的3个多时钟周期将用来完成被转换器忽略的最后字节(DOUT置低)。
5、外接典型应用电路:
在这里插入图片描述
有4个外部接口:
AIN0:检测转换电位器模拟信号,信号采集地址为0x94或者0xB4
AIN1:检测转换热敏电阻模拟信号,信号采集地址为0xD4
AIN2:检测转换光敏电阻模拟信号,信号采集地址为0xA4
AIN3:检测转换AIN3通道上模拟信号,信号采集地址为0xE4

4、 系统软件设计

4.1、算法状态机(ASM)图

针对上文关于系统模块的描述以及项目具体的功能需要,为了明晰编程思路,画出算法状态机(ASM)图如下所示:
在这里插入图片描述

4.2、传感器数据处理

从MQ135空气质量传感器所检测的数值需要经由模拟量—>数字量—>气体浓度的变换,其中数字量—>气体浓度遵循这如下规律:没有被测气体的环境,设定传感器输出电压值为参考电压,这时,aout端的电压在1v左右,当传感器检测到被测气体时,电压每升高0.1v,实际被测气体的浓度增加20ppm(简单的说:1ppm=1mg/kg=1mg/l=1×10-6 常用来表示气体浓度,或者溶液浓度),根据这个参数就可以在单片机里面将测得的模拟量电压值转换为浓度值。然后再经由AIN3所测得的数值与真实的数值进行线性拟合得出相应表达式:
value(ppm) = (int)(0.236 * (value(ad) - 12.8623));
由于所测数据点样本较少,得出的拟合结果公式可能会与真实值存在小范围的偏差,但经过实际测试发现并不影响实际使用,在一定0~5V的电压范围内所测的气体浓度与真实值接近。

4.3、工程具体代码

此项工程的具体代码如下所示,注意单片机型号!不同型号的单片机所对应的具体引脚值会有所不同,具体请查看单片机开发原理图。此外,对于
XPT2046.H

/**
 *@file      XPT2046.H
 *@brief     封装模数转换器xpt2046芯片的相应功能引脚,声明相应函数
 *@details   与51单片机采用串口通信的方式进行数据交换
 *@author    青渡
 *@version   V1.1.0
 *@date      2021-04-05
 */
#ifndef __xpt2046_H_
#define __xpt2046_H_

#include "reg52.h"
#include "intrins.h"

#ifndef u8
#define u8 unsigned char
#endif

#ifndef u16
#define u16 unsigned int
#endif

/**输出引脚*/
sbit DOUT = P3^7;
/**时钟引脚*/
sbit CLK = P3^6;
/**输入引脚*/
sbit DIN = P3^4;
/**片选引脚*/
sbit CS = P3^5;

u16 read_ad_data(u8 cmd);
u16 SPI_read();
void SPI_write(u8 dat);

#endif

LCD1602.H

/**
 *@file      LCD1602.H
 *@brief     封装字符型液晶lcd1602的相应功能引脚,声明相应函数
 *@details   注意所采用的lcd1602是4位输入还是8位输入,如果是4位输入
             则应该添加语句#define LCD1602_4PINS 
 *@author    青渡
 *@version   V1.1.0
 *@date      2021-04-05 
 */
#ifndef __lcd1602_H_
#define __lcd1602_H_  
 								  	
#include"reg52.h"

/*#define LCD1602_4PINS*/ 
#ifndef uchar8
#define uchar8 unsigned char
#endif

#ifndef	uint16
#define uint16 unsigned int
#endif

#define lcd_data P0
/**读写选择*/	 
sbit lcd_RW = P2^5;
sbit lcd_RS = P2^6;
/**使能端*/
sbit lcd_E = P2^7;

void delay(uint16 i);
void lcd_writecom(uchar8 com);
void lcd_writedat(uchar8 dat);
void lcdinit();
void lcd_stringwrite(uchar8 com, uchar8 *s);

#endif

xpt2046.c

/**
 *@file      xpt2046.c
 *@brief     配置xpt2046芯片的读写函数,读取相应模拟量数据
 *@details	 无
 *@author    青渡
 *@version   V1.1.0
 *@date      2021-04-05
 */
#include "xpt2046.h"

/**
 *@brief     编写xpt2046的写数据函数
 *@details   写入的是采集模拟量的地址,数据进行串行输入
 *@param     dat  8位数据
 *@retval    无
 */
void SPI_write(u8 dat)
{
  u8 i = 0;
  CLK = 0;
  for(i = 0; i <= 7; i++)
  {
    DIN = dat>>7;
	dat = dat<<1;
	CLK = 0;
	/**延迟一个机器周期以形成相应沿信号*/
	_nop_();
	CLK = 1;
  }
}

/**
 *@brief     编写xpt2046的读数据函数
 *@details   DOUT为串行数据输出,需要一位一位地进行读取
 *@param     无
 *@retval    dat  16位处理后数据
 */
u16 SPI_read()
{
  u8 i = 0;
  u16 dat = 0;
  for(i = 0; i <= 11; i++)
  {
    dat = dat<<1;
	CLK = 1;
	_nop_();
	CLK = 0;
	dat |= DOUT;
  }
  return dat;
}

/**
 *@brief     根据xpt2046芯片的通信时序实例化输出数字信号
 *@details   根据相应时序初始化相对应的标志位
 *@param     cmd  8位数据采集地址
 *@retval    value  16位输出数字量
 */
u16 read_ad_data(u8 cmd)//模拟AD模数转换过程
{
  u8 i;
  u16 value;
  CLK = 0;
  CS = 0;
  SPI_write(cmd);
  for(i = 6; i >0; i--);
  CLK = 1;
  _nop_();
  _nop_();
  CLK = 0;
  _nop_();
  _nop_();
  value = SPI_read();
  /**通信结束置CS为高电平*/
  CS = 1;
  return value;
}

lcd1602.c

/**
 *@file      lcd1602.c
 *@brief     配置lcd1602的读写函数,实现显示功能
 *@details   对于4位和8位的输入应编写相对应的函数,不能混用
 *@author    青渡
 *@version   V1.1.0
 *@date      2021-04-05
 */
#include "lcd1602.h"

/*基本延时函数*/
void delay(uint16 i)
{
  while(i--);
}

/**
 *@brief     编写lcd1602的写指令函数
 *@details   注意操作时序RS=L,RW=L,D0~D7=指令码,E=高脉冲->低脉冲
 *@param     com 8位控制指令
 *@retval    无
 */
#ifndef LCD1602_4PINS
void lcd_writecom(uchar8 com)
{
  lcd_RS = 0;
  lcd_RW = 0;
  lcd_E = 0;
  lcd_data = com;
  delay(200);
  lcd_E = 1;
  delay(1000);
  lcd_E = 0;
}

#else
void lcd_writecom(uchar8 com)
{
  lcd_RS = 0;
  lcd_RW = 0;
  lcd_E = 0;
  lcd_data = com;
  delay(200);
  lcd_E = 1;
  delay(1000);
  lcd_E = 0;

  lcd_data = com<<4;
  delay(200);
  lcd_E = 1;
  delay(1000);
  lcd_E = 0;
}
#endif

/**
 *@brief     编写lcd1602的写数据函数
 *@details   RS=H,RW=L,D0~D7=数据,E=高脉冲->低脉冲
 *@param     dat 8位数据
 *@retval    无
 */
#ifndef LCD1602_4PINS 
void lcd_writedat(uchar8 dat)
{
  lcd_RS = 1;
  lcd_RW = 0;
  lcd_E = 0;
  lcd_data = dat;
  delay(200);
  lcd_E = 1;
  delay(400);
  lcd_E = 0;
}

#else 
void lcd_writedat(uchar8 dat)
{
  lcd_RS = 1;
  lcd_RW = 0;
  lcd_E = 0;
  lcd_data = dat;
  delay(200);
  lcd_E = 1;
  delay(400);
  lcd_E = 0;

  lcd_data = dat<<4;
  delay(200);
  lcd_E = 1;
  delay(400);
  lcd_E = 0;
}
#endif

/**
 *@brief     编写lcd1602的初始化函数,写入相应控制指令
 *@details   无
 *@param     无
 *@retval    无
 */
#ifndef LCD1602_4PINS
void lcdinit()
{
  lcd_writecom(0x38);
  lcd_writecom(0x0c);
  lcd_writecom(0x06);
  lcd_writecom(0x01);
}

#else 
void lcdinit()
{
  /**将8位总线转化成4位总线*/
  lcd_writecom(0x32);
  lcd_writecom(0x28);
  lcd_writecom(0x0c);
  lcd_writecom(0x06);
  lcd_writecom(0x01);
}
#endif

/**
 *@brief     实例化lcd1602的写数据函数
 *@details   lcd1602是字符型液晶,只能接受char类型的数据输入
 *@param     com  8位控制指令  *s  输入数据的地址
 *@retval    无
 */
void lcd_stringwrite(uchar8 com, uchar8 *s)
{
  lcd_writecom(com);
  while(*s > 0)
  {
    lcd_writedat(*s++);
  }
}  

main.c

/**
 *@file      main.c
 *@brief     配置室内空气净化系统的相应功能
 *@details	 无
 *@author    青渡
 *@version   V1.1.0
 *@date      2021-04-05
 */
#include "reg52.h"
#include "lcd1602.h"
#include "xpt2046.h"

sbit beep = P1^5;
sbit power = P1^0;
sbit key1 = P3^1;
sbit key2 = P3^0;
sbit key3 = P3^2;
uint16 value;
uchar8 token,num;
uchar8 threshold;
uchar8 code str1[] = "GAS:";
uchar8 code str2[] = "SET:";
uchar8 code math[] = "0123456789";

/**定时器0的中断初始配置*/
void timecontrol()
{
  EA = 1;
  ET0 = 1;
  TR0 = 0;
  TMOD |= 0x01;
  TH0 = 0xFC;
  TL0 = 0x18;
}

/**定时器1的中断初始配置*/
void timecon()
{
  EA = 1;
  ET1 = 1;
  TR1 = 0;
  TMOD |= 0x10;
  TH1 = 0xFC;
  TL1 = 0x18;
}

/**定时器0的中断服务函数*/
void timecontrol1()interrupt 1
{
/**无功能用途可设置为空*/
}

/**定时器1的中断服务函数*/
void timecon1()interrupt 3
{
  uchar8 i;
  /**蜂鸣器配置*/
  for(i = 10 ; i > 0; i--)
  {
  beep =~ beep;
  delay(100);
  }
}

/**
 *@brief     实现通过按键设置阈值,暂停的功能
 *@details	 key1用以暂停,key2用以增大阈值,key3用于减小阈值
 *@param     无
 *@retval    无
 */
void dataset()
{
  /**将num设置成静态变量*/
  static num = 0;
  if(key1 == 0)
  {
    /**按键消抖,触发定时器0中断*/
    TR0 = 1;
	if(key1 == 0)
	{
	  token = 0;
	  num = num + 1;
	}
	/**等待按键松开*/
	while(!key1);
  }
  if(num == 2)
  {
    num = 0;
	token = 1;
  }

  /**当程序处在暂停状态下*/
  if(key2 == 0&&num == 1)
  {
    TR0 = 1;
	if(key2 == 0&&num == 1)
	{
	  threshold = threshold+1;
	  if(threshold > 200)
	  {
	    threshold = 200;
	  }
	}
	while(!key2);
  }
  
  if(key3 == 0&&num == 1)
  {
    TR0 = 1;
	if(key3 == 0&&num == 1)
	{
	  threshold = threshold - 1;
	  if(threshold < 0)
	  {
	    threshold = 0;
	  }
	}
	while(!key3);
  }
}

/**
 *@brief     实现对传感器数据的处理
 *@details	 实现对外部模拟量测量值——>电压值——>气体浓度值的转换
 *@param     无
 *@retval    无
 */
void datadispose()
{
  /**0xE4是外部输入AD值的地址,value为实际检测气体浓度值*/
  value = read_ad_data(0xE4);
  value = (int)(0.236 * (value - 12.8623));

  /**当程序处在正常运行状态下且气体浓度值超出阈值时,排气扇转动并发出蜂鸣声预警*/
  if(value >= threshold&&token == 1)
  {
    /**触发定时器1中断*/
    TR1 = 1;
    power = 1;
  }
  else
  { 
    TR1 = 0;
    power = 0;
  }
}

/**
 *@brief     将相对应的数据显示在lcd1602液晶屏上
 *@details   注意对应数据在液晶屏上的写入地址
 *@param     无
 *@retval    无
 */
void datadisplay()
{
  uchar8 a, b, c, d, i, j, k, l;
  a = value/1000;
  b = value%1000/100;
  c = value%1000%100/10;
  d = value%1000%100%10;

  i = threshold/1000;
  j = threshold%1000/100;
  k = threshold%1000%100/10;
  l = threshold%1000%100%10;
 
  /**第一行最左侧的写入地址是0x80,第二行最左侧的写入地址是0xc0*/
  lcd_stringwrite(0x80, &str1);
  lcd_stringwrite(0xc0, &str2);
  /**一个字符占用1位存储地址*/
  lcd_writecom(0x84);
  lcd_writedat(math[a]);
  lcd_writedat(math[b]);
  lcd_writedat(math[c]);
  lcd_writedat(math[d]);
  lcd_writecom(0xc4);
  lcd_writedat(math[i]);
  lcd_writedat(math[j]);
  lcd_writedat(math[k]);
  lcd_writedat(math[l]);
}

/**
 *@brief     主函数,集成模块功能
 *@details   初值的设置以及相应的硬件配置初始化应放在while(1)循环外
 *@param     无
 *@retval    无
 */
void main()
{
  beep = 1;
  token = 1;
  power = 0;
  threshold = 80;
  timecontrol();
  timecon();
  /*将lcd1602的初始化函数放在while循环外,避免占用时序导致屏幕闪烁*/
  lcdinit();
  while(1)
  {
	  dataset();
	  datadisplay();
	  datadispose();
  }
}

5、项目部分成果展示

在这里插入图片描述
写在最后:若对本文内容存在质疑或疑惑,欢迎提出指正,一起学习进步!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-10 14:41:08  更:2021-07-10 14:42:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:30:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计