大二时候的单片机课程设计希望对大家有帮助,也是在51黑大佬们的帮助下完成的。
附件中包括原理图 pcb 程序源码工程文件 以及设计报告
Altium Designer画的火灾烟雾声光报警器电路原理图和PCB图如下:(51hei附件中可下载工程文件)
目录
1设计指标及要求
1.1设计要求
1.2设计指标
2 系统方案设计
2.1 系统方案设计
3 系统硬件电路设计
3.1 单片机最小系统
3.1.1复位电路
3.1.2时钟电路
3.2 数模转换电路
3.3 液晶显示电路
3.4 烟雾监测电路
3.5温度监测及按键电路
4 系统软件设计
4.1系统软件结构
5.系统调试
结 论
参 考 文 献
附录A 系统硬件电路图
附录B 实物照片
附录C 程序代码
1设计指标及要求
1.1设计要求
设计一个简单、实用的基于单片机室内火灾报警系统(模拟机),对火灾的实时、准确监测,快速、自动报警,该系统能自动完成对布测点的火情检测即气体温度、浓度,设定一个温度,由液晶显示屏会看到温度变化,如果超过设定温度就会自动报警,报警形式有声音和灯光闪烁,。要求报警时输出一个状态指示信号,用一个LED点亮示意。
1.2设计指标
选择一款合适的烟雾传感器,在兼顾检测精度的同时尽量降低成本用于前端检测电路之用;
以51单片机为核心对烟雾浓度进行实时检测,检测结果可通过数码管、液晶或者其他方式进行显示;
检测结果与阈值进行比较,通过启动蜂鸣器达到超限报警的功能,并触发继电器闭合。
2 系统方案设计
2.1 系统方案设计本设计以STC89C51单片机为系统的核心处理芯片,通过烟雾传感器MQ-2模块及温度传感器DS18B20进行检测环境中的烟雾浓度及温度进行实施监测,同时也采用ADC0832数模转换模块将烟雾传感器所采集到的烟雾值转化为电压值从而传递给核心处理芯片,通过核心处理芯片STC89C51单片机对数据进行,并且将其监测到的温度和烟雾浓度通过LcD1602液晶显示屏幕进行显示。 预设温度过高和烟气浓度过高报警的临界值,如果探测所得数据超过报警值,便接通蜂鸣器和LED灯开始报警;如果没有达到报警临街值则继续正常工作;如果收到的是报警按键信号,则立即报警。同时无论哪种情况显示模块都正常显示温度和烟雾浓度。 系统工作原理框图如2.1所示:

图2.1 系统结构图
3 系统硬件电路设计3.1 单片机最小系统最小系统包括单片机及其所需的必要的电源、时钟、复位等部件,能使单片机始终处于正常的运行状态。电源、时钟等电路是使单片机能运行的必备条件,可以将最小系统作为应用系统的核心部分,通过对其进行存储器扩展、A/D扩展等,使单片机完成较复杂的功能。 STC89C51是片内有ROM/EPROM的单片机,因此,这种芯片构成的最小系统简单﹑可靠。用STC89C52单片机构成最小应用系统时,只要将单片机接上时钟电路和复位电路即可,由于集成度的限制,最小应用系统只能用作一些小型的控制单元。单片机最小系统如图3.1所示. 
图3.1单片机最小系统原理图 3.1.1复位电路当在STC89C51单片机的RST引脚引入高电平并保持2个机器周期时,单片机内部就执行复位操作(若该引脚持续保持高电平,单片机就处于循环复位状态)。 最简单的上电自动复位电路中上电自动复位是通过外部复位电路的电容充放电来实现的。只要Vcc的上升时间不超过1ms,就可以实现自动上电复位。 除了上电复位外,有时还需要按键手动复位。本设计就是用的按键手动复位。按键手动复位有电平方式和脉冲方式两种。其中电平复位是通过RST(9)端与电源Vcc接通而实现的。 
图3.2 STC89C51复位电路
3.1.2时钟电路STC89C51单片机的时钟信号通常有两种方式产生:一是内部时钟方式,二是外部时钟方式。在STC89C51单片机内部有一振荡电路,只要在单片机的XTAL1(18)和XTAL2(19)引脚外接石英晶体(简称晶振),就构成了自激振荡器并在单片机内部产生时钟脉冲信号。图中电容C1和C2的作用是稳定频率和快速起振,电容值在5~30pF,典型值为30pF。晶振CYS的振荡频率范围在1.2~12MHz间选择,典型值为12MHz和6MHz。时钟电路原图如3.3所示。 
图3.3 STC89C51内部时钟电路
3.2 数模转换电路在数模转换电路部分,我们最开始有两种选择方案。 方案一:采用ADC0809数模转换芯片对采集到的电压转化为数字量。 方案二:采用ADC0832数模转换芯片对烟雾浓度进行处理使其转换为数字量。 首先在在方案选择上面,ADC0809是一种8位并行的A/D转换芯片,如果使用方案一,则单片机的I/O口占用则会比较多。而且ADC0809的外部电路连接复杂。对于方案二,ADC0832虽然是一种串行A/D转换芯片,处理速度也较ADC0809慢很多,但是由于其外部电路连接简单,占用I/O口较少,因此我们选用方案二。 ADC0832 具体资料如下: · CS_片选使能,低电平芯片使能。 · CH0 模拟输入通道0,或作为IN+/-使用。 · CH1 模拟输入通道1,或作为IN+/-使用。 · GND 芯片参考0 电位(地)。 · DI 数据信号输入,选择通道控制。 · DO 数据信号输出,转换数据输出。 · CLK 芯片时钟输入。 · Vcc/REF 电源输入及参考电压输入(复用)。 ADC0832 为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在0~5V之间。芯片转换时间仅为32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。独立的芯片使能输入,使多器件挂接和处理器控制变的更加方便。通过DI 数据输入端,可以轻易的实现通道功能的选择。其硬件连接如图3.3所示。 
图3.4 ADC0832 连接图
3.3 液晶显示电路LCD1602的引脚RS,RW,E,DBO,DB1,DB2,DB3,DB4,DB5,DB6,DB7分别接到单片机P20,P26,P27,P00,P01,P02,P03,P04,P05,P06,P07进行与单片机的通信,以便于显示出单片机所要求要显示的字符。本部分硬件连接情况就是这样,软件系和几部分第四部分有更详细的说明。 由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。因此,液晶显示器画质高且不会闪烁。 液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。 液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多。 相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。并且在考虑系统耗电及供电的问题我们采用了LCD1602液晶显示屏幕。 (1)引脚说明: 第1脚:VSS为地电源。 第2脚:VDD接5V正电源。 第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。 第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平 R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。 第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。 
图3.5 lcd1602液晶显示图
3.4 烟雾监测电路MQ-2接烟雾调理电路,其实质也就是一个电压比较器电路,当检测到烟雾浓度传感器模块输出一个模拟量给设计中所使用的A/D转换芯片ADC0832,将模拟量转化为数字量,传递给单片机使单片机对数据进行处理,从而实现烟雾的检测功能。烟雾传感器检测电路的实质就是可变电阻街上电压比较器,在感受到外界环境变化时电阻发生变化,输出电压随电阻的阻值而发生变化,并且通过后面所接的电压比较器输出连接ADC0832的CH0端AD转换器对电压进行转换。将数据送给单片机进行处理。 MQ-2型气敏元件具有以下特点: (1) 采用烧结半导体所形成的敏感烧结体,具有稳定的R (即器件在纯洁空气中的阻抗)阻值,从而保证了长期工作的稳定性。 (2) 单电源供电,其功耗仅0.7W左右。 (3) 对所测试的气体有极高的灵敏度和信噪比。 MQ-2型气敏元件有两种型号。MQ-2A型适用于天然气、城市煤气、石油液化气、丙丁烷及氢气等;MQ-2型适用于烟雾等减光型有害气体。 器件的灵敏度:S=Ro/Rx为10~30。常见为QM系列的S值仅8左右。Rx为器件在丁烷浓度为0.2%时的阻抗。电路如下图所示。 
图3.6 MQ-2模块原理图
3.5温度监测及按键电路温度传感器我们之所以采用DS18B20,是因为其硬件电路连接相对于其他温度传感器来说连接较简单,并且在软件设计方面我们书中有详细的例程介绍。它采用单根信号线,既传输时钟又传输数据,而且数据传输是双向的,具有节省I/O口线资源、结构简单、成本低廉、便于总线扩展和维护等诸多优点。但是值得注意的是DS18B20在连接时余姚在二号引脚接一个上拉电阻。 DS18B20 的特点及内部构造 特点如下: ①采用独特的单总线接口方式,即只有一根信号线与控制器相连,实现数据的双向通信,不需要外部元件; ②测量结果直接输出数字温度信号,以单总线串行传送给控制器,同时可传送CRC校验码,具有极强的抗干扰纠错能力; ③支持多点组网功能,多个DS18B20可以并联在唯一的三根线上,实现组网多点测量; ④适应电压范围宽3.0-5.5V,不需要备份电源、可用数据线供电,温度测量范围为-55℃~125℃,-10℃~85℃时测量精度为±0.5℃; ⑤通过编程可实现9~12位的数字值读数方式,对应的可分辨温度分别为0.5℃,0.25℃,0.125℃,0.0625℃,实现高精度测温; ⑥负压特性。电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。 封装图及内部构造,如下图所示。 
图3.7 DS18B20外部结构框图 本设计采用按键接低的方式来读取按键,单片机初始时,因为为高电平,当按键按下的时候,会给单片机一个低电平,单片机对信号进行处理 单片机键盘有独立键盘和矩阵式键盘两种:独立键盘每一个I/O 口上只接一个按键,按键的另一端接电源或接地(一般接地),这种接法程序比较简单且系统更加稳定;而矩阵式键盘式接法程序比较复杂,但是占用的I/O少。根据本设计的需要这里选用了独立式键盘接法。 
图3.8 温度传感器及按键电路
4 系统软件设计4.1系统软件结构本设计根据硬件结构,软件设计共分成以下几大部分: Main函数是整个程序最主要的一部分同时也时产品是否能够达到与其设计目标的根本所在,首先主函数调用1602函数显示开机界面,而后进行烟雾以及温度的监测,此时主函数对ADC0832函数进行调用,将模拟量转换为数字传递给单片机后通过主程序进行实时监控。主函数中也声明了按键函数,用户可通过按键对整个系统检测的范围进行调节。主函数流程图如4.2所示 
图4.1 主函数流程图 我们对于整个系统所监测到的数据进行显示采用1602液晶显示屏幕,首先将其初始化,而后对进行字节的读写,使其根据监测到数据进行不断读取显示。显示函数程序设计流程图如4.2所示。 
图4.2 显示函数设计流程图 数模转换我们采用ADC0832芯片,我们将DO和DI并联在一根数据线上使用。当ADC0832未工作时其CS输入端应为高电平,此时芯片禁用,CLK 和DO/DI 的电平可任意。当要进行A/D转换时,须先将CS使能端置于低电平并且保持低电平直到转换完全结束。此时芯片开始转换工作,同时由处理器向芯片时钟(CLK)输入端输入时钟脉冲,DO/DI端则使用DI端输入通道功能选择的数据信号。在第一个时钟脉冲的下沉之前DI端必须是高电平,表示启始信号。在第二、三个脉冲下沉之前DI端应输入两位数据用于 选择通道功能。 Ds18b20。温度传感器函数参考单片机教材251页中ds18b20例程。
5.系统调试调试过程中首先要检测的就是硬件电路的设计原理是否正确,所以在我们进行设计原理图时就查阅了大量的资料,包括烟雾传感器及温度传感器电路的选择,在进行电路图设计结束进行排版布局以及布线时,我们使用两台电脑,对原理图及pcb图纸进行对照,一个点一个点一根线一线的进行检查,从而为后来的硬件焊接后的调试打下了基础,其次在焊接好难有线电路之后,认真检查电路的焊接情况。这次采用的是分块调试的方法,烟雾探测电路,控制电路以及单片机控制电路进行调试。在对每个模块的进行调试过程中又采用了由局部到整体,由简单到复杂的调试方法,最后再将各个模块总和成一个整体。 在软件系统调试方面。首先我们的硬件检查与我们所设计的原理图基本吻合,在硬件完好的基础上我们着重于软件设计,首先我们进行分模块编程,参考单片机C语言教程,以及上学期我们所用的单片机课本,这两本书里面都有关于DS 18B20以及lcd1602及独立键盘部分的例程,我们首先参考lcd1602例程,首先点亮了液晶显示屏,因此也证明我们的单片机最小系统是完好的,并且对各个模块的程序进行资料搜索并用我们所学的知识进行程序的编写,调试。
结 论通过本次课程设计,从一开始的无从下手,而后也在老师的指导下在百度上搜集一些关于烟雾检测类型的课题资料。再对原理图进行设计时,我们也发现有些部分电子元器件数值在仿真中可以实现但是在现实中会出现不一样的现象所以我们通过计算将每一个电阻阻值都计算的非常精细。并且在完成原理图及PCB设计后,我们通过PCB和原理图进行对照对每一个点都进行了查证,从而也保证了我们后面系统调试时在硬件电路上没有耗费太多的时间。 当我们拿到我们设计的PCB板子进行焊接完成后便开始进行了软件设计,我们首先进行一个模块一各模块的检测,这种方法也帮助我们验证了单片机各个功能是否正常。用软件对硬件进行检测完毕后,我们便进行了整体的电路软件设计,因为我们组组员曾经做过关于温度测量的课题,我们在进行温度传感器程序编写时便显得轻车熟路。数模转换部分在芯片手册中也由相关的例程,我们对照我们自己的单片机接口对程序也进行了修改,并且将烟雾和温度显示在1602显示屏幕进行的调整。
附录A 系统硬件电路图
附录B 实物照片
单片机源程序如下:
- #include <reg52.h>
- #include <intrins.h>
- #define u8 unsigned char
- #define u16 unsigned int
- #define uchar unsigned char
- #define uint unsigned int
- uchar wendu=0;
- uchar yanwu=0;
- uint shezhiwendu;
- uchar shezhiyanwu;
- uchar Mode=0;
- sbit LedRed=P2^2;
- sbit LedYellow=P2^4;
- sbit Buzzer=P2^0;
- sbit LCDRS=P2^7;
- sbit LCDEN=P2^6;
- sbit D0= P0^0;
- sbit D1= P0^1;
- sbit D2= P0^2;
- sbit D3= P0^3;
- sbit D4= P0^4;
- sbit D5= P0^5;
- sbit D6= P0^6;
- sbit D7= P0^7;
- void delay(uint z)
- {
- uint i,j;
- for(i=0;i<z;i++)
- for(j=0;j<110;j++);
- }
- void LCDdelay(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=10;y>0;y--);
- }
- void LCD_WriteData(u8 dat)
- {
- if(dat&0x01)D0=1;else D0=0;
- if(dat&0x02)D1=1;else D1=0;
- if(dat&0x04)D2=1;else D2=0;
- if(dat&0x08)D3=1;else D3=0;
- if(dat&0x10)D4=1;else D4=0;
- if(dat&0x20)D5=1;else D5=0;
- if(dat&0x40)D6=1;else D6=0;
- if(dat&0x80)D7=1;else D7=0;
- }
- void write_com(uchar com)
- {
- LCDRS=0;
- LCD_WriteData(com);
- LCDdelay(5);
- LCDEN=1;
- LCDdelay(5);
- LCDEN=0;
- }
- void write_data(uchar date)
- {
- LCDRS=1;
- LCD_WriteData(date);
- LCDdelay(5);
- LCDEN=1;
- LCDdelay(5);
- LCDEN=0;
- }
- void SelectPosition(unsigned char x,unsigned char y)
- {
- if (x==0)
- {
- write_com(0x80+y);
- }
- else
- {
- write_com(0xC0+y);
- }
- }
- void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
- {
- SelectPosition(x,y) ;
- while (*s)
- {
- write_data( *s);
- s ++;
- }
- }
- void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
- {
- SelectPosition(x,y) ;
- if(l>=5)
- write_data(0x30+s/10000%10);
- if(l>=4)
- write_data(0x30+s/1000%10);
- if(l>=3)
- write_data(0x30+s/100%10);
- if(l>=2)
- write_data(0x30+s/10%10);
- if(l>=1)
- write_data(0x30+s%10);
- }
- void Init1602()
- {
- uchar i=0;
- write_com(0x38);
- write_com(0x0c);
- write_com(0x06);
- write_com(0x01);
-
- }
- void Display_1602(shezhiwendu,shezhiyanwu,c,temp)
- {
- LCD_Write_Char(0,6,shezhiwendu,2) ;
- LCD_Write_Char(0,13,shezhiyanwu,3) ;
- //wendu
- LCD_Write_Char(1,6,c/10,2) ;
- write_data('.');
- LCD_Write_Char(1,9,c%10,1) ;
- //yanwu
- LCD_Write_Char(1,13,temp,3) ;
- }
- //ad0832 函数
- sbit ADCS =P1^5;
- sbit ADCLK =P1^2;
- sbit ADDI =P1^3;
- sbit ADDO =P1^3;
- unsigned int Adc0832(unsigned char channel)
- {
- uchar i=0;
- uchar j;
- uint dat=0;
- uchar ndat=0;
- uchar Vot=0;
- if(channel==0)channel=2;
- if(channel==1)channel=3;
- ADDI=1;
- _nop_();
- _nop_();
- ADCS=0;//拉低CS端
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿1
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- ADDI=channel&0x1;
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿2
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- ADDI=(channel>>1)&0x1;
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿3
- ADDI=1;//控制命令结束
- _nop_();
- _nop_();
- dat=0;
- for(i=0;i<8;i++)
- {
- dat|=ADDO;//收数据
- ADCLK=1;
- _nop_();
- _nop_();
- ADCLK=0;//形成一次时钟脉冲
- _nop_();
- _nop_();
- dat<<=1;
- if(i==7)dat|=ADDO;
- }
- for(i=0;i<8;i++)
- {
- j=0;
- j=j|ADDO;//收数据
- ADCLK=1;
- _nop_();
- _nop_();
- ADCLK=0;//形成一次时钟脉冲
- _nop_();
- _nop_();
- j=j<<7;
- ndat=ndat|j;
- if(i<7)ndat>>=1;
- }
- ADCS=1;//拉低CS端
- ADCLK=0;//拉低CLK端
- ADDO=1;//拉高数据端,回到初始状态
- dat<<=8;
- dat|=ndat;
- return(dat); //return ad data
- }
- // 温度传感器模块代码 单片机教材
- sbit DQ = P1^0;
- void Delay_DS18B20(int num)
- {
- while(num--) ;
- }
- void Init_DS18B20(void)
- {
- unsigned char x=0;
- DQ = 1;
- Delay_DS18B20(8);
- DQ = 0;
- Delay_DS18B20(80);
- DQ = 1;
- Delay_DS18B20(14);
- x = DQ;
- Delay_DS18B20(20);
- }
- unsigned char ReadOneChar(void)
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--)
- {
- DQ = 0;
- dat>>=1;
- DQ = 1;
- if(DQ)
- dat|=0x80;
- Delay_DS18B20(4);
- }
- return(dat);
- }
- void WriteOneChar(unsigned char dat)
- {
- unsigned char i=0;
- for (i=8; i>0; i--)
- {
- DQ = 0;
- DQ = dat&0x01;
- Delay_DS18B20(5);
- DQ = 1;
- dat>>=1;
- }
- }
- unsigned int ReadTemperature(void)
- {
- unsigned char a=0;
- unsigned char b=0;
- unsigned int t=0;
- float tt=0;
- Init_DS18B20();
- WriteOneChar(0xCC);
- WriteOneChar(0x44);
- Init_DS18B20();
- WriteOneChar(0xCC);
- WriteOneChar(0xBE);
- a=ReadOneChar();
- b=ReadOneChar();
- t=b;
- t<<=8;
- t=t|a;
- tt=t*0.0625;
- t= tt*10+0.5; //放大10倍输出并四舍五入
- return(t);
- }
- u16 check_wendu(void)
- {
- u16 c;
- c=ReadTemperature()-5;
- if(c<1) c=0;
- if(c>=999) c=999;
- return c;
- }
- //按键
- sbit Key1=P1^6;
- sbit Key2=P1^7;
- sbit Key3=P3^2;
- #define KEY_SET 1
- #define KEY_ADD 2
- #define KEY_MINUS 3
- u8 Key_Scan()
- { static u8 key_up=1;
- if(key_up&&(Key1==0||Key2==0||Key3==0))
- {
- delay(10);
- key_up=0;
- if(Key1==0) return 1;
- else if(Key2==0)return 2;
- else if(Key3==0)return 3;
- }
- else if(Key1==1&&Key2==1&&Key3==1)
- key_up=1;
- return 0;
- }
- void main (void)
- {
- u8 key;
- wendu=check_wendu();
- Init1602();
- LCD_Write_String(0,0,"SET T:00 E:000");
- LCD_Write_String(1,0,"NOW T:00.0 E:000");
- delay(1000);
- wendu=check_wendu();
-
- while (1)
- {
- key=Key_Scan();
- yanwu=Adc0832(0);
- wendu=check_wendu();
-
- if(key==KEY_SET)
- {
- Mode++;
- }
-
- switch(Mode)
- {
- case 0:
- {
- Display_1602(shezhiwendu,shezhiyanwu,wendu,yanwu);
- if(yanwu>=shezhiyanwu) //温度大于预设温度
- {
- LedRed=0;
- Buzzer=0; //报警器报警
- }
- else
- {
- LedRed=1; //关掉报警灯
- }
- if(wendu>=(shezhiwendu*10)) //温度大于等于预设温度值时
-
- {
- Buzzer=0;
- LedYellow=0;
- }
- else
- {
- LedYellow=1;
- }
- if((yanwu<shezhiyanwu)&&(wendu<(shezhiwendu*10)))
- {
- Buzzer=1;
- }
- break;
- }
- case 1://预设温度模式
- {
- SelectPosition(0,5) ;
- write_com(0x0d);
- if(key==KEY_ADD)
- {
- shezhiwendu++;
- if(shezhiwendu>=99)
- shezhiwendu=99;
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
烟雾报警器设计全套资料.7z
(1.98 MB, 下载次数: 275)
|