项目名称:测温过温报警系统及时钟系统
此系统主要由AT89C51、DS18B20温度模块、LCD1602、喇叭组成。大致的原理是DS18B20温度采集到的数据传送给AT89C51的P3.4,最后通过LCD1602显示当前的实时温度,根据中断按键判断显示时间还是温度。
复习使用
(1) DS18B20简介
1.传感器参数:
(1)测温范围为-55℃到+125℃,在-10℃到+85℃范围内误差为±0.4°。
(2)返回16位二进制温度数值。
(3)主机和从机通信使用单总线,即使用单线进行数据的发送和接收。
(4)在使用中不需要任何外围元件,独立芯片即可完成工作。
(5)掉电保护功能 DS18B20 内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。
(6)每个DS18B20都有独立唯一的64位-ID,此特性决定了它可以将任意多的DS18b20挂载到一根总线上,通过ROM搜索读取相应DS18B20的温度值。
(7)宽电压供电,电压2.5V~5.5V
2.DS18B20内部结构:
主要由4部分组成:64 位ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同。64位ROM的排的循环冗余校验码(CRC=X^8+X^5+X^4+1)。 ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。
3.DS18B20内部构成:
高速暂存存储器由9个字节组成,当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。单片机可通过单线接口读到该数据,读取时低位在前,高位在后,对应的温度计算:当符号位S=0时,直接将二进制位转换为十进制;当S=1时,先将补码变为原码,再计算十进制值。
4.DS18B20 单线通信:
DS18B20 单线通信功能是分时完成的,他有严格的时隙概念,如果出现序列混乱, 1-WIRE 器件将不响应主机,因此读写时序很重要。系统对 DS18B20 的各种操作必须按协议进行。
1.引脚功能:
·引脚1:VSS为地电源。
·引脚2:VDD接5V正电源。
·引脚3:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”现象,使用时可以通过一个10kQ的电位器调整其对比度。
·引脚4:RS为寄存器选择脚,高电平时选择数据寄存器、低电平时选择指令寄存器。
·引脚5:R/W为读/写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或显示地址;当RS为低电平,R/W为高电平时,可以读忙信号;当RS为高电平,R/W为低电平时,可以写入数据。
·引脚6:E端为使能端,当E端由高电平跳变为低电平时,液晶模块执行命令。
·引脚7~14:D0~D7为8位双向数据线。
·引脚15:背光源正极。
·引脚16:背光源负极。
2.LCD1602的基本操作
①读状态:RS=0,RW=1,E=高脉冲。输出:D0~D7为状态字。
②读数据:RS=1,RW=1,E=高脉冲。输出:D0~D7为数据。
③写指令:RS=0,RW=0,E=高脉冲。输出:无
④写数据:RS=1,RW=0,E=高脉冲。输出:无。
显示模式设置
显示开/关光标设置
此次实践中主要查询的是这两个元件,通过了解其原理与工作方式,实现所需功能。其次是查询中断及定时器使用,不在赘述。
本系统基本功能为测温过温警报及时间显示,按键P1.0、P1.1控制设定温度的加减,P1.2控制是否报警。按键P3.3按下为进入中断,此时系统切换显示此刻时间,时间初始值需人为设定。
3、调试过程中遇到的问题
(1)初次使用LCD1602时,编写程序发现液晶屏上显示不了
解决方案:LCD1602显示字符,需将显示数字改为字符串形式。
(2)DS18B20初始化一直失败
解决方案:DS18B20时序性非常严格,需准确定时,故单独为此元件设定了延时函数。
解决方案:每次调用时间或温度显示时先清屏,但只能调用一次,一直调用会出现闪烁重影现象,故需加上标志位,每次调用函数时标志位为1,执行一次后标志位置0,标志位为1时执行清屏动作,并且将另一个显示函数的标志位置1,如此便可使每次调用函数时都能使清屏动作执行一次。
protues仿真图:
温度显示:
时间显示:
附上代码:
#include
#define uint unsigned int
#define uchar unsigned char
#define LCD P2
sbit E=P3^0; //LCD使能端口定义
sbit RW=P3^1; //LCD读写使能端口定义
sbit RS=P3^2; //LCD数据/命令选择方式端口定义
sbit bflag=P2^7; //LCD忙指示端口,高电平为忙
sbit DQ = P3^4; //DS18B20引脚
sbit P10=P1^0; //温度加一
sbit P11=P1^1; //温度减一
sbit P12=P1^2; //报警
sbit P13=P1^3; //喇叭
sbit TW=P3^3; //显示时间还是温度
uint readtemp=0; //读取温度
uint settemp=25; //设定温度
uchar i=0;
uchar miao=50; //时间显示
uchar fen=59;
uchar shi=23;
uchar str[]={"0123456789"}; //驱动数组
uchar str1[]={"Temp:"}; //读取温度
uchar str3[]={"Set:"}; //设定温度
uchar str4[]={"Time:"}; //时间
uint xtemp; //装载小数
int flag=1; //温度清屏标志
int balg=1; //时间清屏标志位
void delay_18b20(uint i) //DS18B20专用延时
{
for(;i>0;i--);
}
void delay(uint x)
{
uint i,j;
for(i=0;i>1; //右移一位
DQ = 1; //释放总线
if(DQ)
dat = dat|0x80;
delay_18b20(4);
}
return dat;
}
void WriteOneChar(unsigned char dat) //写字节
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ= 0; //拉低电平
DQ = dat&0x01;
if(DQ)
{
delay_18b20(1);DQ=1;}
else { delay_18b20(5);DQ=1;}
dat = dat>>1;
}
}
uchar ReadTemperature(void)
{
unsigned char a=0,b=0;
uchar temp=0;
InitDs18b20(); //初始化DS18B20
WriteOneChar(0xcc); //跳过ROM
WriteOneChar(0x44); //启动温度转换指令
delay_18b20(100);
InitDs18b20(); //每一次写命令都需要初始化
WriteOneChar(0xcc); //跳过ROM
WriteOneChar(0xbe); //读暂存器内容
a=ReadOneChar(); //获取温度的第一个字节 a存低字节
b=ReadOneChar(); //获取温度的第二个字节 b存高字节 00000 111 1111 0000
temp=b<<4|a>>4; // 获取温度整数值
xtemp=a&0x0f; //获取小数
return (temp);
}
void display() //正温度显示
{
uint temp0=0,temp1=0,temp2=0,temp3=0,i=0;
temp0=readtemp/100;
temp1=(readtemp%100)/10;
temp2=readtemp%10;
temp3=xtemp*625/1000;
writecom(0x80);
delay(5);
while(str1[i]!='\0')
{
writedat(str1[i]);
i++;
}
writecom(0x80+7); //定义地址
delay(1);
writedat(str[temp0]); //百位
delay(1);
writedat(str[temp1]); //十位
delay(1);
writedat(str[temp2]); //个位
delay(1);
writedat('.');
delay(1);
writedat(str[temp3]); //小数
delay(1);
writedat(0xdf);
delay(1);
writedat('c');
delay(1);
}
void displayfu() //负温度显示
{
uint temp0=0,temp1=0,temp2=0,temp3=0,i=0;
temp0=readtemp/100;
temp1=(readtemp/10)%10;
temp2=readtemp%10;
/* xtemp=~xtemp;
xtemp=xtemp&0x0f;
xtemp=xtemp+1;
temp3=xtemp*625/1000;
*/
writecom(0x80);
delay(1);
while(str1[i]!='\0')
{
writedat(str1[i]);
i++;
}
writecom(0x80+7);
delay(1);
writedat('-');
writecom(0x80+8);
delay(1);
writedat(str[temp0]);
delay(1);
writedat(str[temp1]);
delay(1);
writedat(str[temp2]);
delay(1);
writedat('.');
delay(1);
writedat(str[temp3]);
delay(1);
writedat(0xdf);
delay(1);
writedat('c');
delay(1);
}
void display0() //0 时
{
uint temp0=0,temp1=0,temp2=0,temp3=0,i=0;
temp0=readtemp/100;
temp1=(readtemp%100)/10;
temp2=readtemp%10;
temp3=xtemp*625/1000;
writecom(0x80);
delay(1);
while(str1[i]!='\0')
{
writedat(str1[i]);
i++;
}
writecom(0x80+7);
delay(1);
writedat(str[temp0]);
delay(1);
writedat(str[temp1]);
delay(1);
writedat(str[temp2]);
delay(1);
writedat('.');
delay(1);
writedat(str[temp3]);
delay(1);
writedat(0xdf);
delay(1);
writedat('c');
delay(1);
}
void wenkong()
{
if(P10==0) //温控加一
{
settemp=settemp+1;
while(P10==0); //检测按键是否弹起
}
if(P11==0) //温控减一
{
settemp=settemp-1;
while(P11==0); //检测按键是否弹起
}
}
void displayset() //显示设定的温度
{
uint temp0=0,temp1=0,temp2=0,i=0;
temp0=settemp/100;
temp1=(settemp%100)/10;
temp2=settemp%10;
writecom(0x80+0x40);
while(str1[i]!='\0')
{
writedat(str3[i]);
i++;
}
writecom(0x80+0x40+7);
delay(1);
writedat(str[temp0]);
delay(1);
writedat(str[temp1]);
delay(1);
writedat(str[temp2]);
delay(1);
writedat('.');
delay(1);
writedat('0');
delay(1);
writedat(0xdf);
delay(1);
writedat('c');
delay(1);
}
void delay500()
{
unsigned char i;
for(i=250;i>0;i--);
}
void displaymusic() //报警程序
{
uchar readtemp1;
uchar count;
if(P12==0)
{
readtemp1=readtemp;
if(readtemp>settemp)
{
for(count=200;count>0;count--)
{
P13=~P13;
delay500();
}
for(count =200;count>0;count--)
{
P13=~P13;
delay500();
delay500();
}
}
}
}
void findisplay() //温度显示整合
{
displayset();
wenkong();
displaymusic();
if(ReadTemperature()==0)
{
writecom(0x01);
readtemp=0;
display0();
}
if(ReadTemperature()<128)
{
readtemp=ReadTemperature();
display();
}
else
{
char a=0;
a=ReadTemperature();
readtemp=~a+1;
displayfu();
}
}
void timedisplay()
{ uint i=0;
writecom(0x80); //第一行显示time:
while(str4[i]!='\0')
{
writedat(str4[i]);
i++;
}
writecom(0x80+0x40+4); //第二行显示 时间 00:00:00
writedat(str[shi/10]); //小时数
writedat(str[shi%10]);
writedat(':');
writedat(str[fen/10]); //分钟数
writedat(str[fen%10]);
writedat(':');
writedat(str[miao/10]); //秒数
writedat(str[miao%10]);
}
void timer0() interrupt 1 //定时50ms 0.05s
{
char i;
i++;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
if(i==20)
{
i=0;
miao++;
}
if(miao==60)
{
miao=0;
fen++;
}
if(fen==60)
{
fen=0;
shi++;
}
if(shi==24)
{
shi=0;
}
}
void int1() interrupt 2
{
if(balg==1) //清屏标志
{
writecom(0x01);
balg=0;
}
timedisplay();
flag=1; //方便下次温度显示清屏
}
void main()
{
TMOD=0x01;
TL0=(65536-50000)%256 ; //定义50ms
TH0=(65536-50000)/256 ;
IE=0X86; //启用 TF0 INT1
TR0=1;
initlcd();
while(1)
{
balg=1; //中断清屏准备
if(flag==1)
{
writecom(0x01);
flag=0;
}
findisplay();
}
}