基于AT89C51的天氣溫度報警系統,采用Protues仿真。
元件:
DS1302時鐘芯片
DS18B20溫度傳感器
LM016L(1602)液晶
AT89C51單片機
LED燈若干
蜂鳴器一只 用于報警 本人不寫這個報警程序了 其實挺簡單的
我只貼出部分主要的代碼
完整源代碼請到: http://blog.sina.com.cn/u/2311964960(內附圖片)
或直接下載: LSD.c (7.4 KB, 下載次數: 72)
/*初始化DS18B20*/
void Init_DS18B20()
{ //初始化DS18B20必須先給DS18B20一個復位脈沖,接收到復位脈沖后DS18B20會返回一個存在脈沖
DQ=1; //DQ先置高電平
_nop_(); //延時
_nop_();
DQ=0; //DQ置低電平(拉低總線),開始初始化
delayus(60); //DQ置低電平后必須延時至少480us,此處延時600us
DQ=1; //然后DQ置高電平(釋放總線)
delayus(3); //釋放總線后要求延時15-60us,此處延時30us
flag=DQ; //讀取DQ并付值flag,如果flag為0,表示返回了一個存在脈沖,初始化完成。相反失敗
delayus(20);
}
/*讀取DS18B20中的scrathpad一個字節*/
uchar read_scratchpad()
{
uchar i=0;
for (i=8;i>0;i--)
{
DQ=1; //DQ位拉高
_nop_(); //延時1us秒
DQ = 0; // DQ置0拉低總線
dat>>=1; //左移一位
delayus(1); //延時1us-15us,此處延時10us
DQ = 1; // DQ置1釋放總線
delayus(1); //延時10us
if(DQ==1){dat|=0x80;} //采樣
else{dat|=0x00;}
delayus(5); //延時50us
}
return dat;
}
/*向DS18B20中寫入一個字節,寫ROM指令用*/
void write_command(uchar com)
{
uchar i=0;
uchar num;
for (i=8; i>0; i--)
{
DQ=1; //先將DQ置1;
_nop_(); //延時
DQ = 0; //DQ置0,拉低總線
num = com&0x01; //讀取指令最低位
if(num==1) //如果為1
{
delayus(1); //要求先延時1-15us,此處延時10us
DQ=1; //然后釋放總線
delayus(4); //延時大概45us,此處延時40us
}else //如果為0
{
delayus(6); //要求延時60-120us,此處延時60us
DQ=1; //然后DQ置1釋放總線
delayus(1); //延時10us
}
com>>=1;
}
delayus(1);
}
/*溫度轉換*/
void Temperature_conversion()
{
Init_DS18B20(); //初始化DS18B20
write_command(0xCC); // 讀取ROM中64-bit code
write_command(0x4E); // 寫暫存器,向暫存器中的TH、TL和configuration Register中寫數據
write_command(0x50);// 向TH Register位寫入數據
write_command(0x00);//向TL Register位寫入數據
write_command(0x7F);//向configuration Register寫入數據
delay(10);
Init_DS18B20();
write_command(0xCC); // 跳過讀序號列號的操作
write_command(0x44); // 啟動溫度轉換
delay(10);
Init_DS18B20();//
write_command(0xCC); //跳過讀序號列號的操作
write_command(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
}
/*向16602寫入指令*/
void write_com_1602(uchar com)
{
lcdrs=0;
lcdrw=0;
P3=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
/*從1602讀取數據*/
void write_data_1602(uchar date)
{
lcdrs=1;
lcdrw=0;
P3=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
/*判斷溫度正負*/
void checkMSB(uchar ta)
{
if(ta==0x07)
{
write_com_1602(0x80+0x48);
write_data_1602(0x20);
TN=MSB*16+LSB/16;
TD=(LSB%16)*10/16;
if(TN>=TH){P1=~P1;} //如果溫度設置的超出上限,LED閃爍
else{P1=0xFF;}
}else{
write_com_1602(0x80+0x48);
display_minus();
LSB=~LSB+1;
MSB=~MSB;
TN=MSB*16+LSB/16;
TD=(LSB%16)*10/16;
P1=~P1; //如果溫度超出設置的下限(小于0),LED閃爍
}
}
/*向DS1302寫數據,分別寫入地址和指令*/
void write_com_1302(uchar add,com)
{
uchar i;
CE=1;
for(i=0;i<8;i++)
{
SCLK=0;
IO=add&0x01;
add>>=1;
SCLK=1;
}
for(i=0;i<8;i++)
{
SCLK=0;
IO=com&0x01;
com>>=1;
SCLK=1;
}
SCLK=0;
CE=0;
}
/*從DS1302中讀數據,但須先寫入地址*/
uchar read_data_1302(uchar add)
{
uchar Data,i;
CE=1;
for(i=0;i<8;i++)
{
SCLK=0;
IO=add&0x01;
add>>=1;
SCLK=1;
}
for(i=0;i<8;i++)
{
SCLK=0;
Data>>=1;
if(IO==1)Data|=0x80;
SCLK=1;
_nop_();
}
SCLK=0;
CE=0;
return Data;
}
/*將從DS1302中讀到的數據換化為10進制*/
uchar changenum(uchar num)
{
uchar TH,TL,new_num;
TH=num&0xF0;
TH>>=4;
TH*=10;
TL=num&0x0F;
new_num=TH+TL;
return new_num;
}
void main()
{
while(1)
{
Temperature_conversion(); //溫度轉換
LSB=read_scratchpad(); //讀取LSB位數據
MSB=read_scratchpad(); //讀取MSB位數據
TH=read_scratchpad(); //讀取TH Register數據
TL=read_scratchpad(); //讀取TL Register數據
CR=read_scratchpad(); //讀取Configuration Register數據
TA=MSB|0x07; //按位與,從MSB位判斷溫度正負
checkMSB(TA); //判斷溫度正負
write_com_1602(0x80+0x49);
display_temp1(TN);
display_dot();
display_temp2(TD);
display_cent();
write_com_1602(0x80);
YY=read_data_1302(0x8D);
YY=changenum(YY);
display_temp3(YY);
display_minus();
MM=read_data_1302(0x89);
MM=changenum(MM);
display_temp3(MM);
display_minus();
DD=read_data_1302(0x87);
DD=changenum(DD);
display_temp3(DD);
write_data_1602(0x20);
write_data_1602(0x20);
write_data_1602(0x20);
HH=read_data_1302(0x85);
HH=changenum(HH);
display_temp3(HH);
display_minus();
MIN=read_data_1302(0x83);
MIN=changenum(MIN);
display_temp3(MIN);
WEEK=read_data_1302(0x8B)-1;
write_com_1602(0x80+0x45);
write_data_1602(digit[WEEK]);
//SEC=read_data_1302(0x81);
//SEC=changenum(SEC);
//display_temp3(SEC);
}
}