目錄
1,DS18B20介紹
2,DS18B20數(shù)據(jù)手冊?
2.1,初始化時(shí)序?
2.2,讀寫時(shí)序?
3,DS18B20工作流程
4,代碼
?
1,DS18B20介紹
DS18B20的基本特征:
(1)內(nèi)置集成ADC,外部數(shù)字接口,也就是可以直接與單片機(jī)的數(shù)字接口連接,DS18B20 在使用中不需要任何外圍元件,全部傳感元件及轉(zhuǎn)換電路集成在形如一只三極管的集成電路內(nèi);
(2)單總線數(shù)字接口,布線成本低,獨(dú)特的單線接口方式,DS18B20 在與微處理器連接時(shí)僅需要一條線即可實(shí)現(xiàn)微處理器與DS18B20 的雙向通訊;
(3)溫范圍-55℃~+125℃,在-10~+85℃時(shí)精度為±0.5℃;
(4)數(shù)字值溫度分辨率位數(shù)可軟件設(shè)置,可根據(jù)需要設(shè)置分辨率位數(shù),可編程的分辨率為9~12 位,對應(yīng)的可分辨溫度分別為0.5℃、0.25℃、0.125℃ 和0.0625℃,可實(shí)現(xiàn)高精度測溫;
(5)溫度閾值報(bào)警功能,且閾值可內(nèi)置存儲(chǔ)掉電不丟失;
(6)在9 位分辨率時(shí)最多在93.75ms 內(nèi)把溫度轉(zhuǎn)換為數(shù)字,12 位分辨率時(shí)最多在750ms 內(nèi)把溫度值轉(zhuǎn)換為數(shù)字,速度更快,DS18B20溫度采集是由主CPU控制,需要采集溫度時(shí)才工作;
(7)內(nèi)置唯一64位序列碼,CPU可以單線串聯(lián)無限多個(gè)DS18B20,CPU通過序列碼識(shí)別與哪個(gè)DS18B20通信,DS18B20 支持多點(diǎn)組網(wǎng)功能,多個(gè)DS18B20 可以并聯(lián)在唯一的三線上,實(shí)現(xiàn)組網(wǎng)多點(diǎn)測溫;
(8)支持VDD供電,或通過數(shù)據(jù)總線及內(nèi)部電容實(shí)現(xiàn)寄生電源供電,也就是可以通過數(shù)據(jù)線(DQ)來供電,如果通過數(shù)據(jù)線供電,數(shù)據(jù)線在不傳輸數(shù)據(jù)時(shí),需要拉高,否則如果內(nèi)部電容沒電時(shí)DS18B20就不能工作了;
(9)測量結(jié)果直接輸出數(shù)字溫度信號(hào),以"一根總線"串行傳送給CPU,同時(shí)可傳送CRC 校驗(yàn)碼,具有極強(qiáng)的抗干擾糾錯(cuò)能力?
使用到的三根線是GND(接地)、DQ(數(shù)據(jù)線)、VCC(電源線),當(dāng)然也可以只使用GND和DQ。?
綜合評價(jià):
(1)DS18B20是很多年前的東西了;
(2)現(xiàn)在趨向于溫度+濕度的綜合傳感器;
(3)現(xiàn)實(shí)應(yīng)用一般低端用熱敏電阻、熱電偶,高端用精密傳感器;
(4)學(xué)習(xí)重點(diǎn)和難點(diǎn)是單總線協(xié)議的時(shí)序編程實(shí)現(xiàn);
2,DS18B20數(shù)據(jù)手冊?
DS18B20數(shù)據(jù)手冊
上圖為DS18B20的內(nèi)部框圖。內(nèi)部的64位的ROM存儲(chǔ)其獨(dú)一無二的序列號(hào)。暫存存儲(chǔ)器(The scratchpad memory)包含了存儲(chǔ)有數(shù)字溫度結(jié)果的2個(gè)字節(jié)寬度的溫度寄存器。另外,暫存存儲(chǔ)器還提供了一個(gè)字節(jié)的過溫和低溫(TH和TL)溫度報(bào)警寄存器和一個(gè)字節(jié)的配置寄存器。配置寄存器允許用戶自定義溫度轉(zhuǎn)換為9、10、11、12位精度。過溫和低溫(TH和TL)溫度報(bào)警寄存器是非易失性的(EEPROM),所以其可以在設(shè)備斷電的情況下保存。
DS18B20的另外一個(gè)特性就是可以無需外部電源供電。當(dāng)數(shù)據(jù)線DQ為高的時(shí)候由其為設(shè)備供電??偩€拉高的時(shí)候?yàn)閮?nèi)部電容(Spp)充電,當(dāng)總線拉低是由該電容向設(shè)備供電。這種由1-Wire總線為設(shè)備供電的方式稱為“寄生電源”。此外,DS18B20也可以由外部電源通過VDD供電。
DS18B20的核心功能是直接溫度-數(shù)字測量。其溫度轉(zhuǎn)換可由用戶自定義為9、10、11、12位精度分別為0.5℃、0.25℃、0.125℃、0.0625℃分辨率。值得注意的是,上電默認(rèn)為12位轉(zhuǎn)換精度。DS18B20上電后工作在低功耗閑置狀態(tài)下。主設(shè)備必須向DS18B20發(fā)送溫度轉(zhuǎn)換命令[44h]才能開始溫度轉(zhuǎn)換。溫度轉(zhuǎn)換后,溫度轉(zhuǎn)換的值將會(huì)保存在暫存存儲(chǔ)器的溫度寄存器中,并且DS18B20將會(huì)恢復(fù)到閑置狀態(tài)。如果DS18B20是由外部供電,當(dāng)發(fā)送完溫度轉(zhuǎn)換命令[44h]后,主設(shè)備可以執(zhí)行“讀數(shù)據(jù)時(shí)序”,若此時(shí)溫度轉(zhuǎn)換正在進(jìn)行DS18B20將會(huì)響應(yīng)“0”,若溫度轉(zhuǎn)換完成則會(huì)響應(yīng)“1”。如果DS18B20是由“寄生電源”供電,該響應(yīng)的技術(shù)將不能使用,因?yàn)樵谡麄€(gè)溫度轉(zhuǎn)換期間,總線必須強(qiáng)制拉高。??
ROM 中的64 位序列號(hào)是出廠前被光刻好的,它可以看作是該DS18B20 的地址序列號(hào)。64 位光刻ROM 的排列是:開始8 位(28H)是產(chǎn)品類型標(biāo)號(hào),接著的48 位是該DS18B20 自身的序列號(hào),最后8 位是前面56 位的循環(huán)冗余校驗(yàn)碼。光刻ROM 的作用是使每一個(gè)DS18B20 都各不相同,這樣就可以實(shí)現(xiàn)一根總線上掛接多個(gè)DS18B20 的目的。?
DS18B20 溫度傳感器的內(nèi)部存儲(chǔ)器包括一個(gè)高速的暫存器RAM 和一個(gè)非易失性的可電擦除的EEPROM,后者存放高溫度和低溫度觸發(fā)器TH、TL 和配置寄存器。?
配置寄存器是配置不同的位數(shù)來確定溫度和數(shù)字的轉(zhuǎn)化,配置寄存器結(jié)構(gòu)如下:?
低五位一直都是"1",TM 是測試模式位,用于設(shè)置DS18B20 在工作模式還是在測試模式。在DS18B20 出廠時(shí)該位被設(shè)置為0,用戶不需要去改動(dòng)。R1 和R0 用來設(shè)置DS18B20 的精度(分辨率),可設(shè)置為9,10,11 或12 位,對應(yīng)的分辨率溫度是0.5℃,0.25℃,0.125℃和0.0625℃。R0 和R1 配置如下圖:?
在初始狀態(tài)下默認(rèn)的精度是12 位,即R0=1、R1=1。高速暫存存儲(chǔ)器由9 個(gè)字節(jié)組成,其分配如下:?
當(dāng)溫度轉(zhuǎn)換命令(44H)發(fā)布后,經(jīng)轉(zhuǎn)換所得的溫度值以二字節(jié)補(bǔ)碼形式存放在高速暫存存儲(chǔ)器的第0 和第1 個(gè)字節(jié)。存儲(chǔ)的兩個(gè)字節(jié),高字節(jié)的前5 位是符號(hào)位S,單片機(jī)可通過單線接口讀到該數(shù)據(jù),讀取時(shí)低位在前,高位在后,數(shù)據(jù)格式如下:?
如果測得的溫度大于0,這5 位為‘ 0’,只要將測到的數(shù)值乘以0.0625(默認(rèn)精度是12 位)即可得到實(shí)際溫度;如果溫度小于0,這5 位為‘ 1’,測到的數(shù)值需要取反加1 再乘以-0.0625 即可得到實(shí)際溫度。溫度與數(shù)據(jù)對應(yīng)關(guān)系如下:?
比如我們要計(jì)算+85 度,數(shù)據(jù)輸出十六進(jìn)制是0X0550,因?yàn)楦咦止?jié)的高5位為0,表明檢測的溫度是正溫度,0X0550 對應(yīng)的十進(jìn)制為1360,將這個(gè)值乘以12 位精度0.0625,所以可以得到+85 度。?
知道了怎么計(jì)算溫度,接下來我們就來看看如何讀取溫度數(shù)據(jù),由于DS18B20是單總線器件,所有的單總線器件都要求采用嚴(yán)格的信號(hào)時(shí)序,以保證數(shù)據(jù)的完整性。DS18B20 時(shí)序包括如下幾種:初始化時(shí)序、寫(0 和1)時(shí)序、讀(0和1)時(shí)序。DS18B20 發(fā)送所有的命令和數(shù)據(jù)都是字節(jié)的低位在前。這里我們簡單介紹這幾個(gè)信號(hào)的時(shí)序:?
2.1,初始化時(shí)序?
單總線上的所有通信都是以初始化序列開始。主機(jī)輸出低電平,保持低電平時(shí)間至少480us(該時(shí)間的范圍可以從480 到960 微妙),以產(chǎn)生復(fù)位脈沖。接著主機(jī)釋放總線,外部的上拉電阻將單總線拉高,延時(shí)15~60 us,并進(jìn)入接收模式。接著DS18B20 拉低總線60~240 us,以產(chǎn)生低電平應(yīng)答脈沖,若為低電平,還要做延時(shí),其延時(shí)的時(shí)間從外部上拉電阻將單總線拉高算起最少要
480 微妙。初始化時(shí)序圖如下:
注意:主機(jī)釋放總線是指主機(jī)將這個(gè)port置1,因?yàn)閜ort置1后可以被從設(shè)備拉低,但如果port被置0,就不能被從設(shè)備拉高,因此釋放總線是將這個(gè)port置1。
由上述初始化時(shí)序,編寫初始化函數(shù)代碼:
//DS18B20初始化
unsigned char ds18b20_init()
{
DSPORT = 0; //主設(shè)備拉低總線,發(fā)送復(fù)位脈沖,持續(xù)時(shí)間超過480us
void delay500us(void) //誤差 -0.859028845284us
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=227;a>0;a--);
}
DSPORT = 1; //釋放總線
unsigned char i = 0;
while(DSPORT) //檢測DS18B20是否在一定時(shí)間內(nèi)拉低總線,
//根據(jù)時(shí)序圖判斷最長時(shí)間為300us
{
if(i>20)
{
return 0; //超過一定時(shí)間總線未被拉低,說明DS18B20沒有發(fā)送存在脈沖
}
void delay20us(void) //誤差 -0.468396780902us
{
unsigned char a,b;
for(b=3;b>0;b--)
for(a=1;a>0;a--);
}
i++;
}
return 1; //DS18B20在一定時(shí)間內(nèi)響應(yīng)了
}
初始化就是,主機(jī)發(fā)送復(fù)位脈沖,從機(jī)發(fā)送存在脈沖,雙方都收到后,初始化完成。
2.2,讀寫時(shí)序?
下圖為寫時(shí)序圖:
寫時(shí)序有兩種情況:“寫1”時(shí)段和“寫0”時(shí)段。主設(shè)備通過寫1時(shí)段來向DS18B20中寫入邏輯1以及通過寫0時(shí)段來向DS18B20中寫入邏輯0。每個(gè)寫時(shí)段最小必須有60us的持續(xù)時(shí)間且獨(dú)立的寫時(shí)段間至少有1us的恢復(fù)時(shí)間。
為了形成寫1時(shí)段,在將1-Wire總線拉低后,主設(shè)備必須在15us之內(nèi)釋放總線。當(dāng)總線釋放后,5kΩ的上拉電阻將總線拉至高。為了形成寫0時(shí)段,在將1-Wire總線拉低后,在整個(gè)時(shí)段期間主設(shè)備必須一直拉低總線(至少60us)。
在主設(shè)備初始化寫時(shí)段后,DS18B20將會(huì)在15us至60us的時(shí)間窗口內(nèi)對總線進(jìn)行采樣。如果總線在采樣窗口期間是高電平,則邏輯1被寫入DS18B20;若總線是低電平,則邏輯0被寫入DS18B20。
寫時(shí)序?qū)?yīng)代碼:
//DS18B20寫命令函數(shù)
void ds18b20_write(unsigned char data)
{
unsigned char i,j;
for(j = 0;j<8;j++)
{
DSPORT = 0; //拉低總線,開始寫時(shí)序,至少1us
i++;
DSPORT = data & 0x01; //從低字節(jié)開始
void delay65us(void) //持續(xù)至少60us
{
unsigned char a;
for(a=28;a>0;a--);
}
DSPORT = 1; //一個(gè)寫周期后,至少間隔1us給總線恢復(fù)時(shí)間
data >>= 1; //數(shù)據(jù)左移1位
}
}
下圖為讀時(shí)序圖:?
僅在讀時(shí)段期間DS18B20才能向主設(shè)備傳送數(shù)據(jù)。因此,主設(shè)備在執(zhí)行完讀暫存寄存器[BEh]或讀取供電模式[B4h]后,必須及時(shí)地生成讀時(shí)段,這樣DS18B20才能提供所需的數(shù)據(jù)。此外,主設(shè)備可以在執(zhí)行完轉(zhuǎn)換溫度[44h]或拷貝EEPROM[B8h]命令后生成讀時(shí)段,以便獲得在“DS18B20功能命令”章節(jié)中提到的操作信息。
每個(gè)讀時(shí)段最小必須有60us的持續(xù)時(shí)間且獨(dú)立的寫時(shí)段間至少有1us的恢復(fù)時(shí)間。讀時(shí)段通過主設(shè)備將總線拉低超過1us再釋放總線來實(shí)現(xiàn)初始化。當(dāng)主設(shè)備初始化完讀時(shí)段后,DS18B20將會(huì)向總線發(fā)送0或者1。DS18B20通過將總線拉至高來發(fā)送邏輯1,將總線拉至低來發(fā)送邏輯0。當(dāng)發(fā)送完0后,DS18B20將會(huì)釋放總線,則通過上拉電阻該總線將會(huì)恢復(fù)到高電平的閑置狀態(tài)。從DS18B20中輸出的數(shù)據(jù)在初始化讀時(shí)序后僅有15us的有效時(shí)間。因此,主設(shè)備在開始改讀時(shí)段后的15us之內(nèi)必須釋放總線,并且對總線進(jìn)行采樣。
//DS18B20 讀命令函數(shù)
unsigned char DS18B20_read()
{
unsigned char byte,bi;
unsigned char i,j;
for(j=0; j<8; j++)
{
DSPORT = 0; //拉低總線,開始時(shí)序
i++;
DSPORT = 1; //釋放總線
void delay6us(void) //延時(shí)6us等待總線上數(shù)據(jù)穩(wěn)定
{
unsigned char a;
for(a=1;a>0;a--);
}
bi = DSPORT; //要在15us內(nèi)讀取
byte = (byte>>1)|(bi<<7);
void delay45us(void) //延時(shí)至少45us
{
unsigned char a;
for(a=19;a>0;a--);
}
}
return byte;
}
3,DS18B20工作流程
溫度獲取流程:?
DS18B20不會(huì)主動(dòng)進(jìn)行溫度測量, 需要主控主動(dòng)發(fā)起溫度轉(zhuǎn)換命令,這是因?yàn)闇囟绒D(zhuǎn)換本身需要耗電的,所以設(shè)計(jì)為平時(shí)待機(jī),收到溫度轉(zhuǎn)換命令后才會(huì)進(jìn)行溫度AD轉(zhuǎn)換;
主控和DS18B20之間通訊是分周期的,讓DS18B20進(jìn)行溫度轉(zhuǎn)換就是一個(gè)周期。周期包含初始化和N個(gè)命令(每個(gè)周期的開始都有初始化);
初始化主要探測目標(biāo)DS18B20是否存在,若存在將芯片初始化;
命令很重要,DS18B20是一個(gè)典型的“命令-響應(yīng)”型外設(shè);這種外設(shè)的關(guān)鍵是命令集;
ROM操作指令:
DS18B20支持多個(gè)芯片串聯(lián)在一個(gè)總線上,就是所謂的單總線協(xié)議,需要主控區(qū)分總線上多個(gè)DS18B20,因此需要ROM操作指令來完成這個(gè)任務(wù);
ROM操作指令和溫度采集一點(diǎn)關(guān)系都沒有,所以當(dāng)總線上只有一個(gè)DS18B20時(shí),不需要管ROM操作指令;
系統(tǒng)中總線上有多個(gè)DS18B20,需要借助ROM操作指令來區(qū)分多個(gè)DS18B20,可能需要多條ROM操作指令來完成;
只有一個(gè)DS18B20時(shí),使用SKIP ROM (0xCC)忽略;
功能指令:
ROM操作指令是為了在單總線上多個(gè)DS18B20中挑選那個(gè)我們要操作的DS18B20;
功能指令是為了和選定的DS18B20進(jìn)行溫度采樣,常用溫度轉(zhuǎn)換指令和溫度讀取指令;
4,代碼
時(shí)序代碼:?
#include "timesires.h"
#include "uart.h"
void delay500us() //誤差 -0.859028845284us
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=227;a>0;a--);
}
void delay20us(void) //誤差 -0.468396780902us
{
unsigned char a,b;
for(b=3;b>0;b--)
for(a=1;a>0;a--);
}
void delay65us() //持續(xù)至少60us
{
unsigned char a;
for(a=28;a>0;a--);
}
void delay6us(void) //延時(shí)6us等待總線上數(shù)據(jù)穩(wěn)定
{
unsigned char a;
for(a=1;a>0;a--);
}
void delay45us(void) //延時(shí)至少45us
{
unsigned char a;
for(a=19;a>0;a--);
}
void delay1ms(void) //誤差 -0.651041666667us
{
unsigned char a,b;
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
void delay750ms(void) //誤差 -0.000000000171us
{
unsigned char a,b,c;
for(c=37;c>0;c--)
for(b=66;b>0;b--)
for(a=140;a>0;a--);
}
//DS18B20初始化
unsigned char ds18b20_init()
{
unsigned char i = 0;
DSPORT = 0; //主設(shè)備拉低總線,發(fā)送復(fù)位脈沖,持續(xù)時(shí)間超過480us
delay500us();
DSPORT = 1; //釋放總線
while(DSPORT) //檢測DS18B20是否在一定時(shí)間內(nèi)拉低總線,
//根據(jù)時(shí)序圖判斷最長時(shí)間為300us
{
if(i>20)
{
return 0; //超過一定時(shí)間總線未被拉低,說明DS18B20沒有發(fā)送存在脈沖
}
delay20us();
i++;
}
return 1; //DS18B20在一定時(shí)間內(nèi)響應(yīng)了
}
//DS18B20寫命令函數(shù)
void ds18b20_write(unsigned char cmd)
{
unsigned char i = 0,j = 0;
for(j = 0;j<8;j++)
{
DSPORT = 0; //拉低總線,開始寫時(shí)序,至少1us
i++;
DSPORT = cmd & 0x01; //從低字節(jié)開始
delay65us();
DSPORT = 1; //一個(gè)寫周期后,至少間隔1us給總線恢復(fù)時(shí)間
cmd >>= 1; //數(shù)據(jù)左移1位
}
}
//DS18B20 讀命令函數(shù)
unsigned char DS18B20_read()
{
unsigned char byte = 0,bi = 0;
unsigned char i = 0,j = 0;
for(j=0; j<8; j++)
{
DSPORT = 0; //拉低總線,開始時(shí)序
i++;
DSPORT = 1; //釋放總線
delay6us();
bi = DSPORT; //要在15us內(nèi)讀取
byte = (byte>>1)|(bi<<7);
delay45us();
}
return byte;
}
void DS18B20_changeTempCmd()
{
ds18b20_init();
delay1ms(); //如果沒有這個(gè)延時(shí),讀取的溫度會(huì)有問題,用手捏著時(shí)在串口助手中看到的值不變
ds18b20_write(0xcc); //跳過ROM操作指令
ds18b20_write(0x44); //溫度轉(zhuǎn)換命令
delay750ms();
//delay750ms();
}
void DS18B20_readTempCmd()
{
ds18b20_init();
delay1ms();
ds18b20_write(0xcc); //跳過ROM操作指令
ds18b20_write(0xbe); //溫度讀取命令
}
unsigned int DS18B20_Temp_Read()
{
unsigned int temp = 0;
unsigned char tmh = 0, tml = 0;
DS18B20_changeTempCmd();
DS18B20_readTempCmd();
tml = DS18B20_read();
tmh = DS18B20_read();
temp = tmh;
temp <<=8;
temp |= tml;
return temp;
}
串口代碼:
#include "uart.h"
// 串口設(shè)置為: 波特率9600、數(shù)據(jù)位8、停止位1、奇偶校驗(yàn)無
// 使用的晶振是11.0592MHz的,注意12MHz和24MHz的不行
void uart_init(void)
{
// 波特率9600
SCON = 0x50; // 串口工作在模式1(8位串口)、允許接收
PCON = 0x00; // 波特率不加倍
// 通信波特率相關(guān)的設(shè)置
TMOD = 0x20; // 設(shè)置T1為模式2
TH1 = 253;
TL1 = 253; // 8位自動(dòng)重裝,意思就是TH1用完了之后下一個(gè)周期TL1會(huì)
// 自動(dòng)重裝到TH1去
TR1 = 1; // 開啟T1讓它開始工作
// ES = 1;
// EA = 1;
}
// 通過串口發(fā)送1個(gè)字節(jié)出去
void uart_send_byte(unsigned char c)
{
// 第1步,發(fā)送一個(gè)字節(jié)
SBUF = c;
// 第2步,先確認(rèn)串口發(fā)送部分沒有在忙
while (!TI);
// 第3步,軟件復(fù)位TI標(biāo)志位
TI = 0;
}
void uart_send_adVal(unsigned int val)
{
uart_send_byte(val>>8); //AD采樣的數(shù)據(jù)為12位的,首先左移8位串口輸出高4位
uart_send_byte(val); //再輸出低8位
}
main.c
?
#include "timesires.h"
#include "uart.h"
#include <intrins.h>
void delay1s(void) //誤差 -0.000000000227us
{
unsigned char a,b,c;
for(c=13;c>0;c--)
for(b=247;b>0;b--)
for(a=142;a>0;a--);
_nop_(); //if Keil,require use intrins.h
}
void main()
{
unsigned int ret = 0;
uart_init();
while(1)
{
ret = DS18B20_Temp_Read();
uart_send_adVal(ret);
delay1s();
}
}
代碼完成后遇到一個(gè)問題:用手捏著DS18B20發(fā)現(xiàn)在串口調(diào)試助手中看到的值不變化,文章來源:http://www.zghlxwxcb.cn/news/detail-693857.html
原因:DS18B20_changeTempCmd()函數(shù)中,初始化后沒有進(jìn)行時(shí)間延遲,直接發(fā)送ROM操作命令ds18b20_write(0xcc),增加延遲函數(shù)后串口助手中顯示值當(dāng)用手捏著DS18B20會(huì)有變化。文章來源地址http://www.zghlxwxcb.cn/news/detail-693857.html
到了這里,關(guān)于單片機(jī)第二季:溫度傳感器DS18B20的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!