15-DS18B20温度传感器的基本应用
DS18B20温度传感器的基本应用
DS18B20是Dallas半导体公司的一款数字温度传感器芯片
DS18B20是一款支持1-wire总线接口的温度传感器
DS18B20的温度范围-55\(^{\circ}\)C-125\(^{\circ}\)C,精度为\(\pm0.5^{\circ}\)C
DS18B20可将分辨率设置为9到12位
DS18B20的工作电压范围3-5.5v
DS18B20内部结构
以下是Dallas半导体的DS18B20结构图
1.电源与寄生电源
- 正常情况下是从VDD供电一直到内部INTERNAL VDD
- 如果底下VDD不接,则通过DQ取出电源正极一直通过二极管到内部INTERNAL VDD,通过Cpp电容进行供电
- Power Supply sense :电源供给感应,感应外部VDD是否存在
2.64位ROM(只读存储器)和单总线Port
- 作为器件地址,作为总线通信的寻址
3.存储器控制逻辑
4.Scratchpad(高速缓存器)
高速缓存器就是用来存各种数据的,一共可以存9个字节的数据
存的就是5、6、7、8、9这几个模块的数据
5.温度传感器(Temperature LSB and MSB)
Byte0和Byte1存的就是温度,就是传感器已经换算好的数字温度,Byte0是温度的低八位,Byte1是温度的高八位
由上可知上电的复位温度为85\(^{\circ}\)C
也就是055H = 0000 0101 0101 0000=1360,因为默认的分辨率为12位(0.0625\(^{\circ}\)C)所以复位的默认温度位1360*0.0625=85\(^{\circ}\)C
DS18B20以16位带符号位扩展的二进制补码形式读出,单位是摄氏度,两个字节一共是16位,温度的换算表格如下:
由上可知:MS BYTE为Byte1即高八位,LS BYTE为Byte0即低八位
高字节的5个S是符号位,S= 1表示温度为正,S=0,表示温度为负
12位分辨率,最后一位是1/16=0.0625,所以最小的温度分辨率是0.0625\(^{\circ}\)C
11位分辨率,最后一位是1/8=0.125,所以最小的温度分辨率是0.125\(^{\circ}\)C
10位分辨率,最后一位是1/4=0.25,所以最小的温度分辨率是0.25\(^{\circ}\)C
9位分辨率,最后一位是1/2=0.5,所以最小的温度分辨率是0.5\(^{\circ}\)C
正温度的读取
因为存的温度是补码,正数的原码和补码是一样的,直接读数
比如+85摄氏度:0000 0101 0101 0000 = 1360(转换为10进制)
将该10进制*分辨率 = 温度,由于默认分辨率位12位即: 1360×0.0625=85
负温度的读取
因为存的温度是补码负数的补码转换位原码步骤为:先取反,再+1
比如-55摄氏度:的补码是:1111 1100 1001 0000 (高5位是符号位)
所以真实的补码为:100 1001 0000;
补码取反之后,再+1;
也就是011 0110 1111 +1=011 0111 0000 =880(十进制)
即真实的温度为880×0.0625=55
如下为几个温度对应的补码:
6-7报警触发寄存器
Byte2对应的是TH,也就是高温报警值,用户自己设置
Byte3对应的是TL,也就是低温报警值,用户自己设置
8.配置寄存器(Conflguration Register (EEPROM))
Byte4对应的计时配置寄存器的值:
配置寄存器是用来配置温度的分辨率,可以把温度的分辨率配置为9bit,10bit,11bit,12bit
分别对应的实际温度分辨率为0.5\(^{\circ}\)C,0.25\(^{\circ}\)C,0.125\(^{\circ}\)C,0.0625\(^{\circ}\)C,默认为12位分辨率(0.0625\(^{\circ}\)C)
配置寄存器的内容如下图:
Byte5、Byte6、Byte7为保留字节
CRC
CRC发生器产生校验码,存在Byte8,是64位ROM中的前56位编码的校验码,由CRC设置
【1】初始化DS18B20
时序如下:
初始化就是先将总线拉高,检查是否存在该温度传感器,如果有总线就会给一个低电平脉冲,如果没有就一直是高电平
也就是说默认给高电平,拉低高电平,然后给一个480us的延迟
然后再拉高,接收给过来的数据,如果为0则有数据过来,为1反之
bit Init_DS18B20(void) {
bit Initflag = 0;
DQ = 1;
DS18B20_Delay(5); // 25us
DQ = 0; //
DS18B20_Delay(100);// 500us
DQ = 1;
//DS18B20_Delay(5);// 25us
Initflag = DQ;
DS18B20_Delay(100);
return Initflag;
}
ROM指令
这个ROM指令就是查询DS18B20的64位序列号,相当于设备地址,在多个DS18B20总线连接,需要区分每一个DS18B20设备,如果是单个就不需要查询序列号,但是不查询也要发一条指令0xCC,表示跳过ROM指令
以下是ROM指令集
指令名称 | 指令代码 | 指令功能 |
---|---|---|
读ROM | 0x33 | 读DS18B20 ROM中的编码 |
ROM匹配 | 0x55 | 发出次命令之后,接着发出64位的ROM编码,编码匹配的器件会作出回应,接着就可以对该器件进行读写 |
搜索ROM | 0xF0 | 用于确定总线上器件的个数,并识别ROM编码,为操作器件做准备 |
跳过ROM | 0xCC | 忽略ROM编码,直接向器件发温度变换命令 |
警报搜索 | 0xEC | 这个指令发出之后,如果温度超过了设定的上限或下限,器件才会有所回应 |
功能指令
指令命令 | 指令代码 | 指令功能 |
---|---|---|
温度转换 | 0x44 | 启动器件的温度转换,这个转换是需要时间的,转换之后的结果就存在暂存器的Byte1和Byte0中 |
读暂存器 | 0xBE | 读暂存器全部9个Byte的内容 |
写暂存器 | 0x4E | 往暂存器Byte4和Byte3写数据,就是设置温度的上限和下限 |
复制暂存器 | 0x48 | 将暂存器Byte4和Byte3的数据复制到EEPROM中 |
重调EEPROM | 0xB8 | 将EEPROM中的内容恢复到暂存器的Byte4和Byte3中 |
读供电方式 | 0xB4 | 读器件的供电模式,寄生供电时,器件返回0,外接电源供电时,器件返回1 |
写数据
由于要用到写操作,这边先来介绍下写的时序
DS18B20的数据线只有一根,在这根线上完成读和写,所需要的时序就会比较严格
DS18B20的写时序
MCU往DS18B20写一个BIT的"0"
MCU先把总线拉低,拉低时将数据放置到DQ,拉低时需要持续60-120us之间,然后释放总线(释放总线。上拉电阻就把总线拉高了)
MCU往DS18B20写一个BIT的"1"
MCU把总线拉低,拉低时间需要大于1us,拉低时将数据放置到DQ,然后在15us内把总线拉高,然后延迟45us走完时序
这边可同时进行,如果对应的位数有1来临,则置一,否则清0
void Write_DS18B20(unsigned char dat) {
unsigned char i;
for(i = 0; i < 8;i++) {
DQ = 0;
DQ = dat & 0x01;
DS18B20_Delay(5);
DQ = 1;
DS18B20_Delay(10);
dat >>= 1;
}
DS18B20_Delay(5);
}
读数据
由于要用到读操作,这边先来介绍下读的时序
MCU从DS18B20读一个BIT:
MCU先把总线拉低,DS18B20检测到总线被拉低1us后,便开始往外送数据,如果送出的是"0",DS18B20就把
总线拉低,一直读到周期结束,如果送出的是“1” ,就释放总线,让上拉电阻把总线拉高
也就是说先把总线拉低,再拉高,如果DQ为1则将该高位置一,然后再延迟45us,走完时序
unsigned char Read_DS18B20(void) {
unsigned char i;
unsigned char dat;
for(i = 0; i< 8;i++) {
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ) {
dat = dat | 0x80;
}
DS18B20_Delay(10);
}
return dat;
}
DS18B20的温度转换与读取流程
- 【1】DS18B20复位
- 【2】写入字节0XCC,跳过ROM指令
- 【3】写入字节0X44,开始温度转换
- 【4】延时700~900ms
- 【5】DS18B20复位
- 【6】写入字节0XCC,跳过ROM指令
- 【7】写入字节0XBE,读取高速暂存器
- 【8】读取暂存器的第0字节,即温度数据的LSB
- 【9】读取暂存器的第1字节,即温度数据的MSB
- 【10】DS18B20复位,表示读取数据结束
代码如下:
io扩展:
#include <REGX52.H>
#include "absacc.h"
#include "OneWire.h"
// 不带小数点
unsigned char SMGNODot_CA[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
// 带小数点
unsigned char SMGDot_CA[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
unsigned int temp;
void DelaySMG(unsigned int t) {
while(t--);
}
void _74HC138(unsigned char n) {
switch(n) {
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
}
}
void DisplaySMG_Bit(unsigned char pos,unsigned char dat) {
_74HC138(7);
P0 = 0xff;
_74HC138(6);
P0 = 0x01 << pos;
_74HC138(7);
P0 = dat;
}
void Display_All(unsigned char dat) {
_74HC138(6);
P0 = 0xff;
_74HC138(7);
P0 = dat;
}
void Display_SMG_temp(unsigned int temp) {
DisplaySMG_Bit(7,SMGNODot_CA[temp%10]);
DelaySMG(500);
// 567 567/10 == 56 / 10 == 5..6
DisplaySMG_Bit(6,SMGDot_CA[(temp/10)%10]);
DelaySMG(500);
DisplaySMG_Bit(5,SMGNODot_CA[(temp/100)%10]);
DelaySMG(500);
Display_All(0xff);
}
void Delay(unsigned int t) {
while(t--) {
Display_SMG_temp(temp);
}
}
void DS18B20_Reading(void) {
unsigned char LSB,MSB;
Init_DS18B20();
// 跳过ROM
Write_DS18B20(0xCC);
// 温度转换
Write_DS18B20(0x44);
Delay(1000);
Init_DS18B20();
// 跳过ROM
Write_DS18B20(0xCC);
// 读暂存器
Write_DS18B20(0xBE);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
Init_DS18B20();
temp = 0x0000;
temp = MSB;
temp = temp << 8 | LSB;
if((temp & 0xf800) == 0x0000) {
temp >>= 4;
temp = temp * 10;
temp = temp + (LSB & 0x0f) *0.625;
}
}
void main(void) {
_74HC138(4);
P0 = 0xff;
_74HC138(5);
P0 = 0x00;
while(1) {
DS18B20_Reading();
Display_SMG_temp(temp);
}
}
存储器映射:
#include <REGX52.H>
#include "absacc.h"
#include "OneWire.h"
// 不带小数点
unsigned char SMGNODot_CA[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
// 带小数点
unsigned char SMGDot_CA[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
unsigned int temp;
void DelaySMG(unsigned int t) {
while(t--);
}
void DisplaySMG_Bit(unsigned char pos,unsigned char dat) {
XBYTE[0xE000] = 0xff;
XBYTE[0xC000] = 0x01 << pos;
XBYTE[0xE000] = dat;
}
void Display_All(unsigned char dat) {
XBYTE[0xC000] = 0xff;
XBYTE[0xE000] = dat;
}
void Display_SMG_temp(unsigned int temp) {
DisplaySMG_Bit(7,SMGNODot_CA[temp%10]);
DelaySMG(500);
// 567 567/10 == 56 / 10 == 5..6
DisplaySMG_Bit(6,SMGDot_CA[(temp/10)%10]);
DelaySMG(500);
DisplaySMG_Bit(5,SMGNODot_CA[(temp/100)%10]);
DelaySMG(500);
Display_All(0xff);
}
void Delay(unsigned int t) {
while(t--) {
Display_SMG_temp(temp);
}
}
void DS18B20_Reading(void) {
unsigned char LSB,MSB;
Init_DS18B20();
// 跳过ROM
Write_DS18B20(0xCC);
// 温度转换
Write_DS18B20(0x44);
Delay(1000);
Init_DS18B20();
// 跳过ROM
Write_DS18B20(0xCC);
// 读暂存器
Write_DS18B20(0xBE);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
Init_DS18B20();
temp = 0x0000;
temp = MSB;
temp = temp << 8 | LSB;
if((temp & 0xf800) == 0x0000) {
temp >>= 4;
temp = temp * 10;
temp = temp + (LSB & 0x0f) *0.625;
}
}
void main(void) {
XBYTE[0X8000] = 0XFF;
XBYTE[0Xa000] = 0x00;
while(1) {
DS18B20_Reading();
Display_SMG_temp(temp);
}
}