在辉光管时钟里,我们还加入了温度显示功能。这里,我们采用简单易用的温度芯片DS18B20来测量环境温度。DS18B20是常用的数字温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。
本文主要是通过STC89C52单片机与温度芯片DS18B20通信,让LCD1602来显示温度,其电路原理图如下:
注意:DS18B20有字一面朝我们,管脚朝下,依次接入地、单片机管脚、以及5V,其中还需要接一个上拉电阻如图中的10k电阻。在图1中,关于单片机和1602液晶部分我们已经在前面文章《辉光管时钟系列<二>LCD液晶显示》中介绍过了。下面首先给出了温度芯片DS18B20的实物图,如图2所示:
下面给出简单的测试程序:
/********************************************
读取DS18B20温度,通过LCD1602显示出来
第一行: 实时温度值
第二行: 最大值和最小值
********************************************/
/*头文件*/
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define _Nop() _nop_()
sbit DQ =P2^3; //定义DS18B20通信端口
#define uchar unsigned char
#define uint unsigned int
sbit lcden=P2^7;
sbit lcdrs=P2^5;
/*定义数字ascii编码*/
unsigned char mun_char_table[]={"0123456789abcdef"};
unsigned char temp_table[] ={" Temp: . 'C"};
unsigned char temp_high_low[]={"H: . L: . "};
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
//
//以下是LCD1602驱动程序
void write_com(uchar com)
{
lcdrs=0;
P0=com;
delay(15);
lcden=1;
delay(15);
lcden=0;
}
void write_date(uchar dat)
{
lcdrs=1;
P0=dat;
delay(15);
lcden=1;
delay(15);
lcden=0;
}
void init()
{
uchar num;
lcden=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
for(num=0;num<14;num++)
{
write_date(temp_table[num]);
delay(5);
}
write_com(0x80+0x40);
for(num=0;num<16;num++)
{
write_date(temp_high_low[num]);
delay(5);
}
}
//以上是LCD1602驱动程序
//以下是DS18B20驱动程序
//延时函数
void delay_ds(unsigned int i)
{
while(i--);
}
//初始化函数
Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1; //DQ复位
delay_ds(8); //稍做延时
DQ = 0; //单片机将DQ拉低
delay_ds(80); //精确延时 大于 480us
DQ = 1; //拉高总线
delay_ds(14);
x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay_ds(20);
}
//读一个字节
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_ds(4);
}
return(dat);
}
//写一个字节
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--){
DQ = 0;
DQ = dat&0x01;
delay_ds(5);
DQ = 1;
dat>>=1;
}
}
//读取温度
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); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar();
b=ReadOneChar();
t=b;
t<<=8;
t=t|a;
tt=t*0.0625; //将温度的高位与低位合并
t= tt*10+0.5; //对结果进行4舍5入
return(t);
}
//以上是DS18B20驱动程序
/*1MS为单位的延时程序*/
void delay_1ms(uchar x)
{
uchar j;
while(x--){
for(j=0;j<125;j++)
{;}
}
}
void main()
{
unsigned int i=0;
unsigned int temp_high;
unsigned int temp_low;
int num;
ReadTemperature(); //读取当前温度,会读取初始数据85,舍去?
init();
i=ReadTemperature(); /*读取当前温度*/
temp_high = i;
temp_low = i;
while(1){
i=ReadTemperature(); //读取当前温度
if(temp_high<i) temp_high=i;
if(temp_low>i) temp_low=i;
write_com(0x88);
write_date(mun_char_table[i/100]); /*把温度显示出来*/
delay(5);
write_date(mun_char_table[i%100/10]);
delay(5);
write_com(0x80+11);
write_date(mun_char_table[i%10]);
delay_1ms(10);
write_com(0x80+0x40+2);
write_date(mun_char_table[temp_high/100]);
delay(5);
write_date(mun_char_table[temp_high%100/10]);
delay(5);
write_com(0x80+0x40+5);
write_date(mun_char_table[temp_high%10]);
delay(5);
write_com(0x80+0x40+12);
write_date(mun_char_table[temp_low/100]);
delay(5);
write_date(mun_char_table[temp_low%100/10]);
delay(5);
write_com(0x80+0x40+15);
write_date(mun_char_table[temp_low%10]);
delay(5);
}
}
最后,给出测试结果图: