仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
#include <reg52.h> #include "intrins.h"
#define u8 unsigned char #define u16 unsigned int #define uchar unsigned char #define uint unsigned int
uchar yushe_wendu=50; //温度预设值 uchar yushe_yanwu=100; //烟雾预设值 uint wendu; //温度值全局变量 uchar yanwu; //用于读取ADC数据
//运行模式 uchar Mode=0; //=1是设置温度阀值 =2是设置烟雾阀值 =0是正常监控模式 //管脚声明 sbit Led_Reg =P2^2; //红灯 sbit Led_Yellow =P2^4; //黄灯 sbit Buzzer =P2^0; //蜂鸣器 sbit Fan =P3^3; //
/******************************************************************** * 名称 : delay_1ms() * 功能 : 延时1ms函数 * 输入 : q * 输出 : 无 ***********************************************************************/ void delay_ms(uint q) { uint i,j; for(i=0;i<q;i++) for(j=0;j<110;j++); } /*********************************************************************************************************** LCD1602相关函数 ***********************************************************************************************************/
//LCD管脚声明 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;
//LCD延时 void LCDdelay(uint z) //该延时大约100us { 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); // DAT=com; LCDdelay(5); LCDEN=1; LCDdelay(5); LCDEN=0; } //数据 void write_data(uchar date) { LCDRS=1; LCD_WriteData(date); // DAT=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) // 应用: LCD_Write_Char(0,1,366,4) ; // 描述: 在第0行第一个字节位置显示366的后4位,显示结果为 0366 // 参数: x:行,y:列,s:要显示的字,l:显示的位数 // 返回: none. // 版本: VER1.0 // 日期: 2013-4-1 // 备注: 最大显示65535 //======================================================================== 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); //个位
} /*1602指令简介 write_com(0x38);//屏幕初始化 write_com(0x0c);//打开显示 无光标 无光标闪烁 write_com(0x0d);//打开显示 阴影闪烁 write_com(0x0d);//打开显示 阴影闪烁 */ //1602初始化 void Init1602() { uchar i=0; write_com(0x38);//屏幕初始化 write_com(0x0c);//打开显示 无光标 无光标闪烁 write_com(0x06);//当读或写一个字符是指针后一一位 write_com(0x01);//清屏
}
void Display_1602(yushe_wendu,yushe_yanwu,c,temp) { //显示预设温度 LCD_Write_Char(0,6,yushe_wendu,2) ;
//显示预设烟雾 LCD_Write_Char(0,13,yushe_yanwu,3) ;
//时时温度 LCD_Write_Char(1,6,c/10,2) ; write_data('.'); LCD_Write_Char(1,9,c%10,1) ;
//时时烟雾 LCD_Write_Char(1,13,temp,3) ; }
/*********************************************************************************************************** ADC0832相关函数 ***********************************************************************************************************/ sbit ADCS =P1^5; //ADC0832 片选 sbit ADCLK =P1^2; //ADC0832 时钟 sbit ADDI =P1^3; //ADC0832 数据输入 /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行, sbit ADDO =P1^3; //ADC0832 数据输出 /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上
//======================================================================== // 函数: unsigned int Adc0832(unsigned char channel) // 应用: temp=Adc0832(0); // 描述: 读取0通道的AD值 // 参数: channel:通道0和通道1选择 // 返回: 选取通道的AD值 // 版本: VER1.0 // 日期: 2015-05-29 // 备注: //======================================================================== 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 }
/*********************************************************************************************************** DS18B20相关函数 ***********************************************************************************************************/
sbit DQ = P1^0; //ds18b20的数据引脚
/*****延时子程序:该延时主要用于ds18b20延时*****/ void Delay_DS18B20(int num) { while(num--) ; } /*****初始化DS18B20*****/ void Init_DS18B20(void) { unsigned char x=0; DQ = 1; //DQ复位 Delay_DS18B20(8); //稍做延时 DQ = 0; //单片机将DQ拉低 Delay_DS18B20(80); //精确延时,大于480us DQ = 1; //拉高总线 Delay_DS18B20(14); x = DQ; //稍做延时后,如果x=0则初始化成功,x=1则初始化失败 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(); //读低8位 b=ReadOneChar(); //读高8位 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; //获取温度值并减去DS18B20的温漂误差 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() // 应用: temp=u8 Key_Scan(); // 描述: 按键扫描并返回按下的键值 // 参数: NONE // 返回: 按下的键值 // 版本: VER1.0 // 日期: 2015-05-29 // 备注: 该函数带松手检测,按下键返回一次键值后返回0,直至第二次按键按下 //======================================================================== u8 Key_Scan() { static u8 key_up=1;//按键按松开标志 if(key_up&&(Key1==0||Key2==0||Key3==0)) { delay_ms(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(); //初始化时调用温度读取函数 防止开机85°C Init1602(); //调用初始化显示函数 LCD_Write_String(0,0,"SET T:00 E:000"); //开机界面 LCD_Write_String(1,0,"NOW T:00.0 E:000"); delay_ms(1000); wendu=check_wendu(); //初始化时调用温度读取函数 防止开机85°C while (1) //主循环 { key=Key_Scan(); //按键扫描 yanwu=Adc0832(0); //读取烟雾值 wendu=check_wendu(); //读取温度值
if(key==KEY_SET) { Mode++; }
switch(Mode) //判断模式的值 { case 0: //监控模式 { Display_1602(yushe_wendu,yushe_yanwu,wendu,yanwu); //显示预设温度,预设烟雾,温度值,烟雾值 if(yanwu>=yushe_yanwu) //烟雾值大于等于预设值时 { Led_Reg=0; //烟雾指示灯亮 Fan=0; Buzzer=0; //蜂鸣器报警 } else //烟雾值小于预设值时 { Led_Reg=1; //关掉报警灯 Fan=1; } if(wendu>=(yushe_wendu*10)) //温度大于等于预设温度值时(为什么是大于预设值*10:因为我们要显示的温度是有小数点后一位,是一个3位数,25.9°C时实际读的数是259,所以判断预设值时将预设值*10) { Buzzer=0; //打开蜂鸣器报警 Led_Yellow=0; //打开温度报警灯 } else //温度值小于预设值时 { Led_Yellow=1; //关闭报警灯 } if((yanwu<yushe_yanwu)&&(wendu<(yushe_wendu*10))) //当烟雾小于预设值并且温度也小于预设值时 (&&:逻辑与,左右两边的表达式都成立(都为真,也就是1)时,该if语句才成立) { Buzzer=1; //停止报警 } break; } case 1://预设温度模式 { SelectPosition(0,5) ; //指定位置 write_com(0x0d); //阴影闪烁 if(key==KEY_ADD) //加键按下 { yushe_wendu++; //预设温度值(阀值)加1 if(yushe_wendu>=99) //当阀值加到大于等于99时 yushe_wendu=99; //阀值固定为99 LCD_Write_Char(0,6,yushe_wendu,2) ;//显示预设温度 } if(key==KEY_MINUS) //减键按下 { if(yushe_wendu<=1) //当温度上限值减小到1时 yushe_wendu=1; //固定为1 yushe_wendu--; //预设温度值减一,最小为0 LCD_Write_Char(0,6,yushe_wendu,2) ;//显示预设温度 } break; //执行后跳出switch } case 2: //预设烟雾模式 { SelectPosition(0,12) ; //指定位置 write_com(0x0d); //打开显示 无光标 光标闪烁 if(key==KEY_ADD) //加键按下 { if(yushe_yanwu>=255) //当阀值加到大于等于255时 yushe_yanwu=254; //阀值固定为254 yushe_yanwu++; //预设烟雾值(阀值)加1,最大为255 LCD_Write_Char(0,13,yushe_yanwu,3) ;//显示预设烟雾 } if(key==KEY_MINUS) //减键按下 { if(yushe_yanwu<=1) //当烟雾上限值减小到1时 yushe_yanwu=1; //固定为1 yushe_yanwu--; //预设温度值减一,最小为0 LCD_Write_Char(0,13,yushe_yanwu,3) ;//显示预设烟雾 } break; } default : { write_com(0x38);//屏幕初始化 write_com(0x0c);//打开显示 无光标 无光标闪烁 Mode=0; //恢复正常模式 break; } }
}
}
全部资料51hei下载地址:
仿真工程:
新建压缩文件.zip
(31.46 KB, 下载次数: 156)
火灾报警器.doc
(178.04 KB, 下载次数: 75)
|