本帖最后由 gzh_soul 于 2012-2-1 19:34 编辑
基于AT89C51的天气温度报警系统,采用Protues仿真。 元件: DS1302时钟芯片 DS18B20温度传感器 LM016L(1602)液晶 AT89C51单片机 LED灯若干 蜂鸣器一只 用于报警 本人不写这个报警程序了 其实挺简单的 我只贴出部分主要的代码 完整源代码请到: http://blog.sina.com.cn/u/2311964960(内附图片) 或直接下载:
LSD.c
(7.4 KB, 下载次数: 95
)
/*初始化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);
}
}
最后是程序运行:
其实也几乎将整个源代码贴出来,写了几天很辛苦呢,分享出来,帮助像我一样的菜鸟,希望有所帮助
|