DS18B20是一款低成本低开销的数字温度传感器,它的测量范围在-55℃ ~ 125℃之间,固有误差为1摄氏度,在-10℃ ~ 85℃之间的精度为0.5℃,能够满足日常测温需求。
DS18B20采用OneWire(单线)通信协议,只需要一根信号线就可以完成数据的读写。供电也允许有独立供电和数据寄生供电两种模式,在寄生供电模式下电源线接地,电源从数据线上获取,可以节省一根连接线。
连线方式
DS18B20有三个引脚:
- VDD,外部电源,如果使用寄生供电模式,该端接地
- DQ,数据引脚,需要上拉电阻拉高
- GND,接地端,提供参考低电平
独立供电模式
需要给DQ提供一个5kΩ的弱上拉电阻
独立供电电路
寄生供电模式
需要给DQ提供一个5kΩ的弱上拉电阻,在DS18B20工作时,需要给DQ提供一个强上拉。如果DS18B20工作在超过100℃的环境下,漏电流会比较大,寄生供电的工作方式可能无法正常为DS18B20供电,此时需要设计为独立供电模式。
寄生供电电路
驱动代码
DS18B20采用OneWire协议通信,OneWire通信协议的实现这里就不详细说明了,对于Arduino来说已经内建了OneWire库,可以直接使用。
寄存器结构
DS18B20内建有三种寄存器:
- 高速缓存,测量的环境温度会缓存在此
- 暂存器,上电后对DS18B20的配置以及温度转换后的数值都存放在此,以备读写
- EEPROM,配置都可转储到这里做永久保存,也可从这里读取配置到暂存器上去使用,详见指令寄存转储和寄存恢复
指令集
指令 | 类型 | 功能 | 描述 |
---|---|---|---|
0x33 | ROM指令 | 读取ROM | 读取64位只读唯一识别码,其中第一个字节为固定识别符0x28,最后一个字节为CRC检验码 |
0x55 | ROM指令 | 查询ROM | 查找总线上是否有指定识别码的DS18B20存在 |
0xF0 | ROM指令 | 枚举ROM | 枚举总线上DS18B20的数量和固定标识符 |
0xCC | ROM指令 | 忽略ROM | 跳过ROM查询流程 |
0xEC | ROM指令 | 枚举告警 | 枚举总线上处于告警状态的DS18B20的标识符 |
0x44 | 功能指令 | 温度转换 | 开始探测环境温度并存储到寄存器上 |
0xBE | 功能指令 | 读取数据 | 读取RAM中的数据 |
0x4E | 功能指令 | 设置阈值 | 设置高温告警温度TH和低温告警温度TL |
0x48 | 功能指令 | 寄存转储 | 把RAM中TH、TL和配置转储到EEPROM中 |
0xB8 | 功能指令 | 寄存恢复 | 把EEPROM中的数据恢复到RAM中的TH、TL和配置位上 |
0xB4 | 功能指令 | 查询供电方式 | 查询供电方式 |
和DS18B20通信要遵循一定的访问时序:
- 主机下拉DQ脚至少480μs做复位操作,然后恢复上拉等待15-60μs
- DS18B20下拉DQ脚60~240μs做"存在"应答
- 主机发送ROM指令,然后拉高DQ
- [读取DS18B20的回复]
- 主机发送功能指令,然后拉高DQ
- [读取DS18B20的回复]
DS18B20是指令严格流程化的,如果通信指令的时序不正确,DS18B20会不应答主机的请求。每次访问DS18B20都要重复上面的所有步骤,否则只有不完整的流程时序会得不到DS18B20的应答。
CRC校验
CRC = X8+X5+X4+1
枚举ROM
#define DS18B20_PIN 2
OneWire onewire(DS18B20_PIN);
byte address[8];
int count = 0;
void enumerateROM() {
while (onewire.search(address)) {
count++;
for (byte i = 0; i < 8; i++) {
Serial.print(count);
Serial.print(": 0x");
if (address[i] < 0x10) Serial.print("0"); Serial.println(address[i], HEX);
}
}
}
温度读取
#define STARTCONVERT 0x44
#define READDATA 0xBE
#define DS18B20_PIN 2
OneWire onewire(DS18B20_PIN);
byte address[8]; // 枚举ROM时可获得
bool isParasite = true; // 是否为寄生供电模式
float readTemperature() {
byte temperature[2];
byte highAlarmTemperature;
byte lowAlarmTemperature;
byte configuration;
byte crc;
// 请求温度转换
onewire.reset();
onewire.select(address);
onewire.wirte(STARTCONVERT, isParasite);
// 等待DS18B20完成温度转换
delay(delayForResolution(bitResolution));
// 开始读取DS18B20的数据
int result = onewire.reset();
if (result == 0) {
// DS18B20正在做温度转换,忙
return;
}
onewire.select(address);
onewire.write(READDATA);
// byte 0: temperature LSB
// byte 1: temperature MSB
// byte 2: high alarm temp
// byte 3: low alarm temp
// byte 4: configuration register
// byte 5: internal use
// byte 6: internal use
// byte 7: internal use
// byte 8: CRC
for (byte pos = 0; pos < 9; pos++) {
switch (pos) {
case 0: temperature[0] = onewire.read(); break;
case 1: temperature[1] = onewire.read(); break;
case 2: highAlarmTemperature = onewire.read(); break;
case 3: lowAlarmTemperature = onewire.read(); break;
case 4: configuration = onewire.read(); break;
case 8: crc = onewire.read(); break;
}
}
onewire.reset();
// 计算温度值
return (((unsigned int) temperature[1]) << 11) |
(((unsigned int) temperature[0]) << 3);
}
/**
* 根据DS18B20的说明文档所述,不同精度的温度转换需要的时间不同
* 需要等待DS18B20完成温度转换后再读取温度,否则得到的温度为0℃
*/
unsigned int delayForResolution(byte bitResolution) {
switch (bitResolution) {
case 9: return 94; // 9位精度等待94ms
case 10: return 188; // 10位精度等待188ms
case 11: return 375; // 11位精度等待375ms
default:
return 750; // 默认等待750ms
}
}
代码还没验证过,大概是这样啦~→_→←_←
网友评论