DS18B20是比較常見的溫度傳感器之一,如何用arduino連接DS18B20並讀取數據。當然也有必要瞭解一下DS1820和1-Wire。
DS18x20和1-Wire
DS18x20系列數字溫度傳感器主要有DS18S20和DS18B20(DS18S20只有9位一種工作模式,分辨率只到0.5攝氏度,DS18B20有9、10、11、12位四種工作可編程控制的模式,分辨率最高為0.0625攝氏度。),都是由美國Dallas半導體公司(現在改名叫Maxim)生產的。這個系列最大的特點就是採用了Maxim的專利技術1-Wire。
DS18x20系列數字溫度傳感器主要有DS18S20和DS18B20(DS18S20只有9位一種工作模式,分辨率只到0.5攝氏度,DS18B20有9、10、11、12位四種工作可編程控制的模式,分辨率最高為0.0625攝氏度。),都是由美國Dallas半導體公司(現在改名叫Maxim)生產的。這個系列最大的特點就是採用了Maxim的專利技術1-Wire。
顧名思義,1-Wire就是採用單一信號線,但可像I2C,SPI一樣,同時傳輸時鐘(clock)又傳輸數據(data),而且數據傳輸是雙向的。1-Wire 使用較低的數據傳輸速率,通常是用來溝通小型device,如數位溫度計。通過1-Wire技術可以在單一信號線的基礎上構成傳感器網絡,Maxim起名”MicroLan”。
DS18x20的供電主要有兩種模式:
Parasite
power mode/寄生供電
所謂的寄生供電是指DS18x20只需要兩根接線,一根數據線,一根接地線,數據線上還要接一個4.7k上拉電阻連電源,數據線同時也提供了電能。DS18x20內置了電容,高電平期時把電能儲存在內部電容裏,低電平期內消耗內部電容裏的能量工作,直到下次高電平期內再次電容充電。雖然這樣的模式簡化了線路同時也帶來了一些缺陷:
1. 電路的電流一般很小,只有當DS18x20進行溫度轉化或者寫EEPROM時會高達1.5mA,當DS18x20進行上述操作時,數據線必須保持電平拉高狀態直到操作結束,期間master端的Arduino不能做任何操作,DS18x20溫度轉化時這個時間間隔大概是750ms。
2.如果要求DS18x20有精確的轉化,數據線在溫度轉化期間必須保證足夠的能量,但當你使用多個DS18x20構成MicroLan進行多點測溫時,單靠4.7k的上拉電阻無法提供足夠的能量,會導致較大的測溫誤差。
Normal
(external supply) mode/標準(外部供電)
標準外部供電模式,相比寄生供電模式,每個DS18x20需要多一條獨立的電源線接獨立電源。雖然多用些線,但由於外部供電,保證了每個設備的進精確度和穩定性。而且沒有了上述溫度轉換期間Arduino不能做任何事的問題。
對DS18x20和1-Wire想瞭解更多的可以點這裏:
http://www.arduino.cc/playground/Learning/OneWire
http://www.arduino.cc/playground/Learning/OneWire
今天嘗試的就是Arduino+單個DS18B20+寄生供電。
採用寄生供電模式接溫度傳感器DS18B20,同時在Serial Monitor顯示溫度數據。
如果DS18B20的VDD針腳再接5V的話,就是外部供電模式了。
電路圖
在開始程式之前,我們需要瞭解一下DS18x20的資料構成,每個DS18x20系列產品ROM裏存放著一個64位字符串,包含8位的family code(0×10代表DS18S20, 0×28代表DS18B20 , 0×22代表DS1822)、48位序列碼、8位的CRC(Cyclical Redundancy Check/循環冗餘校驗碼,就是一串用於數據校驗的數字)。這樣ROM code就讓每個DS18x20都有個獨立ID,master端可以通過MATCH
ROM來確定其身份。
怎麼獲得溫度數據呢?當master端發出CONVERT指令時,指定的slave device就會開始溫度轉化過程。這個過程挺慢,前面提到過,大概需要750ms,會產生2位的數據,被儲存在RAM裏一個叫Scratchpad的地方,這個數據可以隨意讀寫。我們可以通過READ SCRATCHPAD指令讀取溫度數據,返回的是一個9位的數據(數據構成如圖所示)。
溫度的話我們還需要用以下公式進行轉換:
Temp = ((HighByte << 8 ) + LowByte ) *0.0625
Temp = ((HighByte << 8 ) + LowByte ) *0.0625
#include <OneWire.h>
// DS18S20 Temperature chip i/o
OneWire ds(10); // on pin 10
void setup(void) {
// initialize inputs/outputs
// start serial port
Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
Serial.print("No more addresses.\n");
ds.reset_search();
return;
}
Serial.print("R=");
for( i = 0; i < 8; i++) {
Serial.print(addr[i], HEX);
Serial.print(" ");
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.print("CRC is not valid!\n");
return;
}
if ( addr[0] == 0x10) {
Serial.print("Device is a DS18S20 family device.\n");
}
else if ( addr[0] == 0x28) {
Serial.print("Device is a DS18B20 family device.\n");
}
else {
Serial.print("Device family is not recognized: 0x");
Serial.println(addr[0],HEX);
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print("P=");
Serial.print(present,HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print( OneWire::crc8( data, 8), HEX);
Serial.println();
}
雖然我們讀到了Scratchpad的數據,但是顯示的是HEX16進制代碼,看不懂啊,我們還需要轉化成我們能讀的溫度格式。這裏推薦一個叫Dallas Temperature Control的Library,大大簡化了這個過程。
// Load Libraries for DS1820 and OneWire
#include <OneWire.h>
#include <DallasTemperature.h>
// Variables for temperature readings
float myTemp;
float myHighTemp;
float myLowTemp = 50;
// DS1820 Data wire is plugged into pin 4 on the Arduino
#define ONE_WIRE_BUS 4
// Setup oneWire instance to communicate with devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup()
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");
// Start the OneWire library
sensors.begin();
}
void loop()
{
// Read the temperature
readtemp();
// Write the Results to the serial Monitor
serialPrint();
}
void readtemp()
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
sensors.requestTemperatures(); // Send the command to get temperatures
myTemp = (sensors.getTempCByIndex(0));
// Set High or Low Temp
if (myTemp < myLowTemp) { myLowTemp = myTemp; } if (myTemp > myHighTemp) {
myHighTemp = myTemp;
}
}
void serialPrint()
{
Serial.print("Current Temp: ");
Serial.print(myTemp);
Serial.print("C");
Serial.print(" Lowest Temp: ");
Serial.print(myLowTemp);
Serial.print("C");
Serial.print(" Highest Temp: ");
Serial.print(myHighTemp);
Serial.println("C");
delay (500);
Serial.print("Or if you prefer : ");
Serial.print(DallasTemperature::toFahrenheit(myTemp));
Serial.print("F / ");
Serial.print(DallasTemperature::toFahrenheit(myLowTemp));
Serial.print("F / ");
Serial.print(DallasTemperature::toFahrenheit(myHighTemp));
Serial.println("F ");
Serial.println();
delay (500);
}
Dallas Temperature Control Library
http://www.milesburton.com/?title=Dallas_Temperature_Control_Library
沒有留言:
張貼留言