? ? ? DS18B20是一种数字温度传感器,应用非常广泛。它输出的是数字信号,同时具有体积小,硬件资源耗费少,抗干扰能力强,精度高等特点
1.独特的单线接口,仅需要一个端口引脚进行通讯
2.每一个器件有唯一的64位序列号存储在内部存储器中
3.简单的多点分布式测温应用
4.无需外部器件
5.可通过数据线供电。供电范围是3.0V到5.5V
6.测温范围为-55~+125℃,在-10~+85℃范围内精确度是±0.5℃
7.温度计分辨率可以被使用者选用9~12位
8.最多在750ms内将温度转换为12位数字
9.掉电保护功能, DS18B20温度传感器内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度。在DS18B20温度传感器掉电以后仍可保存分辨率及报警温度的设定值。
10.DS18B20温度传感器返回16位二进制数代表此刻探测的温度值,其高五位代表正负。如果高五位全部为1,则代表返回的温度值为负值。如果高五位全部为0,则代表返回的温度值为正值。后面的11位数据代表温度的绝对值,将其转换为十进制数值之后,再乘以0.0625即可获得此时的温度值。
? DS18B20温度传感器寄生电源供电方式如下图所示。在寄生电源供电方式下,DS18B20温度传感器从信号线上汲取电源:在信号线高电平时把电能储存在内部电容里;在信号线低电平时消耗电容上的电能,直到信号线高电平到来再给电容(寄生电源)充电。然而,当DS18B20在执行温度转换或从高速暂存器向EPPROM传送数据的时候,工作电流可能高达1.5mA。这个电流可能会引起连接单总线的弱上拉电阻的不可接受的压降,这需要更大的电流,而此时Cpp无法提供,为保证DS18B20有充足的供电,当进行温度转换或拷贝EEPROM操作时,必须给单总线提供一个强上拉,用漏极开路把I/O直接拉到电源上就可以实现。
在外部电源供电方式下,DS18B20温度传感器工作电源由VDD引脚接入,不存在电源电流不足的问题,可以保证转换精度。同时在总线上可以挂接多个DS18B20温度传感器,组成多点测温系统。外部电源供电方式是DS18B20温度传感器最佳供电方式:工作稳定可靠、抗干扰能力强、电路也比较简单。
DS18B20温度传感器的内部由64位ROM、高速缓冲存储器、CRC生成器、温度敏感器件、高低温触发器及配置寄存器等部件组成
每只 DS18B20 都有一个唯一存储在 ROM 中的 64 位编码。最前面 8 位是单线系列 编码:28h。接着的 48 位是一个唯一的序列号。最后 8 位是以上 56 位的 CRC 编 码。64 位 ROM 和 ROM 操作控制区允许 DS18B20作为单总线器件并按照作为单总线器件并按照详述于单总线系统节的单总线协议工作。
?DS18B20温度传感器内有9个字节高速缓冲存储单元,下图所示
存储器有一个暂存 SRAM 和一个存储高低报警触发值 TH 和 TL 的非易失性电可擦除 EEPROM 组成。注意当报警功能不使用时,TH 和 TL 寄存器可以被当作普通寄存器使用。所有的存储器指令被详述于 DS18B20 功能指令节。
存储器的第 4 位为配置寄存器,其组织见图 8。用户可以通过按表 3 所示设置 R0 和 R1 位来设定 DS18B20 的精度。上电默认设置:R0=1,R1=1(12 位精度)。注意: 精度和转换时间之间有直接的关系。暂存器的位 7 和位 0-4 被器件保留,禁止写 入;在读回数据时,它们全部表现为逻辑 1。
执行序列通过单线总线端口访问 DS18B20 的协议如下:
步骤1. 初始化
步骤2. ROM 操作指令
步骤3. DS18B20 功能指令
每一次 DS18B20 的操作都必须满足以上步骤,若是缺少步骤或是顺序混乱,器件 将不会返回值。例如这样的顺序:发起 ROM 搜索指令[F0h]和报警搜索指令[ECh] 之后,总线控制器必须返回步骤 1。
初始化
通过单总线的所有执行操作处理都从一个初始化序列开始。初始化序列包括一个 由总线控制器发出的复位脉冲和其后由从机发出的存在脉冲。存在脉冲让总线控 制器知道 DS18B20 在总线上且已准备好操作,详见单总线信号节。
ROM 指令
一旦总线控制器探测到一个存在脉冲,它就发出一条 ROM 指令。如果总线上挂有 多只 DS18B20,这些指令将基于器件独有的 64 位 ROM 片序列码使得总线控制器 选出特定要进行操作的器件。这些指令同样也可以使总线控制器识别有多少只, 什么型号的器件挂在总线上,同样,它们也可以识别哪些器件已经符合报警条件。 ROM 指令有 5 条,都是 8 位长度。总线控制器在发起一条 DS18B20 功能指令之前 必须先发出一条 ROM 指令。
DS18B20 功能指令
在总线控制器发给欲连接的 DS18B20 一条 ROM 命令后,跟着可以发送一条 DS18B20 功能指令。这些命令允许总线控制器读写 DS18B20 的暂存器,发起温度转换和识 别电源模式。
? ? ? DS18B20温度传感器经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。所以当我们只想简单的读取温度值的时候,只用读取暂存器中的第0和第1个字节就可以了。
? 简单的读取温度值的步骤如下:
? ? ? 1、跳过ROM操作。??????? 2、发送温度转换命令。
? ? ? 3、跳过ROM操作。??????? 4、发送读取温度命令。
? ? ? 5、读取温度值。
主器件首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有DS18B20温度传感器已做出应答。若无低电平出现一直都是高电平说明总线上无DS18B20温度传感器应答。
做为从器件的DS18B20温度传感器在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。
?由两种写时序:写 1 时序和写 0 时序。总线控制器通过写 1 时序写逻辑 1 到 DS18B20,写 0 时序写逻辑 0 到 DS18B20。所有写时序必须最少持续 60us,包括 两个写周期之间至少 1us 的恢复时间。当总线控制器把数据线从逻辑高电平拉到 低电平的时候,写时序开始(见图 14)。 总线控制器要生产一个写时序,必须把数据线拉到低电平然后释放,在写时序开 始后的 15us 释放总线。当总线被释放的时候,5K 的上拉电阻将拉高总线。总控 制器要生成一个写 0 时序,必须把数据线拉到低电平并持续保持(至少 60us)。 总线控制器
18B20 在一个 15us 到 60us 的窗口内对 I/O 线采 样。如果线上是高电平,就是写 1。如果线上是低电平,就是写 0。
?对于读数据操作时序也分为读0时序和读1时序两个过程。
? ? ? 读周期是从主器件把单总线拉低1微秒之后就得释放单总线为高电平,以让DS18B20温度传感器把数据传输到单总线上。作为从机DS18B20温度传感器在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束。若要送出1则释放总线为高电平。
? ? ? 主器件在一开始拉低总线1微秒后释放总线,然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为0。采样期内总线为高电平则确认为1。完成一个读时序过程,至少需要60微秒才能完成。
?
因为DS18B20对时序的要求特别严格,所以我们在书写代码之前需要先确定一个相对准确的延时时间。这里需要用到debug进行调试。
在得到准确的时序后,我们接下来就开始正式进入DE18B20的温度函数书写了。
#include<stc89c5xrc.h>
#include<intrins.h>
#include<stdio.h>
#define uint unsigned int
#define uchar unsigned char
#define dstemp P22
#define dula P26
#define wela P27
uchar num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void DelayXus(uchar xus);
void DsReset();//初始化
void DsWriteDat(uchar dat);//写数据
uchar DsReadDat();//读一个字节的数据
int DsTempGet();//实现一次温度采集
void DisPlayTemper(int v shu);
void DelayMs(uint c);
void Init();
void main()
{
int DisTemp;
Init();
// DelayXus(1);//7
// DelayXus(2);//10
// DelayXus(3);//12
// DelayXus(4);//14
// DelayXus(5);//17
// DelayXus(100);//222
// DelayXus(250);//548
while(1)
{
if(num>=20)
{
num=0;
DisTemp=DsTempGet();
}
DisPlayTemper(DisTemp);
}
}
void DelayXus(uchar xus)
{
while(--xus);
}
void DsReset()//DS18B20初始化
{
dstemp=1;//数据线置1
DelayXus(1);
dstemp=0;
DelayXus(250);
dstemp=1;
DelayXus(250);
}
void DsWriteDat(uchar dat)//写一个字节
{
uchar i;
bit dstp;
for(i=0;i<8;i++)
{
dat=dat>>1;
dstp=CY;
if(dstp)//控制器写1
{
dstemp=1;
DelayXus(1);
dstemp=0;
DelayXus(1);
dstemp=1;
DelayXus(30);
}
else
{
dstemp=1;
DelayXus(1);
dstemp=0;
DelayXus(30);
}
}
}
uchar DsReadDat()//读一个字节的数据
{
uchar dat,i,k;
for(i=0;i<8;i++)
{
dstemp=1;
DelayXus(1);
dstemp=0;
DelayXus(1);
dstemp=1;
k=dstemp;
dat=(k<<7)|(dat>>1);
DelayXus(20);
}
return dat;
}
int DsTempGet()//实现一次温度采集
{
int temper;
uchar dat1,dat2;
DsReset();
DsWriteDat(0xcc);
DsWriteDat(0x44);
DsReset();
DsWriteDat(0xcc);
DsWriteDat(0xBE);
dat1=DsReadDat();//读第一个字节
dat2=DsReadDat();//读第二个字节
temper=dat2;
temper=(temper<<8)|dat1;
return temper;
}
void DisPlayTemper(int shu)
{
int tem;
float temper;
ET0=0;
if(shu&0x8000)
tem=~shu+1;
else
tem=shu;
temper=shu*0.0625;
tem=temper*10+0.5;//四舍五入
if(shu&0x8000)
{
wela=1;
P0=0XFE;
wela=0;
P0=0;
dula=1;
P0=0x40;
dula=0;
DelayMs(2);
}
wela=1;
P0=0XFD;
wela=0;
P0=0;
dula=1;
P0=table[tem/100];
dula=0;
DelayMs(2);
wela=1;
P0=0XFB;
wela=0;
P0=0;
dula=1;
P0=table[tem/10%10]|0x80;
dula=0;
DelayMs(2);
wela=1;
P0=0XF7;
wela=0;
P0=0;
dula=1;
P0=table[tem%10];
dula=0;
DelayMs(2);
ET0=1;
}
void DelayMs(uint c)
{
uint a,b;
for(a=c;a>0;a--)
for(b=115;b>0;b--);
}
void Time0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;//装初值
num++;
}
void Init()
{
TMOD=0x21;//配置定时器0是工作模式1,定时器1是工作模式2
TH0=(65536-46296)/256;
TL0=(65536-46296)%256;//装初值
TH1=0xfd;//bps为9600
TL1=0xfd;//装初值
EA=1;//打开总中断
ES=1;//打开串行口中断
ET0=1;//打开定时器0的中断
// ET1=1;//打开定时器1的中断
TR0=1;//启动定时器0
TR1=1;//启动定时器1
// EX0=1;//打开外部中断0
// IT0=1;//设置中断类型为下降沿
SCON=0x50;//01010000
}