萬事俱備,整合吧!
在上一篇中了解了DS18B20的暫存器架構及溫度值的計算後,本篇就是完成讀取溫度值的最後一步:整合!底下我們從接線方式、程式架構及程式碼等三個方面依序說明!
接線方式
再次重申,此程式只適用於Arduino與DS18B20於一對一的連接狀況下喲!此外,請注意,於Arduino的接線pin腳是7不是2,若你的接腳有調整時,請調整程式內的設定!程式架構
底下之讀取溫度架構圖是關鍵函式-getTemp()的架構解析,而數字所標明的區域為前面所寫的工具副程式:1、重啟程序(綠色):Arduino將電位拉低並維持480μs,DS18B20應簽低電位值既代表重啟程序OK。
2、命令程序(藍色):命令拆解成為位元,再使用寫位元(Write bit)程序使用DS18B20
3、讀取程序(黃色):讀取DS18B20給予之位元值,並組合成一字元(Byte)
4、計算溫度值(紅色):將讀取程序的位元值(LSB及MSB)轉換為溫度值
除了整合上述四個工具副程式外,其中,要注意的是等待轉換的時間設定,
不同的位元(9-12位元)精密度有不同的轉換時間如下表所示,在這裡直接設定750μs,可確保其轉換時間充足。
程式碼及輸出
程式碼有點長,但其實就是初始設定、關鍵程式庫(getTemp()-程式行號為17至31行)及工具程式碼的結合!程式碼
const uint8_t g_dq_pin =7; //Arduino數位腳位7接到DS18B20
#define Skip_ROM 0xcc //用於1對1時,省略每次作ROM序號確認程序
#define Convert_T 0x44 //啟動溫度轉換
#define Read_Scratchpad 0xbe //讀取暫存器值,有9個字元
void setup() {
Serial.begin(9600);
Serial.println("<>");
}
void loop() {
Serial.print("DS18b20's Temperature ->");
Serial.println(getTempC());
delay(1000);
}
float getTempC()
{
while(!CommandReset()); //重啟成功,再進行動作
SendCommand(Skip_ROM); //主機下0xcc命令(1對1的省略ROM確認作業)
SendCommand(Convert_T); //0x44啟動溫度轉換
delay(750);
//再次重啟,因為要作通訊作業
while(!CommandReset()); //重啟成功,再進行動作
SendCommand(Skip_ROM); //主機下0xcc命令(1對1的省略ROM確認作業)
SendCommand(Read_Scratchpad); //0xBE溫度暫存器中的訊息(共9個字元)
//前兩個字元就是溫度的訊息
uint8_t LSB = ReceiveData(); //第一個讀到的是低位
uint8_t MSB = ReceiveData(); //第二個讀到的是高位
return Caculate_Temperature(LSB,MSB);
}
float Caculate_Temperature(uint8_t temp_LSB , uint8_t temp_MSB)
{
boolean fp_minus = false; //温度正負標誌:預設為false,因為通常為零度以上
if(temp_MSB > 0x7f) //當temp_MSB>7代表此溫度為負數值時,測到的數值需要先反相再加 1
{
fp_minus = true; //溫度正負指標,負數時fg_Minus=0
temp_MSB = ~temp_MSB; //將temp_MSB中的每一位元反相(0、1互換)
temp_LSB = ~temp_LSB + 1;
//將temp_LSB中的每一位元反相(0、1互換),要記得加一,才能正確的反應其值
}
//以十六位元空箱來結合MSB及LSB
uint16_t raw_temp =
(((uint16_t)temp_MSB) << 8) | //將MSB先用空的十六位元左移8個位元,等於乘256
(((uint16_t)temp_LSB));
float fp_temp = raw_temp * 0.0625;
//將十六位元的整數值再乘於0.0625的單位值,既得溫度值
if(fp_minus) {fp_temp = -fp_temp;} //當fp_minus是1,代表是負數,將溫度加上負號
return fp_temp;
}
uint8_t ReceiveData()
{
uint8_t byte_in=0;
for(uint8_t i = 0; i < 8; i++)
{
//此時所測到的電位,就是此位元的資料
if(ReadSlot()) {
//看看此時主機線的電位狀況若為高位,就是1
bitSet(byte_in, i); //將byte_in第i個位元值,設置為1
}
else {
bitClear(byte_in, i); //將byte_in第i個位元值,設置為0
}
}
return (byte_in);
}
uint8_t ReadSlot() {
delayMicroseconds(1);
pinMode(g_dq_pin, OUTPUT); //轉為輸出,可達到高電位
digitalWrite(g_dq_pin, LOW); //將電位拉低告訴DS18B20,主機已準備好了
delayMicroseconds(2);
pinMode(g_dq_pin, INPUT); //轉為輸入狀態,同時釋放線路
delayMicroseconds(10); //加前面的延時,約於12~13us時取樣
uint8_t fp=digitalRead(g_dq_pin);
delayMicroseconds(55); //加上延時過渡此段作業時間60us
return fp;
}
void SendCommand(uint8_t instruction)
{
for(uint8_t i = 0; i < 8; i++) {
WriteSolt(bitRead(instruction, i));
}
}
void WriteSolt(uint8_t order_bit)
{
if(order_bit) { //當值為1時的處理,
pinMode(g_dq_pin, OUTPUT); //先將pin腳改為輸出狀態
digitalWrite(g_dq_pin, LOW); //將電位拉低,等於通知DS18B20要do something
delayMicroseconds(10); //至少要等待1us,但於15us前轉為高電位
pinMode(g_dq_pin, INPUT); //將接收轉成INPUT狀態,轉為高電位
delayMicroseconds(60); //加前段的延時至少等待60us過此周期
}
else { //當寫入值為'0'時,Tx拉低電位時段60~120us
pinMode(g_dq_pin, OUTPUT); //先轉為輸出狀態
digitalWrite(g_dq_pin, LOW); //將電位輸出低電位
delayMicroseconds(65); //靜靜的等待DS18B20來讀取資料
pinMode(g_dq_pin, INPUT); //釋放電位控制轉回輸入狀態
delayMicroseconds(5); //等待上拉電阻將電位復位為HIGH
}
}
uint8_t CommandReset()
{
pinMode(g_dq_pin, OUTPUT);
digitalWrite(g_dq_pin, LOW);
delayMicroseconds(720);
pinMode(g_dq_pin, INPUT);
delayMicroseconds(70);
uint8_t is_exist = !digitalRead(g_dq_pin);
delayMicroseconds(410);
return is_exist;
}
程式輸出
結語
歷經了前面淺水區的練功期,再加上此階段的暫存器、溫度值轉換,如今,終於看到溫度值了!不過,高興一下就好!這樣就結束了嗎?當然沒那麼簡單,讀到溫度值只是此階段的甜頭,但不是終點,因為,溫度值雖然出來了,但我們要保證讀取到DS18B20的溫度值是正確無誤,要達到這個功能就必須掌握DS18B20的檢核功能-CRC碼檢驗,只要通過了檢驗,就代表此數值無誤,我們可以安心使用了!
那麼,就讓我們邁入檢核程式階段吧!
沒有留言:
張貼留言