仿真原理圖如下(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是正常監(jiān)控模式 //管腳聲明 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行第一個字節(jié)位置顯示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 數據輸出 /*為節(jié)省單片機引腳,簡化電路所以輸入輸出連接在同一個引腳上
//======================================================================== // 函數: 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;//拉高數據端,回到初始狀態(tài) 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); } /*****讀一個字節(jié)*****/ 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); } /*****寫一個字節(jié)*****/ 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) //主循環(huán) { key=Key_Scan(); //按鍵掃描 yanwu=Adc0832(0); //讀取煙霧值 wendu=check_wendu(); //讀取溫度值
if(key==KEY_SET) { Mode++; }
switch(Mode) //判斷模式的值 { case 0: //監(jiān)控模式 { 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; //執(zhí)行后跳出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)
2020-6-22 11:39 上傳
點擊文件名下載附件
火災報警器.doc
(178.04 KB, 下載次數: 75)
2020-6-22 11:39 上傳
點擊文件名下載附件
|