当前位置:文档之家› DS18B20介绍、流程图和程序源代码

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、21 温度高字节 6 计数器余值2 TH/用户字节1 存放温度上限7 计数器/℃3 HL/用户字节2 存放温度下限8 CRC CRC校验图1 DS18B20引脚分布图以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)。

9位测量分辨率0.5℃;10位测量分辨率0.25℃;11位测量分辨率0.125℃;12位测量分辨率0.0625℃;9~12位的测量,无论采用哪种分辨率,温度整数的有效位均是表中26~20;1、DS18B20控制方法在硬件上,DS18B20与单片机的连接有两种方法,一种是VCC接外部电源,GND接地,I/O与单片机的I/O线相连;另一种是用寄生电源供电,此时U DD、GND接地,I/O接单片机I/O。

无论是内部寄生电源还是外部供电,I/O口线要接5kΩ左右的上拉电阻。

DS18B20有六条控制命令,如下表所示:CPU对DS18B20的访问流程是:先对DS18B20初始化,再进行ROM操作命令,最后才能对存储器操作,数据操作。

DS18B20每一步操作都要遵循严格的工作时序和通信协议。

如主机控制DS18B20完成温度转换这一过程,根据DS18B20的通讯协议,须经三个步骤:每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的操作。

Initialization procedure “reset and presence pulses ”开始 发一个DS18B20序列号执行期间匹配命令 延时1s 启动在线DS18B20温度AD 转换 发跳过ROM 命令、发转换命令初始化DS18B20读在线DS18B20序号发出搜索ROM 命令DS18B20复位 所有在线DS18B20访问完? 存在一个DS18B20?初始化DS18B20 发读暂存RAM 指令 读匹配的DS18B20温度YYNN多点温度检测软件流程图YN读DS18B20温度的流程图DS18B20是否存在?(读DS18B20测量温度子程序)GET-TEMPA TURE 开始YN数据端置位 读温度值返回复位DS18B20(调用RESETDS18B20)写温度转换命令44H (调用WRITE18B20)写跳过ROM 匹配命令0CCH (调用WRITE18B20) 延时750μs ?(读温度前)复位DS18B20 (调用RESETDS18B20) 写跳过POM 匹配命令0CCH(调用WRITE18B20) 写读温度字节命令0BEH(调用WRITE18B20)读温度(调用READ18B20)NOPCLR P2.2;主机发出延时537微秒的复位低脉冲MOV R1, #3TSR1: MOV R0, #107DJNZ R0, $DJNZ R1, TSR1SETB P2.2 ;然后拉高数据线NOPNOPNOPMOV R0, #25HTSR2: JNB P2.2, TSR3 ;等待DS18B20DJNZ R0, TSR2LJMP TSR4 ; 延时TSR3: SETB FLAG1 ; 置标志位,表示CLR P1.7 ; 检查到DS18B20就点亮P1.7LEDLJMP TSR5TSR4: CLR FLAG1 ; 清标志位,表示DS1820不存在CLR P1.1LJMP TSR7TSR5: MOV R0, #117TSR6: DJNZ R0, TSR6 ; 时序要求延时一段时间TSR7: SETB P2.2RET循环右移一次 写DS18B20(子程序)开始进位标志位清零延时30μs数据端清零指令字节写完?YN进位标志位值送数据端延时(15μs)数据端置位(拉高数据线)DS18B20写返回 写DS18B20指令字节的流程图存低位字节数据一个字节是否读完?布尔累加器C 清零YN读DS18B20两个温度字节的流程图是低位字节数据?(读DS18B20的温度字节子程序)READ18B20开始 读数据端(数据) 数据端清零 YN延时(10μs) 数据端置位 DS18B20读返回延时(2μs) 数据端置位 延时(3μs) 延时(25μs)保存所读一位数据存高位字节数据C51程序#include <AT89X52.H>#include <INTRINS.h>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,29HMOV C,40H ;将28H中的最低位移入CRRC AMOV C,41HRRC AMOV C,42HRRC AMOV C,43HRRC AMOV 29H,ALCALL DISPLAY ;调用数码管显示子程序CPL P1.0AJMP MAIN; 这是DS18B20复位初始化子程序INIT_1820: SETB P2.2 ; 数据脚NOPCLR P2.2 ;主机发出延时537微秒的复位低脉冲MOV R1, #3TSR1: MOV R0, #107DJNZ R0, $DJNZ R1, TSR1SETB P2.2 ;然后拉高数据线NOPNOPNOPMOV R0, #25HTSR2: JNB P2.2, TSR3 ;等待DS18B20回应DJNZ R0, TSR2LJMP TSR4 ; 延时TSR3: SETB FLAG1 ; 置标志位,表示DS1820存在CLR P1.7 ; 检查到DS18B20就点亮P1.7LEDLJMP TSR5TSR4: CLR FLAG1 ; 清标志位,表示DS1820不存在CLR P1.1LJMP TSR7TSR5: MOV R0, #117TSR6: DJNZ R0, TSR6 ; 时序要求延时一段时间TSR7: SETB P2.2RET; 读出转换后的温度值GET_TEMPER: SETB P2.2LCALL INIT_1820 ;先复位DS18B20JB FLAG1, TSS2CLR P1.2RET ; 判断DS1820是否存在?若DS18B20不存在则返回TSS2: CLR P1.3 ;DS18B20已经被检测到!!!!!!!!!!!!!!!!!!MOV A, #0CCH ; 跳过ROM匹配LCALL WRITE_1820MOV A, #44H ; 发出温度转换命令LCALL WRITE_1820;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒LCALL DISPLAYLCALL INIT_1820 ;准备读温度前先复位MOV A, #0CCH ; 跳过ROM匹配LCALL WRITE_1820MOV A, #0BEH ; 发出读温度命令LCALL WRITE_1820LCALL READ_18200; 将读出的温度数据保存到35H/36HCLR P1.4RET;写DS18B20的子程序(有具体的时序要求)WRITE_1820: MOV R2, #8 ;一共8位数据CLR CWR1: CLR P2.2MOV R3, #5DJNZ R3, $RRC AMOV P2.2, CMOV R3, #21DJNZ R3, $SETB P2.2NOPDJNZ R2, WR1SETB P2.2RET; 读DS18B20的程序, 从DS18B20中读出两个字节的温度数据READ_18200: MOV R4,#2 ; 将温度高位和低位从DS18B20中读出MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H) RE00: MOV R2,#8 ; 数据一共有8位RE01: CLR CSETB P2.2NOPNOPCLR P2.2NOPNOPNOPSETB P2.2MOV R3,#8RE10: DJNZ R3,RE10MOV C,P2.2MOV R3,#21RE20: DJNZ R3,RE20RRC ADJNZ R2,RE01MOV @R1,ADEC R1DJNZ R4,RE00RET;显示子程序display: MOV A,29H ;将29H中的十六进制数转换成10进制MOV B,#10 ;10进制/10=10进制DIV A BMOV b_bit ,A ;十位在aMOV a_bit ,B ;个位在bMOV DPTR, #numtab ;指定查表启始地址MOV R0,#4dpl1: MOV R1,#250 ;显示1000次dplop:MOV A, a_bit ;取个位数MOVC A,@A+DPTR ;查个位数的7段代码MOV P0,A ;送出个位的7段代码CLR P2.7 ;开个位显示ACALL d1ms ;显示1msSETB P2.7MOV A, b_bit ;取十位数MOVC A,@A+DPTR ;查十位数的7段代码MOV P0,A ;送出十位的7段代码CLR P2.6 ;开十位显示ACALL d1ms ;显示1msSETB P2.6DJNZ R1,dplop ;100次没完循环DJNZ R0,dpl1 ; 4个100次没完循环RET;1MS延时d1ms: MOV R7,#80DJNZ 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<count;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=!R UN_LED;/* Read_Id();*/TX_C =!TX_C ;currSensorNo=(currSensorNo==1)?0:1;Display_AllTemp();/*Change();*/send(6,Digit);Delay_ms(1000);_nop_();}}。

相关主题