DS18B20溫度傳感器時(shí)序圖解析(STM32)
網(wǎng)上DS18B20的驅(qū)動(dòng)實(shí)現(xiàn)代碼一大堆,簡簡單單的就能夠移植成功,獲得溫度值,但是為什么代碼這么寫?為什么要延時(shí)那么長的時(shí)間?不對照手冊仔細(xì)分析時(shí)序圖,還真是不明白為什么。
下面我們就來詳細(xì)剖析一下DS18B20的驅(qū)動(dòng)函數(shù)的實(shí)現(xiàn)。
DS18B20 簡介
DS18B20數(shù)字溫度傳感器是美國DALLAS公司生產(chǎn)的單總線數(shù)字溫度傳感器。其測溫范圍為-55℃~+125℃(-67℉~+257℉),64位只讀存儲(chǔ)器的片序列號(hào)。從而允許多只DS18B20同時(shí)并聯(lián)在一根單線總線上;
華氏度和攝氏度換算關(guān)系:
(華氏度-32)×5÷9=攝氏度
DS18B20可以用一個(gè)微控制器的GPIO引腳去控制。器件內(nèi)部高速暫存器區(qū)含有兩個(gè)字節(jié)的溫度寄存器,用來存儲(chǔ)溫度傳感器輸出的數(shù)據(jù)。
此外,高速暫存器區(qū)還有上下溫度報(bào)警寄存器(TH和TL),和一個(gè)字節(jié)的配置寄存器。
配置寄存器允許用戶將溫度的精度設(shè)置為9~12位對應(yīng)的分辨率為0.5℃、0.25℃、0.125℃、0.0625℃。上電默認(rèn)為12位轉(zhuǎn)換精度。
-
DS18B20存儲(chǔ)器圖
實(shí)際使用中,當(dāng)只是為了測溫,只需用到字節(jié)1,字節(jié)2和字節(jié)5。應(yīng)用環(huán)境中如果沒有強(qiáng)干擾,不是十分嚴(yán)格的話,不做校驗(yàn)也可以。
其中,暫存寄存器中的字節(jié)5包含著配置寄存器,配置寄存器內(nèi)容如下圖所示:
用戶通過改變上表中R0和R1的值來配置DS18B20的分辨率。上電默認(rèn)為R0=1及R1=1(12位分辨率)。
-
溫度/數(shù)據(jù)對應(yīng)表:
溫度轉(zhuǎn)換后,溫度轉(zhuǎn)換的值將會(huì)保存在暫存存儲(chǔ)器的溫度寄存器中,并且DS18B20將會(huì)恢復(fù)到閑置狀態(tài)。
TH,TL和配置寄存器是EEPROM,存儲(chǔ)的數(shù)據(jù)在器件掉電時(shí)不會(huì)消失。
DS18B20的另一個(gè)功能是可以在沒有外部電源供電的情況下工作。當(dāng)總線處于高電平狀態(tài),DQ與上拉電阻連接通過單總線對器件供電。
同時(shí)處于高電平狀態(tài)的總線信號(hào)對內(nèi)部電容(Cpp)充電,在總線處于低電平狀態(tài)時(shí),該電容提供能量給器件。
這種提供能量的形式被稱為“寄生電源”;
寄生電源模式時(shí),VDD引腳必須接地。
-
“寄生電源”供電方式
-
外部電源供電方式
原理圖
外觀及封裝
-
TO-92封裝
-
防水型不銹鋼封裝
采用導(dǎo)熱性高的密封膠灌封,保證了溫度傳感器的高靈敏性,極小的溫度延遲。
芯片每個(gè)引腳均用熱縮管隔開,防止短路,內(nèi)部封膠,防水防潮。
引腳說明
紅線:VCC
綠線:GND
黃線:DQ,傳感器數(shù)據(jù)總線
驅(qū)動(dòng)實(shí)現(xiàn)
INITIALIZATION TIMING
在初始化序列期間,總線控制器拉低總線并保持至少480us以發(fā)送一個(gè)復(fù)位脈沖,返回釋放總線,進(jìn)入接收狀態(tài)(等待DS18B20應(yīng)答)。
總線釋放后,單總線由上拉電阻拉到高電平。
當(dāng)DS18B20探測到I/O引腳上的上升沿后,等待15-60us,然后其以拉低總線60-240us的方式發(fā)出存在脈沖。至此,初始化時(shí)序完畢。
所以,初始化成功的標(biāo)志就是能否讀到DS18B20這個(gè)先低后高的脈沖時(shí)序,并且拉低的時(shí)間要滿足60-240us。
復(fù)位DS18B20的代碼如下:
//復(fù)位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //總線設(shè)置為輸出模式
DS18B20_DQ_OUT=0; //主機(jī)拉低總線
delay_us(750);
DS18B20_DQ_OUT=1; //釋放總線,產(chǎn)生的上升沿能被DS18B20檢測到
delay_us(15); //延時(shí)15us之后,等待DS18B20發(fā)送的低電平信號(hào)到達(dá)。
}
//等待DS18B20的回應(yīng)
//返回1:未檢測到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN(); //總線設(shè)置為輸入模式
while (DS18B20_DQ_IN&&retry<200) //等待拉低總線60-240us的低電平
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)
return 1;
return 0;
}
READ/WRITE TIME SLOT TIMING DIAGRAM
DS18B20的寫時(shí)序(見下圖):
主機(jī)在寫時(shí)隙向DS18B20寫入數(shù)據(jù),其中分為寫”0”時(shí)隙,和寫”1”時(shí)隙。總線主機(jī)使用寫“1”時(shí)間隙向DS18B20寫入邏輯1,使用寫“0”時(shí)間隙向DS18B20寫入邏輯0。
所有的寫時(shí)隙必須有最少60us的持續(xù)時(shí)間,相鄰兩個(gè)寫時(shí)隙必須要有最少1us的恢復(fù)時(shí)間。兩種寫時(shí)隙都通過主機(jī)拉低總線產(chǎn)生(見下圖)。
為了產(chǎn)生寫1時(shí)隙,在拉低總線后主機(jī)必須在15μs內(nèi)釋放總線。在總線被釋放后,由于上拉電阻將總線恢復(fù)為高電平。
為了產(chǎn)生寫”0”時(shí)隙,在拉低總線后主機(jī)必須繼續(xù)拉低總線以滿足時(shí)隙持續(xù)時(shí)間的要求(至少60μs)。
在主機(jī)產(chǎn)生寫時(shí)隙后,DS18B20會(huì)在其后的15~60us的一個(gè)時(shí)間段內(nèi)采樣單總線(DQ)。在采樣的時(shí)間窗口內(nèi),如果總線為高電平,主機(jī)會(huì)向DS18B20寫入1;如果總線為低電平,主機(jī)會(huì)向DS18B20寫入0。
綜上所述,所有的寫時(shí)隙必須至少有60us的持續(xù)時(shí)間。相鄰兩個(gè)寫時(shí)隙必須要有最少1us的恢復(fù)時(shí)間。所有的寫時(shí)隙(寫0和寫1)都由拉低總線產(chǎn)生。
//寫一個(gè)字節(jié)到DS18B20
//dat:要寫入的字節(jié)
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT(); //設(shè)置DQ為輸出模式
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DS18B20_DQ_OUT=0;// Write 1
delay_us(2);
DS18B20_DQ_OUT=1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT=0;// Write 0
delay_us(60); // 等待DS18B20來采集信號(hào)
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
DS18B20的讀時(shí)序(見下圖):
主機(jī)發(fā)起讀時(shí)序時(shí),DS18B20僅被用來傳輸數(shù)據(jù)給控制器。因此,總線控制器在發(fā)出讀指令后必須立刻開始讀時(shí)序。
所有讀時(shí)序必須最少60us,包括兩個(gè)讀周期間至少1us的恢復(fù)時(shí)間。
當(dāng)總線控制器把數(shù)據(jù)線從高電平拉到低電平時(shí),讀時(shí)序開始,數(shù)據(jù)線必須至少保持1us,然后總線被釋放。
DS18B20 通過拉高或拉低總線來傳輸”1”或”0”。
當(dāng)傳輸邏輯”0”結(jié)束后,總線將被釋放,通過上拉電阻回到上升沿狀態(tài)。
從DS18B20輸出的數(shù)據(jù)在讀時(shí)序的下降沿出現(xiàn)后15us 內(nèi)有效。因此,總線控制器在讀時(shí)序開始后必須把I/O口設(shè)置為輸入模式,以讀取I/O口狀態(tài)。
陰影部分為DS18B20釋放總線的時(shí)刻,總線為空閑狀態(tài)。
//從DS18B20讀取一個(gè)位
//返回值:1/0
u8 DS18B20_Read_Bit(void) // read one bit
{
u8 data;
DS18B20_IO_OUT(); //設(shè)置總線為輸出模式
DS18B20_DQ_OUT=0;
delay_us(2); //拉低最少1us
DS18B20_DQ_OUT=1; //拉低再升高,產(chǎn)生讀時(shí)序
DS18B20_IO_IN(); //設(shè)置總線為輸入模式
delay_us(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
delay_us(50);
return data;
}
//從DS18B20讀取一個(gè)字節(jié)
//返回值:讀到的數(shù)據(jù)
u8 DS18B20_Read_Byte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
-
DS18B20的功能命令
-
獲取溫度值
要獲取溫度值,我們需要發(fā)送上面功能命令0x44,然后發(fā)送讀取暫存寄存器命令0xBE,然后我們只需要獲得暫存器中的9個(gè)字節(jié)的前兩個(gè)字節(jié)即可。
要獲得DS18B20的溫度值,需要按照下表中的順序依次發(fā)送功能命令。
獲取溫度的具體代碼實(shí)現(xiàn)如下:
//開始溫度轉(zhuǎn)換
void DS18B20_Start(void)// ds18b20 start convert
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
//從ds18b20得到溫度值
//精度:0.1C
//返回值:溫度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds18b20 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//溫度為負(fù)
}else temp=1;//溫度為正
tem=TH; //獲得高八位
tem<<=8;
tem+=TL;//獲得底八位
tem=(float)tem*0.625;//轉(zhuǎn)換
if(temp)return tem; //返回溫度值
else return -tem;
}
跳過ROM序列號(hào)檢測命令(0xCCH),對于單片DS18B20在線的系統(tǒng),該命令允許主機(jī)跳過ROM序列號(hào)檢測而直接對寄存器操作,從而節(jié)省時(shí)間,對于多片DS18B20在線系統(tǒng),該命令將引起數(shù)據(jù)沖突。
如果主機(jī)只是對一個(gè)DS18B20進(jìn)行操作,進(jìn)而不需要讀取ROM編碼了,只要發(fā)送跳過ROM(0xCCH)命令,就可以進(jìn)行溫度轉(zhuǎn)換和讀取操作了。
-
獲取DS18B20內(nèi)部ID序列號(hào)
因?yàn)樵蹅兛偩€上只有一個(gè)DS18B20設(shè)備,所以直接發(fā)送0x33指令即可READ ROM。
DS18B20中有一個(gè)64位光刻ROM,按說明書說法,開始(最低)8位是產(chǎn)品類型標(biāo)號(hào),對于DS18B20來說都是(28H),接著的48位是該DS18B20自身的序列號(hào),最后8位是前面56位的循環(huán)冗余校驗(yàn)碼(CRC=X8+X5+X4+1)。
光刻ROM的作用是使每一個(gè)DS18B20都各不相同,這樣就可以實(shí)現(xiàn)一根總線上掛接多個(gè)DS18B20的目的。
讀取ROM方法:先復(fù)位DS18B20,成功后執(zhí)行讀取ROM命令(33H),然后將這64位以8個(gè)字節(jié)的方式存入數(shù)組。
獲取DS18B20內(nèi)部ID序列號(hào)的具體代碼實(shí)現(xiàn)如下:
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0x33);
for(i = 0; i < 8;i++)
{
arrDS18B20ID[i] = DS18B20_Read_Byte();
}
sprintf((char *)dtbuf,"DS18B20 ID is %02X %02X %02X %02X %02X %02X %02X %02X\r\n", arrDS18B20ID[0], arrDS18B20ID[1], arrDS18B20ID[2], arrDS18B20ID[3], arrDS18B20ID[4], arrDS18B20ID[5], arrDS18B20ID[6], arrDS18B20ID[7]);
printf((u8 *)dtbuf,strlen((char *)dtbuf));
我手里的兩個(gè)DS18B20得到的結(jié)果如下所示:
由上可以看出,首字節(jié)都是0x28,即產(chǎn)品類型都是一樣的。
至此,六月份的智能風(fēng)扇中的溫度傳感器模塊的已經(jīng)實(shí)現(xiàn)了哈。
推薦閱讀:
STM32單片機(jī)最小系統(tǒng)詳解
STM32F103 串口的使用方法
STM32中精確延時(shí)函數(shù)的實(shí)現(xiàn)
DHT11及DHT21溫濕度傳感器時(shí)序圖解析(STM32)
基于STM32固件庫的MDK5工程建立
修改Keil工程名稱并添加其他模塊文件
基于單片機(jī)的智能風(fēng)扇的功能點(diǎn)及所需要的功能模塊【2020.06每月活動(dòng)】
資料下載
微信公眾號(hào)后臺(tái)回復(fù)“溫度傳感器”,可以下載工程源碼及DS18B20的手冊。
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請聯(lián)系我們,謝謝!