DS18B20数字温度传感器.docx
《DS18B20数字温度传感器.docx》由会员分享,可在线阅读,更多相关《DS18B20数字温度传感器.docx(28页珍藏版)》请在冰点文库上搜索。
![DS18B20数字温度传感器.docx](https://file1.bingdoc.com/fileroot1/2023-8/4/67bc0d9e-768f-4b50-b0f6-764651b4b8c1/67bc0d9e-768f-4b50-b0f6-764651b4b8c11.gif)
DS18B20数字温度传感器
DS18B20单线数字温度传感器
DALLAS半导体公司的数字化温度传感器DS1820是世界上第一片支持“一线总线”接口的温度传感器,体积更小、适用电压更宽、更经济。
一线总线独特而且经济的特点,使用户可轻松地组建温度传感器网络,为测量系统的构建引入全新概念。
DS18B20、DS1822“一线总线”数字化温度传感器同DS1820一样,支持“一线总线”接口,测量温度范围为-55°C~+125°C,在-10~+85°C范围内,精度为±0.5°C,而DS1822的精度较差为±2°C。
现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性,适合于恶劣环境的现场温度测量,如:
环境控制、设备或过程控制、测温类消费电子产品等。
DS18B20可以程序设定9~12位的分辨率,精度为±0.5°C,分辨率设定,以及用户设定的报警温度存储在EEPROM中,掉电后依然保存。
DS1822与DS18B20软件兼容,是DS18B20的简化版本。
省略了存储用户定义报警温度、分辨率参数的EEPROM,精度降低为±2°C,适用于对性能要求不高,成本控制严格的应用,是经济型产品。
继“一线总线”的早期产品后,DS1820开辟了温度传感器技术的新概念。
DS18B20和DS1822使电压、特性及封装有更多的选择,让我们可以构建适合自己的经济的测温系统。
1、 DS18B20性能特点
DS18B20的性能特点:
①采用单总线专用技术,既可通过串行口线,也可通过其它I/O口线与微机接口,无须经过其它变换电路,直接输出被测温度值(9位二进制数,含符号位),②测温范围为-55℃-+125℃,测量分辨率为0.0625℃,③内含64位经过激光修正的只读存储器ROM,④适配各种单片机或系统机,⑤用户可分别设定各路温度的上、下限,⑥内含寄生电源。
2、 DS18B20内部结构
DS18B20内部结构主要由四部分组成:
64位光刻ROM,温度传感器,非挥发的温度报警触发器TH和TL,高速暂存器。
DS18B20的管脚排列如图1所示。
64位光刻ROM是出厂前被光刻好的,它可以看作是该DS18B20的地址序列号,不同的器件地址序列号不同。
8位产品系列号
48位产品序号
8位CRC编码
DS18B20高速暂存器共9个存储单元,如表所示:
序号
寄存器名称
作 用
序号
寄存器名称
作 用
0
温度低字节
以16位补码形式存放
4、5
保留字节1、2
1
温度高字节
6
计数器余值
2
TH/用户字节1
存放温度上限
7
计数器/℃
3
HL/用户字节2
存放温度下限
8
CRC
CRC校验
以12位转化为例说明温度高低字节存放形式及计算:
12位转化后得到的12位数据,存储在18B20的两个高低两个8位的RAM中,二进制中的前面5位是符号位。
如果测得的温度大于0,这5位为0,只要将测到的数值乘于0.0625即可得到实际温度(等价说明:
高8位字节的低3位和低8位字节的高4位组成温度整数值的二进制数;或者说:
12位测量时,所测数值乘以0.0625(=1/16),即右移4位后去掉了二进制数的小数部分);如果温度小于0,这5位为1,测到的数值需要取反加1再乘于0.0625才能得到实际温度(等价说明:
当温度小于0时,整数部分就是各位取反,小数部分则是各位取反后加1)。
高8位
S
S
S
S
S
26
25
24
低8位
23
22
21
20
2-1
2-2
2-3
2-4
说明:
温度测量分辨率有四种,即
9位测量分辨率0.5℃;
10位测量分辨率0.25℃;
11位测量分辨率0.125℃;
12位测量分辨率0.0625℃;
9~12位的测量,无论采用哪种分辨率,温度整数的有效位均是表中26~20;
以12位为例:
温度值
二进制数
十六进制数
+125℃
0000011111010000
07D0H
+25.0625℃
0000000110010001
0191H
+10.125℃
0000000010100010
00A2H
+0.5℃
0000000000001000
0008H
0℃
0000000000000000
0000H
-0.5℃
1111111111111000
FFF8H
-10.125℃
1111111101011110
FF5EH
-25.0625℃
1111111001101111
FF6FH
-125℃
1111110010010000
FC90H
1、DS18B20控制方法
在硬件上,DS18B20与单片机的连接有两种方法,一种是Vcc接外部电源,GND接地,I/O与单片机的I/O线相连;另一种是用寄生电源供电,此时UDD、GND接地,I/O接单片机I/O。
无论是内部寄生电源还是外部供电,I/O口线要接5kΩ左右的上拉电阻。
DS18B20有六条控制命令,如下表所示:
指 令
约定代码
操 作 说 明
温度转换
44H
启动DS18B20进行温度转换
读暂存器
BEH
读暂存器9个字节内容
写暂存器
4EH
将数据写入暂存器的TH、TL字节
复制暂存器
48H
把暂存器的TH、TL字节写到E2RAM中
重新调E2RAM
B8H
把E2RAM中的TH、TL字节写到暂存器TH、TL字节
读电源供电方式
B4H
启动DS18B20发送电源供电方式的信号给主CPU
CPU对DS18B20的访问流程是:
先对DS18B20初始化,再进行ROM操作命令,最后才能对存储器操作,数据操作。
DS18B20每一步操作都要遵循严格的工作时序和通信协议。
如主机控制DS18B20完成温度转换这一过程,根据DS18B20的通讯协议,须经三个步骤:
每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的操作。
Initializationprocedure“resetandpresencepulses”
C51程序
#include
#include
unsignedcharcodedisplaybit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsignedcharcodedisplaycode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x00,0x40};
unsignedcharcodedotcode[32]={0,3,6,9,12,16,19,22,25,28,31,34,38,41,44,48,50,53,56,59,63,66,69,72,
75,78,81,84,88,91,94,97};
unsignedchardisplaycount;
unsignedchardisplaybuf[8]={16,16,16,16,16,16,16,16};
unsignedchartimecount;
unsignedcharreaddata[8];
sbitDQ=P3^7;
bitsflag;
bitresetpulse(void)
{
unsignedchari;
DQ=0;
for(i=255;i>0;i--);
DQ=1;
for(i=60;i>0;i--);
return(DQ);
for(i=200;i>0;i--);
}
Voidwritecommandtods18b20(unsignedcharcommand)
{
unsignedchari;
unsignedcharj;
for(i=0;i<8;i++){
if((command&0x01)==0)
{DQ=0;
for(j=35;j>0;j--);
DQ=1;}
Else
{DQ=0;
for(j=2;j>0;j--);
DQ=1;
for(j=33;j>0;j--);}
command=_cror_(command,1);}
}
unsignedcharreaddatafromds18b20(void)
{unsignedchari;
unsignedcharj;
unsignedchartemp;
temp=0;
for(i=0;i<8;i++)
{temp=_cror_(temp,1);
DQ=0;
_nop_();
_nop_();
DQ=1;
for(j=10;j>0;j--);
if(DQ==1)
{temp=temp|0x80;}
else
{temp=temp|0x00;}
for(j=200;j>0;j--);
}
return(temp);
}
voidmain(void)
{TMOD=0x01;
TH0=(65536-4000)/256;
TL0=(65536-4000)%256;
ET0=1;
EA=1;
while(resetpulse());
writecommandtods18b20(0xcc);
writecommandtods18b20(0x44);
TR0=1;
while
(1){;}
}
voidt0(void)interrupt1using0
{unsignedcharx;
unsignedintresult;
TH0=(65536-4000)/256;
TL0=(65536-4000)%256;
if(displaycount==2)
{P0=displaycode[displaybuf[displaycount]]|0x80;}
else
{P0=displaycode[displaybuf[displaycount]];}
P2=displaybit[displaycount];
displaycount++;
if(displaycount==8)
{displaycount=0;}
timecount++;
if(timecount==150)
{timecount=0;
while(resetpulse());
writecommandtods18b20(0xcc);
writecommandtods18b20(0xbe);
readdata[0]=readdatafromds18b20();
readdata[1]=readdatafromds18b20();
for(x=0;x<8;x++)
{displaybuf[x]=16;}
sflag=0;
if((readdata[1]&0xf8)!
=0x00)
{sflag=1;
readdata[1]=~readdata[1];
readdata[0]=~readdata[0];
result=readdata[0]+1;
readdata[0]=result;
if(result>255)
{readdata[1]++;}}
readdata[1]=readdata[1]<<4;
readdata[1]=readdata[1]&0x70;
x=readdata[0];
x=x>>4;
x=x&0x0f;
readdata[1]=readdata[1]|x;
x=2;
result=readdata[1];
while(result/10)
{displaybuf[x]=result%10;
result=result/10;
x++;}
displaybuf[x]=result;
if(sflag==1)
{displaybuf[x+1]=17;}
x=readdata[0]&0x0f;
x=x<<1;
displaybuf[0]=(dotcode[x])%10;
displaybuf[1]=(dotcode[x])/10;
while(resetpulse());
writecommandtods18b20(0xcc);
writecommandtods18b20(0x44);
}
}
;这是关于DS18B20的读写程序,数据脚P2.2,晶振11.0592MHz
;温度传感器18B20汇编程序,采用器件默认的12位转化,最大转化时间750微秒
;可以将检测到的温度直接显示到AT89C51的两个数码管上
;显示温度00到99度,很准确无需校正!
ORG0000H
;单片机内存分配申明!
TEMPER_LEQU29H;用于保存读出温度的低8位
TEMPER_HEQU28H;用于保存读出温度的高8位
FLAG1EQU38H;是否检测到DS18B20标志位
a_bitequ20h;数码管个位数存放内存位置
b_bitequ21h;数码管十位数存放内存位置
MAIN:
LCALLGET_TEMPER;调用读温度子程序
;进行温度显示,这里我们考虑用网站提供的两位数码管来显示温度
;显示范围00到99度,显示精度为1度
;因为12位转化时每一位的精度为0.0625度,我们不要求显示小数所以可以抛弃29H的低4位
;将28H中的低4位移入29H中的高4位,这样获得一个新字节,这个字节就是实际测量获得的温度
;这个转化温度的方法可是我想出来的哦~~非常简洁无需乘于0.0625系数
MOVA,29H
MOVC,40H;将28H中的最低位移入C
RRCA
MOVC,41H
RRCA
MOVC,42H
RRCA
MOVC,43H
RRCA
MOV29H,A
LCALLDISPLAY;调用数码管显示子程序
CPLP1.0
AJMPMAIN
;这是DS18B20复位初始化子程序
INIT_1820:
SETBP2.2;数据脚
NOP
CLRP2.2;主机发出延时537微秒的复位低脉冲
MOVR1,#3
TSR1:
MOVR0,#107
DJNZR0,$
DJNZR1,TSR1
SETBP2.2;然后拉高数据线
NOP
NOP
NOP
MOVR0,#25H
TSR2:
JNBP2.2,TSR3;等待DS18B20回应
DJNZR0,TSR2
LJMPTSR4;延时
TSR3:
SETBFLAG1;置标志位,表示DS1820存在
CLRP1.7;检查到DS18B20就点亮P1.7LED
LJMPTSR5
TSR4:
CLRFLAG1;清标志位,表示DS1820不存在
CLRP1.1
LJMPTSR7
TSR5:
MOVR0,#117
TSR6:
DJNZR0,TSR6;时序要求延时一段时间
TSR7:
SETBP2.2
RET
;读出转换后的温度值
GET_TEMPER:
SETBP2.2
LCALLINIT_1820;先复位DS18B20
JBFLAG1,TSS2
CLRP1.2
RET;判断DS1820是否存在?
若DS18B20不存在则返回
TSS2:
CLRP1.3;DS18B20已经被检测到!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
MOVA,#0CCH;跳过ROM匹配
LCALLWRITE_1820
MOVA,#44H;发出温度转换命令
LCALLWRITE_1820
;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒
LCALLDISPLAY
LCALLINIT_1820;准备读温度前先复位
MOVA,#0CCH;跳过ROM匹配
LCALLWRITE_1820
MOVA,#0BEH;发出读温度命令
LCALLWRITE_1820
LCALLREAD_18200;将读出的温度数据保存到35H/36H
CLRP1.4
RET
;写DS18B20的子程序(有具体的时序要求)
WRITE_1820:
MOVR2,#8;一共8位数据
CLRC
WR1:
CLRP2.2
MOVR3,#5
DJNZR3,$
RRCA
MOVP2.2,C
MOVR3,#21
DJNZR3,$
SETBP2.2
NOP
DJNZR2,WR1
SETBP2.2
RET
;读DS18B20的程序,从DS18B20中读出两个字节的温度数据
READ_18200:
MOVR4,#2;将温度高位和低位从DS18B20中读出
MOVR1,#29H;低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:
MOVR2,#8;数据一共有8位
RE01:
CLRC
SETBP2.2
NOP
NOP
CLRP2.2
NOP
NOP
NOP
SETBP2.2
MOVR3,#8
RE10:
DJNZR3,RE10
MOVC,P2.2
MOVR3,#21
RE20:
DJNZR3,RE20
RRCA
DJNZR2,RE01
MOV@R1,A
DECR1
DJNZR4,RE00
RET
;显示子程序
display:
MOVA,29H;将29H中的十六进制数转换成10进制
MOVB,#10;10进制/10=10进制
DIVAB
MOVb_bit,A;十位在a
MOVa_bit,B;个位在b
MOVDPTR,#numtab;指定查表启始地址
MOVR0,#4
dpl1:
MOVR1,#250;显示1000次
dplop:
MOVA,a_bit;取个位数
MOVCA,@A+DPTR;查个位数的7段代码
MOVP0,A;送出个位的7段代码
CLRP2.7;开个位显示
ACALLd1ms;显示1ms
SETBP2.7
MOVA,b_bit;取十位数
MOVCA,@A+DPTR;查十位数的7段代码
MOVP0,A;送出十位的7段代码
CLRP2.6;开十位显示
ACALLd1ms;显示1ms
SETBP2.6
DJNZR1,dplop;100次没完循环
DJNZR0,dpl1;4个100次没完循环
RET
;1MS延时
d1ms:
MOVR7,#80
DJNZR7,$
RET
;实验板上的7段数码管0~9数字的共阴显示代码
numtab:
DB0CFH,03H,5DH,5BH,93H,0DAH,0DEH,43H,0DFH,0DBH
END
#include"reg51.h"
#include"INTRINS.H"
#include"LCD.h"
#defineCLR_RI(RI=0)
#defineCLR_TI(TI=0)
unsignedcharcodeID[2][8]={0x28,0x1D,0x25,0x1D,0x00,0x00,0x00,0x80,
0x28,0x0e,0x9e,0x1c,0x00,0x00,0x00,0x32};
unsignedcharcurrSensorNo=0;
sbitTMDAT=P1^7;
sbitRUN_LED=P1^6;
/*------------------------------------------------------------------------------------------------*/
voidserial_initial()
{
TMOD=0X20;
SCON=0X50;
PCON=0X00;
TL1=TH1=0XE8;
TR1=1;
}
/*------------------------------------------------------------------------------------------------*/
voidsend(unsignedcharcount,unsignedcharSEND_Buf[])
{unsignedchari;
for(i=0;i{SBUF=SEND_Buf[i];
while(!
TI);
CLR_TI;}
}
/*---------------------------------delayNms---------------------------------------------------*/
voidDelay_ms(unsignedintNms)
{unsignedchari;
while(Nms--)
for(i=0;i<125;i++);
}
/*-----------------------------------------delayNcount----------------------------------------------*/
voidDelay_Count(unsignedcharCount)
{while(Count>0)Count--;}
/*----------------------------------------------startResetPulse----------------------------------------------*/
voidtmreset(void)
{TMDAT=0;
Delay_Count(103);
TMDAT=1;
Delay_Count(4);
}
/*----------------------------------------ACK-------------------------------