7、SCLK:
串行时钟,输入;
6、I/O:
数据输入输出口;
5、CE/RST:
复位脚
23、X1、X2是外接晶振脚(32.768KHZ的晶振)
4、地(GND)
4、实时环境温度检测模块
DS18B20是美国DALLAS公司生产的数字温度传感器,采用单总线的接口方式与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量,使用方便等优点,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。
测量温度范围宽,测量精度高,在使用中不需要任何外围元件,支持多点组网功能多个DS18B20可以并联在惟一的单线上,实现多点测温,供电方式灵活DS18B20可以通过内部寄生电路从数据线上获取电源。
因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
因此非常适合本系统使用。
DS18B20单线数字温度传感器,测量温度范围宽,测量精度高。
其测量范围为-55℃至+125℃;在-10至+85°C范围内,精度为±0.5°C。
DS18B20还具有体积更小、适用电压更宽、更经济、可选更小的封装方式,更宽的电压适用范围,适合于构建自己的经济的测温系统,因此也就被设计者们所青睐。
图5DS18B20管脚介绍
DS18B20的管脚排列
1.GND为电源地;
2.DQ为数字信号输入/输出端;
3.VDD为外接供电电源输入端,在寄生电源接线方式时接地。
5、报警模块
报警模块采用单片机输出一定频率的方波从而使蜂鸣器发出声音,只要编写相应的程序即可实现发出不同频率的声音。
6、设置模块
因设置模块只需编写相应的程序外加相应的按键即可实现。
四、软件设计
软件设计是本设计的关键,软件程序编写的好坏直接影响着系统运行情况的良好。
因本程序涉及的模块较多,所以程序编写也采用模块化设计,C语言具有编写灵活、移植方便、便于模块化设计的特点,所以本系统的软件采用C52编写。
1、程序流程图
图6主程序流程框图
2、主程序
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitRS=P2^0;//数据/命令选择端
sbitRW=P2^1;//读/写选择端
sbitE=P2^2;//1602使能
sbitIO=P1^0;//DS1302数据口
sbitSCLK=P1^1;//DS1302串行时钟
sbitRST=P1^2;//DS1302时钟复位脚
sbitDQ=P1^3;//DS18B20温度
sbitK1=P3^3;//功能
sbitK2=P3^4;//增加
sbitK3=P3^5;//减少
sbitK4=P3^6;//确定
sbitK5=P3^7;//取消
sbitled=P2^4;//温度报警
sbitbuzz=P2^3;//蜂鸣器报警
uchardataLCD_DSY_BUFFER1[]={"20--"};
uchardataLCD_DSY_BUFFER2[]={":
:
"};
uchardataTemp_BUFFER[8];
char*week[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"};
uchardays[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
uchardataDateTime[7];//秒、分、时、日、月、周、年
ucharAdjust_Index=-1;//时钟调节标志
uinttvalue;//温度值
uchartflag;//温度正负标志
//微妙延时程序(约为10us(小于))
voiddelayus(uintus)
{
while(us--);
}//毫秒延时程序
voiddelayms(uintms)
{
uinti,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}//写LCD命令寄存器
voidWrite_LCD_Command(ucharcmd)
{
RS=0;
RW=0;
P0=cmd;
E=1;
delayms(5);
E=0;
}//写LCD数据寄存器
voidWrite_LCD_Data(uchardat)
{
RS=1;
RW=0;
P0=dat;
E=1;
delayms(5);
E=0;
}//显示字符串
voidLCD_ShowString(ucharx,uchary,uchar*str)
{
uchari=0;
if(y==0)
Write_LCD_Command(0x80|x);
elseif(y==1)
Write_LCD_Command(0xc0|x);
for(i=0;i<16&&str[i]!
='\0';i++)
Write_LCD_Data(str[i]);
}//刷新LCD显示缓冲区
voidRefresh_LCD_BUFFER()
{
LCD_DSY_BUFFER1[2]=DateTime[6]/10+0x30;
LCD_DSY_BUFFER1[3]=DateTime[6]%10+0x30;
LCD_DSY_BUFFER1[5]=DateTime[4]/10+0x30;
LCD_DSY_BUFFER1[6]=DateTime[4]%10+0x30;
LCD_DSY_BUFFER1[8]=DateTime[3]/10+0x30;
LCD_DSY_BUFFER1[9]=DateTime[3]%10+0x30;
LCD_DSY_BUFFER2[0]=DateTime[2]/10+0x30;
LCD_DSY_BUFFER2[1]=DateTime[2]%10+0x30;
LCD_DSY_BUFFER2[3]=DateTime[1]/10+0x30;
LCD_DSY_BUFFER2[4]=DateTime[1]%10+0x30;
LCD_DSY_BUFFER2[6]=DateTime[0]/10+0x30;
LCD_DSY_BUFFER2[7]=DateTime[0]%10+0x30;
}//LCD初始化
voidInitialize_LCD()
{
E=0;
Write_LCD_Command(0x38);
Write_LCD_Command(0x0c);
Write_LCD_Command(0x06);
Write_LCD_Command(0x01);
}//向DS1302中写入一字节(上升沿写入)
voidWrite_Byte_TO_DS1302(ucharx)
{
uchari;
for(i=0;i<8;i++)//循环8次写入数据
{
IO=x&0x01;//每次传输低字节
SCLK=0;
delayus
(2);
SCLK=1;
x>>=1;//右移一位
}}
//从DS1302中读取一字节(下降沿读取)
ucharGet_Byte_FROM_DS1302()
{
uchari,dat=0x00;
for(i=0;i<8;i++)
{
if(IO)
dat|=0x80;
SCLK=1;
delayus
(2);
SCLK=0;
dat>>=1;
}
returndat/16*10+dat%16;//将读出的BCD码值转化为十进制
}//从DS1302的指定地址读取一字节数据
ucharRead_Data(ucharaddr)
{
uchardat;
RST=0;
SCLK=0;
RST=1;
Write_Byte_TO_DS1302(addr);//先写地址在读取
dat=Get_Byte_FROM_DS1302();
RST=0;
SCLK=1;
returndat;
}//向指定的地址写入一字节数据
voidWrite_DS1302(ucharadd,ucharnum)
{
RST=0;
SCLK=0;
RST=1;
Write_Byte_TO_DS1302(add);//先写地址再写数据
Write_Byte_TO_DS1302(num);
RST=0;
SCLK=1;
}//读取当前日期时间
voidGetDateTime()
{
uchari,addr=0x81;//读取秒地址开始(地址最高位10表示要读/写clock数据,
//最低位表示是读
(1)还是写(0)
for(i=0;i<7;i++)
{
DateTime[i]=Read_Data(addr);
addr+=2;
}}//禁止涓流充电
voiddenot()
{
Write_DS1302(0x8e,0x00);//写控制字节,取消写保护
Write_DS1302(0x90,0x8b);//禁止涓流充电
Write_DS1302(0x8e,0x80);//加保护
}//写改动后的数据到DS1302中
voidSetDateTime()
{
uchari;
Write_DS1302(0x8e,0x00);//写控制字节,取消写保护
for(i=0;i<7;i++)
{
Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));
}
Write_DS1302(0x8e,0x80);//加保护
}//判断是否为闰年
ucharIsLeapYear(uinty)
{
if((y%4==0&&y%100!
=0)||(y%400==0))return1;
elsereturn0;
}//根据设定的日期自动刷新星期
voidRefreshWeekday()
{
uinti,d,w=5;//已知1999.12.31是周五
for(i=2000;i<2000+DateTime[6];i++)
{
d=IsLeapYear(i)?
366:
365;
w=(w+d)%7;}
for(d=0,i=1;id+=days[i];
d+=DateTime[3];
DateTime[5]=(w+d)%7+1;
}//根据按键情况调整时间
voidDateTime_Adjust(charx)
{
switch(Adjust_Index)
{
case6:
//年00--99
if(x==1)
{
DateTime[6]++;
if(DateTime[6]==100)
DateTime[6]=0;
}
else
{
DateTime[6]--;
if(DateTime[6]==0xff)
DateTime[6]=99;
}
days[2]=IsLeapYear(2000+DateTime[6])?
29:
28;
if(DateTime[3]>days[DateTime[4]])
DateTime[3]=days[DateTime[4]];
RefreshWeekday();
break;
case4:
//月01--12
if(x==1)
{
DateTime[4]++;
if(DateTime[4]==13)
DateTime[4]=1;
}
else
{
DateTime[4]--;
if(DateTime[4]==0)
DateTime[4]=12;
}
days[2]=IsLeapYear(2000+DateTime[6])?
29:
28;
if(DateTime[3]>days[DateTime[4]])
DateTime[3]=days[DateTime[4]];
RefreshWeekday();
break;
case3:
//日
days[2]=IsLeapYear(2000+DateTime[6])?
29:
28;
if(x==1)
{
DateTime[3]++;
if(DateTime[3]>days[DateTime[4]])
DateTime[3]=1;
}
else
{
DateTime[3]--;
if(DateTime[3]==0)
DateTime[3]=days[DateTime[4]];
}
if(DateTime[3]>days[DateTime[4]])
DateTime[3]=days[DateTime[4]];
RefreshWeekday();
break;
case2:
//时
if(x==1)
{
DateTime[2]++;
if(DateTime[2]==24)
DateTime[2]=0;
}
else
{
DateTime[2]--;
if(DateTime[2]==0xff)
DateTime[2]=23;
}
break;
case1:
//分
if(x==1)
{
DateTime[1]++;
if(DateTime[1]==60)
DateTime[1]=0;
}
else
{
DateTime[1]--;
if(DateTime[1]==0xff)
DateTime[1]=59;
}
break;
case0:
//秒
if(x==1)
{
DateTime[0]++;
if(DateTime[0]==60)
DateTime[0]=0;
}
else
{
DateTime[0]--;
if(DateTime[0]==0xff)
DateTime[0]=59;
}
break;
}}//复位,初始化DS18B20
voiddsreset()
{
do{
DQ=1;//DQ复位
delayus(4);//延时
DQ=0;//DQ拉低
delayus(75);//精确延时480us~~960us
DQ=1;//拉高
delayus(5);
}
while(DQ==1);
delayus(50);//最少480us
}//读一个字节函数
uchartmpread(void)
{
uchari=0;
uchardat=0;
for(i=8;i>0;i--)
{DQ=0;//给脉冲信号
dat>>=1;
DQ=1;//给脉冲信号
if(DQ)
dat|=0x80;
delayus(4);//延时>30us
}
return(dat);
}//写一个字节函数
voidtmpwritebyte(uchardat)
{
uinti;
ucharj;
bittestb;
for(j