【实验目的】
学习单总线器件的读写方法,数值合成,数字类型变化等。
【实验现象】
用单片机控制开发板上的DS18B20数字温度传感器,读取当前环境温度,精度达0.1度,温度范围0-99度,并用数码管的前三位显示出来。同时开发板上的单片机还能把温度值通过串口发送到计算机,在计算机上安装该目录下的.exe 文件后,打开应用程序可看到温度值。
【实验说明】
DS18B20 数字温度传感器是 DALLAS 公司生产的 1-Wire,即单总线器件,具有线路简单,体积小的特点。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计。
DS18B20 产品的特点
(1)只要求一个 I/O 口即可实现通信。
(2)在 DS18B20 中的每个器件上都有独一无二的序列号。
(3)实际应用中不需要外部任何元器件即可实现测温。
(4)测量温度范围在-55 到+125 摄氏度之间。
(5)数字温度计的分辨率用户可以从 9 位到 12 位选择。
(6)内部有温度上、下限告警设置。 DS18B20 详细引脚功能描述 1、GND 地信号;2、DQ 数据输入出引脚。开漏单总线接口引脚。当被用在寄生电源下,也可以向器件提供电源;3、VDD 可选择的 VDD 引脚。当工作于寄生电源时,此引脚必须接地。DS18B20 的使用方法。由于 DS18B20 采用的是 1-Wire 总线协议方式,即在一根数据线实现数据的双向传输,而对 AT89S52 单片机来说,我们必须采用软件的方法来模拟单总线的协议时序来完成对 DS18B20 芯片的访问。由于 DS18B20 是在一根I/O 线上读写数据,因此,对读写的数据位有着严格的时序要求。DS18B20 有严格的通信协议来保证各位数据传输的正确性和完整性。该协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。
【硬件电路】
【程序代码】
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit DS=P2^2; //定义DS18B20接口
uint temp; // variable of temperature
uchar flag1; // sign of the result positive or negative
sbit dula=P2^6;
sbit wela=P2^7;
unsigned char code table[]=
{
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
}; //不带小数点编码。
unsigned char code table1[]=
{
0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef
}; //带小数点编码。
void delay(uint count) //延时子函数
{
uint i;
while(count)
{
i=200;
while(i>0)
i–;
count–;
}
}
///功能:串口初始化,波特率9600,方式1///
void Init_Com(void)
{
TMOD = 0x20;
PCON = 0x00;
SCON = 0x50;
TH1 = 0xFd;
TL1 = 0xFd;
TR1 = 1;
}
void dsreset(void) //发送初始化及复位信号
{
uint i; //DS18B20初始化
DS=0;
i=103;
while(i>0) i–;
DS=1;
i=4;
while(i>0)i–;
}
bit tmpreadbit(void) //read a bit 读一位
{
uint i;
bit dat;
DS=0;i++; //i++ for delay 小延时一下
DS=1;i++;i++;
dat=DS;
i=8;while(i>0) i–;
return (dat);
}
uchar tmpread(void) //read a byte date 读一个字节
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tmpreadbit();
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好
} //一个字节在DAT里
return(dat); //将一个字节数据返回
}
void tmpwritebyte(uchar dat) //write a byte to ds18b20
{ //写一个字节到DS18B20里
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb) //write 1 写1部分
{
DS=0;
i++;i++;
DS=1;
i=8;while(i>0)i–;
}
else
{
DS=0; //write 0 写0部分
i=8;while(i>0)i–;
DS=1;
i++;i++;
}
}
}
void tmpchange(void) //DS18B20 begin change 发送温度转换命令
{
dsreset(); //初始化DS18B20
delay(1); //延时
tmpwritebyte(0xcc); //跳过序列号命令
tmpwritebyte(0x44); //发送温度转换命令
}
uint tmp() //get the temperature 获得温度
{
float tt;
uchar a,b;
dsreset();
delay(1);
tmpwritebyte(0xcc);
tmpwritebyte(0xbe); //发送读取数据命令
a=tmpread(); //连续读两个字节数据
b=tmpread();
temp=b;
temp<<=8; //two byte compose a int variable
temp=temp|a; //两字节合成一个整型变量。
tt=temp0.0625; //得到真实十进制温度值,因为DS18B20
//可以精确到0.0625度,所以读回数据的最低
//位代表的是0.0625度。
temp=tt10+0.5; //放大十倍,这样做的目的将小数点后第一位
//也转换为可显示数字,同时进行一个四舍五入
//操作。
return temp; //返回温度值
}
void readrom() //read the serial 读取温度传感器的序列号
{ //本程序中没有用到此函数
uchar sn1,sn2;
dsreset();
delay(1);
tmpwritebyte(0x33);
sn1=tmpread();
sn2=tmpread();
}
void delay10ms() //delay
{
uchar a,b;
for(a=10;a>0;a–)
for(b=60;b>0;b–);
}
void display(uint temp) //显示程序
{
uchar A1,A2,A2t,A3,ser;
ser=temp/10; //分离出三位要显示的数字
SBUF=ser;
A1=temp/100;
A2t=temp%100;
A2=A2t/10;
A3=A2t%10;
dula=0;
P0=table[A1]; //显示百位
dula=1;
dula=0;
wela=0;
P0=0x7e;
wela=1;
wela=0;
delay(1);
dula=0;
P0=table1[A2]; //显示十位 带小数点的
dula=1;
dula=0;
wela=0;
P0=0x7d;
wela=1;
wela=0;
delay(1);
P0=table[A3]; //显示个位
dula=1;
dula=0;
P0=0x7b;
wela=1;
wela=0;
delay(1);
}
void main() //主函数
{
uchar a;
Init_Com(); //初始化串口
do
{
tmpchange(); //温度转换
for(a=10;a>0;a–)
{
display(tmp()); //显示十次
}
}
while(1);
}