(二)、溫度傳感器
1、One-Wire總線
?One-Wire總線利用一根線實現雙向通信。因此其協議對時序的要求較嚴格,如應答等時序都有明確的時間要求。基本的時序包括復位及應答時序、寫一位時序讀一位時序。單總線即只有一根數據線,系統中的數據交換、控制都由這根線完成。設備(主機或從機)通過一個漏極開路或三態端口連至該數據線,以允許設備在不發送數據時能夠釋放總線,而讓其他設備使用總線。由于它們是主從結構,只有主機呼叫從機時,從機才能應答,因此主機訪問One-Wire器件都必須嚴格遵循單總線命令序列,即初始化、ROM命令、功能命令。
對于藍橋杯的同學,One-Wire協議官方會提供,不需要大家自己寫。DS18B20的通信過程較為簡單。圖 五為藍橋杯DS18B20原理圖,DQ即用于通信的單總線,需要在函數開始定義該引腳sbit DQ = P1^4;
DS18B20的通信過程:初始化總線---寫ROM指令(跳過ROM指令0xcc)---寫RAM指令(開始溫度轉換0x44)---重新初始化---ROM指令(跳過ROM指令0xcc)---寫RAM指令(開始溫度讀取0xbe)---接收數據(先低位再高位)---分析處理數據。(如圖 六)
? ? ? ? ? ? ? ? ? ? ? ? ?圖 五DS18B20原理圖
? ? ? ? ? ? ? ? ? ? ? ? ?圖 六 DS18B20通信過程
?
2、代碼解讀(圖 七)(數據處理分析)
數據處理: High<<8 高八位數據以二進制的形式左移八位就變成了unsigned int 類型數據,后八位數據全為0,此時用 | Low 運算符來獲取后八位數據,則((High<<8)|Low)就是獲取到了初步的溫度數據,float(對象)就是強制轉換括號中數據為float數據類型,但溫度高五位是符號位(圖 八),當這五個全是0時溫度為正值,全為1則為負值。后四位是小數位,此時要*0.0625或者/16.0來獲取到適合的溫度區間,例如0000 0000 0000 0011表示十進制數據3,最后一位精度為0.0625,3*0.0625即為溫度數據。
? ? ? ? ? ? ? ? ? ? ?圖 七 DS18B20代碼解讀
? ? ? ? ? ? ? ? ? ? ?圖 八 DS18B20數據存儲位
?
附相關代碼(注意藍橋杯官方會給初始化、寫入、讀取等底層)
#include <STC15F2K60S2.H>
#include <INTRINS.h>sbit DQ = P1^4;void Delay_OneWire(unsigned int t)
{unsigned char i;while(t--){for(i=0;i<12;i++);}
}//仿真用這個延時
//void Delay_OneWire(unsigned int t)
//{
// while(t--);
//}//
void Write_DS18B20(unsigned char dat)
{unsigned char i;for(i=0;i<8;i++){DQ = 0;DQ = dat&0x01;Delay_OneWire(5);DQ = 1;dat >>= 1;}Delay_OneWire(5);
}//
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 |= 0x80;} Delay_OneWire(5);}return dat;
}//
bit init_ds18b20(void)
{bit initflag = 0;DQ = 1;Delay_OneWire(12);DQ = 0;Delay_OneWire(80);DQ = 1;Delay_OneWire(10); initflag = DQ; Delay_OneWire(5);return initflag;
}/*
DS18B20的通信過程:初始化總線寫ROM指令(跳過ROM指令0xcc)寫RAM指令(開始溫度轉換0x44)重新初始化ROM指令(跳過ROM指令0xcc)寫RAM指令(開始溫度讀取0xbe)接收數據(先低位再高位)分析處理數據
*/float Temperature_Read(void)
{unsigned char Low,High;init_ds18b20(); //初始化總線Write_DS18B20(0xcc); //跳過ROM指令Write_DS18B20(0x44); //開始溫度轉換Delay_OneWire(200);init_ds18b20(); //重新初始化Write_DS18B20(0xcc); //跳過ROM指令Write_DS18B20(0xbe); //開始讀取溫度(低位優先)Low = Read_DS18B20(); //接收數據(先低位再高位)High = Read_DS18B20();return (float)((High<<8)|Low)/16.0; //分析處理數據
}
?
?
?