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
}
}
代碼還沒驗證過,大概是這樣啦~→_→←_←