1、温度采集元件—DS18B20传感器
要想将温度转换为数据,必不可少的就是传感器了。
DS18B20是美国DALLAS公司推出的数字温度传感器,网上查阅资料发现DALLAS公司被Maxim Integrated公司收购了,所以也可以说是由Maxim Integrated公司生产。
特点:
1.它采用单总线接口进行通信,可以直接与微处理器连接。
2.通过单一引脚进行数据传输和供电。
3.DS18B20具有高精度的温度测量能力,精度可达±0.5摄氏度。
4.DS18B20还具有较宽的工作温度范围(-55摄氏度至+125摄氏度)、
5.数字温度转换功能和多种不同封装形式可供选择。
由于其精准度高、接口简单、稳定可靠等特点,DS18B20被广泛应用于各种需要温度监测的领域,如工业控制、电子设备、医疗器械、气象站等。
DS18B20结构图:
这里DS18B20有3个管脚,其中GND接地,VDD接5V电源,DQ连接单片机,DQ在连接单片机的同时还需接一个上拉电阻。
2、单总线串行扩展
单总线(也称1-Wire bus)由美国DALLAS公司推出的外围串行扩展总线。只有一条数据输入/输出线DQ,总线上所有器件都挂在DQ上,电源也通过这条信号线供给。
单总线系统中配置的各种器件,由DALLAS公司提供的专用芯片实现。每个芯片都有64位ROM,厂家对每一芯片都用激光烧写编码,其中存有16位十进制编码序列号,它是器件的地址编号,确保它挂在总线上后,可以唯一被确定。除了器件的地址编码外,芯片内还包含收发控制和电源存储电路,见图11-1。这些芯片耗电量都很小(空闲时几µW,工作时几mW),工作时从总线上馈送电能到大电容中就可以工作,故一般不需另加电源。
3、将DS18B20传感器与单片机联系起来
首先来了解DS18B20的ROM操作。
通过上图我们知道有上面4个ROM操作,这里我们着重记忆CCH代码,因为我们接下来的实验仅使用了1个DS18B20,所以就不需要访问其他的ROM地址,CCH代码跳过就行了。
访问完ROM,我们的下一步是访问RAM。
片内有9个字节的高速暂存器RAM单元,9个字节具体分布如下:
第3、4字节分别是由软件写入用户报警的上下限值TH和TL。
第5个字节为配置寄存器,可对其更改DS18B20的测温分辨率,高速暂存器的第6、7、8字节未用,为全1。第9字节是前面所有8个字节的CRC码,用来保证正确通信。片内还有1个E2PROM为TH、TL以及配置寄存器的映像。
温度低位和温度高位两个字节共同保存了温度数据,它的原理比较简单,需要我们记忆其转换温度的方法,但在了解转换温度的方法前,我们还需了解第5个字节——配置寄存器以及分辨率。
分辨率代表了什么?
答:代表传感器识别一次温度所需的时间,我们通过调节R1和R0可以得到不同的分辨率。
为什么叫分辨率?
答:我们要得到传感器的信息,得到的信息越详细那意味着所需时间越久,分辨率代表了所得到温度数据的位数,位数越多就需要更多时间进行转换。
配置寄存器的作用
配置寄存器主要是用来调节分辨率的,通过改变配置寄存器的R1和R0即可调分辨率。
这里TM是为0不能改变的,也就是只能调R1和R0.
如何计算温度
了解完上述内容后我们就可以开始计算温度了。
我们知道温度一共是由温度低位和温度高位两个字节构成,这也决定了它包含了16位数。前5位用来算作符号位,前5位为0时表示正数,为1时表示负数。接着再来看数据位,数据位的前7位为整数位,后4位为小数位。
了解完上面条件后我们可以将存储的二进制数据转换为10进制,最后再乘0.0625即为实际温度。
比如第一行的数据00000 1111101000转换为十进制为2000,2000*0.0625=125;
比如第三行的数据11111 11001101111转换为十进制,首先看到符号位为负数,所以负数减1再求反,得110010001转换为10进制就是25.0625同时它为负数。
下面我们来了解DS18B20的RAM操作有哪些。
我们在后面示例中需要用到启动温度转换和读取暂存器的温度数据这两个功能,所以我们先着重记忆44H和BEH。
4、实例——单总线DS18B20温度测量系统
题目:利用DS18B20和LED数码管实现单总线温度测量系统,原理电路见下图。DS18B20测量范围是−55~128℃。本例只显示00~99。通过本例读者应掌握DS18B20特性及单片机I/O实现单总线协议的方法。
要实现上述操作,我们需要DS18B20启动温度转换,然后读取暂存温度
我们的步骤为:初始化 → 访问ROM (寻找使用的DS18B20)→ 访问RAM (启动温度转换)→ 初始化 → 访问ROM →访问RAM(读取温度)
这里为什么要访问两次RAM指令,因为在实际调用过程中,我们不能访问完一个RAM指令后马上去访问另一个RAM指令所以需要重新初始化→访问RAM最后到ROM
DS18B20初始化:
访问DQ需要经过以下阶段:
阶段1:
DQ置低电平持续最低480微秒最高960微秒。
阶段2:
DQ转高电平15最低微秒最高60微秒,这时DS18B20会发送低电平信号,收到这个低电平信号后我们再将DQ拉高。
初始化代码如下:
void init_ds18b20(void) //函数功能:18B20初始化
{
uchar i;
DQ =0; //DQ在定义在了全局
for(i=0;i<240;i++);//用for循环来延时,这里表示低电平持续480微秒
DQ =1;
delay5(16); //自己定义了一个delay函数来代替写for循环更加轻松
delay5(80);
}
访问ROM和访问RAM可用同一函数,地址写入DQ代码如下:
void writebyte(uchar dat) //函数功能:写1字节
{
uchar i=0;
for(i=8;i>0;i--)
{
DQ =0;
DQ =dat&0x01; //写"1" 在15µs内拉低
delay5(12); //写"0" 拉低60µs
DQ = 1;
dat>>=1; //上面使用了并运算让DQ取dat最后一位,这里再右移一位
delay5(5);
}
}
在发出读取温度的指令后,我们需要写一串代码来接收这个两位数据
uchar readbyte(void) //函数功能:读取1字节数据
{
uchar i=0;
uchar date=0;
for (i=8;i>0;i--)
{
DQ =0;
delay5(1);
DQ =1; //15µs内拉释放总线
date>>=1;
if(DQ)
date|=0x80;
delay5(11);
}
return(date);
}
将上述操作组合起来就能将温度传入单片机
uchar retemp(void) //函数功能:读取温度
{
uchar a,b,tt;
uint t;
init_ds18b20();
writebyte(0xCC);
writebyte(0x44);
init_ds18b20();
writebyte(0xCC);
writebyte(0xBE);
a=readbyte();
b=readbyte();
t=b;
t<<=8;
t=t|a;
tt=t*0.0625;
return(tt);
}
总代码如下:
#include "reg51.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define out P0
sbit smg1=out^4;
sbit smg2=out^5;
sbit DQ=P3^7;
void delay5(uchar);
void init_ds18b20(void);
uchar readbyte(void);
void writebyte(uchar);
uchar retemp(void);
void main(void) //主函数
{
uchar i,temp;
delay5(1000);
while(1)
{
temp=retemp();
for(i=0;i<10;i++) //连续扫描数码管10次
{
out=(temp/10)&0x0f;
smg1=0;
smg2=1;
delay5(1000); //延时5ms
out=(temp%10)&0x0f;
smg1=1;
smg2=0;
delay5(1000); //延时5ms
}
}
}
void delay5(uchar n) //函数功能:延时5µs
{
do
{
_nop_();
_nop_();
_nop_();
n--;
}
while(n);
}
void init_ds18b20(void) //函数功能:18B20初始化
{
uchar i;
DQ =0;
for(i=0;i<240;i++);
DQ =1;
delay5(16);
delay5(80);
}
uchar readbyte(void) //函数功能:读取1字节数据
{
uchar i=0;
uchar date=0;
for (i=8;i>0;i--)
{
DQ =0;
delay5(1);
DQ =1; //15µs内拉释放总线
date>>=1;
if(DQ)
date|=0x80;
delay5(11);
}
return(date);
}
void writebyte(uchar dat) //函数功能:写1字节
{
uchar i=0;
for(i=8;i>0;i--)
{
DQ =0;
DQ =dat&0x01; //写"1" 在15µs内拉低
delay5(12); //写"0" 拉低60µs
DQ = 1;
dat>>=1;
delay5(5);
}
}
uchar retemp(void) //函数功能:读取温度
{
uchar a,b,tt;
uint t;
init_ds18b20();
writebyte(0xCC);
writebyte(0x44);
init_ds18b20();
writebyte(0xCC);
writebyte(0xBE);
a=readbyte();
b=readbyte();
t=b;
t<<=8;
t=t|a;
tt=t*0.0625;
return(tt);
}
效果展示:
可以看到,LED数码管读数跟随DS18B20变化。
接下来我们在keil的示波器上进行波形验证:
第一节低电平最宽,它是初始化第一步,在代码里消耗了480微秒,然后置高电平,停留一段时间,DS18B20就会传回来一个低电平然后开始访问ROM指令RAM指令,再第二节低电平重复上述步骤,发出了读的指令,然后单片机接收温度信号。