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位为例:
| |||||||||||||||||||||||||||||||||||||||||
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进行预定的操作。
Initialization procedure “reset and presence pulses”
C51程序
#include
#include
unsigned char code displaybit[]={0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f};
unsigned char code displaycode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x00,0x40};
unsigned char code dotcode[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};
unsigned char displaycount;
unsigned char displaybuf[8]={16,16,16,16,16,16,16,16};
unsigned char timecount;
unsigned char readdata[8];
sbit DQ=P3^7;
bit sflag;
bit resetpulse( void)
{
unsigned char i ;
DQ=0;
for(i=255;i>0;i--) ;
DQ=1;
for(i=60;i>0;i--);
return(DQ);
for(i=200;i>0;i--);
}
Void write command to ds18b20 (unsigned char command)
{
unsigned char i;
unsigned char j;
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); }
}
unsigned char readdatafromds18b20(void)
{ unsigned char i;
unsigned char j;
unsigned char temp;
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);
}
void main(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) { ; }
}
void t0(void) interrupt 1 using 0
{ unsigned char x;
unsigned int result;
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度,很准确无需校正!
ORG 0000H
;单片机内存分配申明!
TEMPER_L EQU 29H ;用于保存读出温度的低8位
TEMPER_H EQU 28H ;用于保存读出温度的高8位
FLAG1 EQU 38H ;是否检测到DS18B20标志位
a_bit equ 20h ;数码管个位数存放内存位置
b_bit equ 21h ;数码管十位数存放内存位置
MAIN: LCALL GET_TEMPER ;调用读温度子程序
;进行温度显示,这里我们考虑用网站提供的两位数码管来显示温度
;显示范围00到99度,显示精度为1度
;因为12位转化时每一位的精度为0.0625度,我们不要求显示小数所以可以抛弃29H的低4位
;将28H中的低4位移入29H中的高4位,这样获得一个新字节,这个字节就是实际测量获得的温度
;这个转化温度的方法可是我想出来的哦~~非常简洁无需乘于0.0625系数
MOV A,29H
MOV C,40H ;将28H中的最低位移入C
RRC A
MOV C,41H
RRC A
MOV C,42H
RRC A
MOV C,43H
RRC A
MOV 29H,A
LCALL DISPLAY ;调用数码管显示子程序
CPL P1.0
AJMP MAIN
; 这是DS18B20复位初始化子程序
INIT_1820: SETB P2.2 ; 数据脚
NOP
CLR P2.2 ;主机发出延时537微秒的复位低脉冲
MOV R1, #3
TSR1: MOV R0, #107
DJNZ R0, $
DJNZ R1, TSR1
SETB P2.2 ;然后拉高数据线
NOP
NOP
NOP
MOV R0, #25H
TSR2: JNB P2.2, TSR3 ;等待DS18B20回应
DJNZ R0, TSR2
LJMP TSR4 ; 延时
TSR3: SETB FLAG1 ; 置标志位,表示DS1820存在
CLR P1.7 ; 检查到DS18B20就点亮P1.7LED
LJMP TSR5
TSR4: CLR FLAG1 ; 清标志位,表示DS1820不存在
CLR P1.1
LJMP TSR7
TSR5: MOV R0, #117
TSR6: DJNZ R0, TSR6 ; 时序要求延时一段时间
TSR7: SETB P2.2
RET
; 读出转换后的温度值
GET_TEMPER: SETB P2.2
LCALL INIT_1820 ;先复位DS18B20
JB FLAG1, TSS2
CLR P1.2
RET ; 判断DS1820是否存在?若DS18B20不存在则返回
TSS2: CLR P1.3 ;DS18B20已经被检测到!!!!!!!!!!!!!!!!!!
MOV A, #0CCH ; 跳过ROM匹配
LCALL WRITE_1820
MOV A, #44H ; 发出温度转换命令
LCALL WRITE_1820
;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒
LCALL DISPLAY
LCALL INIT_1820 ;准备读温度前先复位
MOV A, #0CCH ; 跳过ROM匹配
LCALL WRITE_1820
MOV A, #0BEH ; 发出读温度命令
LCALL WRITE_1820
LCALL READ_18200; 将读出的温度数据保存到35H/36H
CLR P1.4
RET
;写DS18B20的子程序(有具体的时序要求)
WRITE_1820: MOV R2, #8 ;一共8位数据
CLR C
WR1: CLR P2.2
MOV R3, #5
DJNZ R3, $
RRC A
MOV P2.2, C
MOV R3, #21
DJNZ R3, $
SETB P2.2
NOP
DJNZ R2, WR1
SETB P2.2
RET
; 读DS18B20的程序, 从DS18B20中读出两个字节的温度数据
READ_18200: MOV R4,#2 ; 将温度高位和低位从DS18B20中读出
MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00: MOV R2,#8 ; 数据一共有8位
RE01: CLR C
SETB P2.2
NOP
NOP
CLR P2.2
NOP
NOP
NOP
SETB P2.2
MOV R3,#8
RE10: DJNZ R3,RE10
MOV C,P2.2
MOV R3,#21
RE20: DJNZ R3,RE20
RRC A
DJNZ R2,RE01
MOV @R1,A
DEC R1
DJNZ R4,RE00
RET
;显示子程序
display: MOV A,29H ;将29H中的十六进制数转换成10进制
MOV B,#10 ;10进制/10=10进制
DIV A B
MOV b_bit ,A ;十位在a
MOV a_bit ,B ;个位在b
MOV DPTR, #numtab ;指定查表启始地址
MOV R0,#4
dpl1: MOV R1,#250 ;显示1000次
dplop:MOV A, a_bit ;取个位数
MOVC A,@A+DPTR ;查个位数的7段代码
MOV P0,A ;送出个位的7段代码
CLR P2.7 ;开个位显示
ACALL d1ms ;显示1ms
SETB P2.7
MOV A, b_bit ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
MOV P0,A ;送出十位的7段代码
CLR P2.6 ;开十位显示
ACALL d1ms ;显示1ms
SETB P2.6
DJNZ R1,dplop ;100次没完循环
DJNZ R0,dpl1 ; 4个100次没完循环
RET
;1MS延时
d1ms: MOV R7,#80
DJNZ R7,$
RET
;实验板上的7段数码管0~9数字的共阴显示代码
numtab: DB 0CFH,03H,5DH,5BH,93H,0DAH,0DEH,43H,0DFH,0DBH
END
#include "reg51.h"
#include "INTRINS.H"
#include "LCD.h"
#define CLR_RI (RI=0)
#define CLR_TI (TI=0)
unsigned char code ID[2][8]={ 0x28,0x1D,0x25,0x1D,0x00,0x00,0x00,0x80,
0x28,0x0e,0x9e,0x1c,0x00,0x00,0x00,0x32};
unsigned char currSensorNo=0;
sbit TMDAT = P1^7;
sbit RUN_LED = P1^6;
/*------------------------------------------------------------------------------------------------*/
void serial_initial()
{
TMOD=0X20;
SCON=0X50;
PCON=0X00;
TL1=TH1=0XE8;
TR1=1;
}
/*------------------------------------------------------------------------------------------------*/
void send(unsigned char count,unsigned char SEND_Buf[])
{ unsigned char i;
for(i=0;i
{ SBUF=SEND_Buf[i];
while(!TI);
CLR_TI; }
}
/*--------------------------------- delay N ms---------------------------------------------------*/
void Delay_ms (unsigned int Nms )
{ unsigned char i;
while(Nms--)
for(i=0; i<125; i++) ;
}
/*----------------------------------------- delay N count----------------------------------------------*/
void Delay_Count (unsigned char Count )
{ while(Count>0) Count--; }
/*---------------------------------------------- start Reset Pulse----------------------------------------------*/
void tmreset(void)
{ TMDAT=0;
Delay_Count(103);
TMDAT=1;
Delay_Count(4);
}
/*---------------------------------------- ACK--------------------------------------------------*/
void tmpre(void)
{ while(TMDAT);
while(~TMDAT);
Delay_Count(4);
}
/*------------------------------------Read a bit from 1820---------------------------------------------*/
bit tmrbit(void)
{ int i=0;
bit dat;
TMDAT=0;i++;
TMDAT=1;i++;i++;
dat = TMDAT;
Delay_Count(8);
return dat;
}
/*-------------------------------- Read a byte from 1820-----------------------------------------------*/
unsigned char tmrbyte(void)
{ unsigned char i,j,dat=0;
for(i=1;i<=8;i++)
{ j=tmrbit();
dat=(j<<7)|(dat>>1); }
return dat;
}
/*-------------------------------- Read a byte from 1820------------------------------------------------*/
void tmwbyte(unsigned char dat)
{ signed char i=0;
unsigned char j;
bit testb;
for(j=1;j<=8;j++)
{ testb=dat & 0x01;
dat = dat>>1;
if(testb)
{ TMDAT=0;
i++;i++;
TMDAT=1;
Delay_Count(8); }
else
{ TMDAT=0;
Delay_Count(8);
TMDAT=1;
i++;i++; }
}
}
/*------------------------------------- send convert command to 1820----------------------------------------------*/
void tmstart(void)
{ unsigned char i;
tmreset();
tmpre();
Delay_ms(1);
/* tmwbyte(0xcc);*/
tmwbyte(0x55);
for(i=0;i<8;i++)
tmwbyte(ID[currSensorNo][i]);
tmwbyte(0x44);
}
/*------------------------------------- Read tempreature from 1820--------------------------------------*/
unsigned int tmrtemp_all(void)
{ unsigned char a,b;
unsigned int y3;
unsigned char i;
tmreset();
tmpre();
Delay_ms(1);
/*tmwbyte(0xcc);*/
tmwbyte(0x55);
for(i=0;i<8;i++)
tmwbyte(ID[currSensorNo][i]);
tmwbyte(0xbe);
a = tmrbyte();
b = tmrbyte();
y3 = ((unsigned int)b) << 8;
return ((y3+a) & 0x7ff) ;
}
/*---------------------------------Start Test tempreature, All--------------------------------------------*/
void Display_AllTemp(void )
{unsigned int last;
unsigned char i,Dot;
RUN_LED=0;
Part=0;
LED_DISPLAY();
Delay_ms(1);
tmstart();
Delay_ms(800);
last=tmrtemp_all();
RUN_LED=1;
Dot= (last & 0x0f)*6.25 ;
Digit[0]= Dot%10;
Digit[1]=Dot/10;
last=(last>>4) & 0x7f ;
if( (last == 0x7f) ) // erro
{ for(i=0;i<5;i++) Digit[i]=16; }
else
{ for(i=2;i<5;i++)
{ Digit[i] = last %10;
last = last/10; }
if(Digit[4]==0)Digit[4]=17;
Part=1;
}
Digit[5]=currSensorNo;
LED_DISPLAY();
}
/*------------------------------------------------------------------------------------*/
/* void Read_Id()
{ unsigned char i,id[8];
tmreset();
tmpre();
Delay_ms(1);
tmwbyte(0x33);
for(i=0;i<8;i++)
id[i]=tmrbyte();
send(8,id);
} */
/*---------------------------------------- Main------------------------------------------------*/
void main(void)
{ unsigned char id[8]={1,2,3,4,5,6,7,8};
serial_initial();
send(8,id);
for(;;)
{ RUN_LED=!RUN_LED;
/* Read_Id();*/
TX_C =!TX_C ;
currSensorNo=(currSensorNo==1)?0:1;
Display_AllTemp();
/*Change();*/
send(6,Digit);
Delay_ms(1000);
_nop_();
}
}
本文来源:https://www.2haoxitong.net/k/doc/b73570743b68011ca300a6c30c2259010202f31b.html
文档为doc格式