12.1 DS18B20 簡介
DS18B20 數字溫度傳感器提供 9-Bit 到 12-Bit 的攝氏溫度測量精度和一個用戶可編程的非易失性且具有過溫和低溫觸發報警的報警功能。DS18B20 采用的 1-Wire 通信即僅采用一個數據線(以及地)與微控制器進行通信。該傳感器的溫度檢測范圍為-55℃ 至 +125℃,并且在溫度范圍超過-10℃ 至 85℃ 之外時還具有 +-0.5℃ 的精度。此外,DS18B20 可以直接由數據線供電而不需要外部電源供電。
每片 DS18B20 都有一個獨一無二的 64 位序列號,所以一個 1-Wire 總線上可連接多個 DS18B20 設備。因此,在一個分布式的大環境里用一個微控制器控制多個 DS18B20 是非常簡單的。這些特征使得其在 HVAC 環境控制,在建筑、設備及機械的溫度監控系統,以及溫度過程控制系統中有著很大的優勢。DS18B20 數字溫度傳感器的 3 種封裝圖如下圖所示:
獨特的 1-Wire 總線接口僅需要一個管腳來通信,應用于溫度控制系統,工業系統,民用產品,溫度傳感器,或者任何溫度檢測系統中。RY-51 開發板根據數據手冊要求,溫度采集模塊電路設計如下所示:
其中,Temp 與單片機的 P2.2 引腳相連接。
DS18B20 是一款直接式數字溫度傳感器,溫度數據格式可設置為 9、10、11、12 位模式,出廠初始值為 12 為格式。對應的最小溫度精度可達到 0.5℃、0.25℃、0.125℃ 或者 0.0625℃。當向 DS18B20 寫入溫度轉換字 44H 之后,傳感器內部會完成溫度數據的采集,并將溫度值以一個 16 位的有符號數存儲在 2 個 8 位的存儲單元中,如下圖所示。
如上圖所示,由兩個字節的存儲單元存儲了溫度數據,高 5 位的 s 表示符號,當 s=0 時,表示溫度為正。當 s=1 時,表示溫度為負值, 并以補碼形式存儲溫度值,溫度值與存儲值轉換關系如圖 12-3 所示。當向傳感器寫入讀溫度指令 BEH 后,傳感器會將上面兩個 8 位存儲單元的內容從最低位開始依次輸出。上電后,溫度存儲單元中存儲的初始溫度為 85℃。
12.2 DS18B20 操作指令
我們使用數字溫度傳感器的最終目的是通過它采集到溫度值,單片機獲得 DS18B20 溫度值的過程一般遵循以下協議:傳感器初始化——>ROM 操作命令——> 存儲器操作命令——> 處理數據。下面逐一進行介紹。
12.2.1 傳感器初始化
單總線上的所有處理均從初始化序列開始。初始化序列由總線主機發出一復位脈沖,當傳感器收到復位脈沖后,會返回存在脈沖,表示總線上存在傳感器并準備好可以接收由主機發來的操作指令。初始化指令如下圖所示,下面我們講解如何來理解這個圖的時序,圖中包括四種線型,第一種為粗的實線表示總線由主機拉低,第二種為粗的虛線表示總線由 DS18B20 拉低,第三種為粗的實線虛線交叉表示主機和 DS18B20 同時拉低總線,第四種為細實線由阻抗拉高,即釋放總線。
下面我們來分析一下初始化的時序步驟:
- 由主機也就是單片機拉低總線引腳,持續時間為 480us 到 960us;
- 主機釋放總線,即單片機拉高總線引腳,等待 15us 到 60us;
- DS18B20 拉低總線 60us 到 240us,即返回存在脈沖,表示傳感器存在總線上并可接受操作指令了;
- DS18B20 主動釋放總線,總線引腳自動被電阻拉高;
DS18B20 復位脈沖時序如下圖:
DS18B20 初始化函數如下所示:
#include< reg52.h >
#include < intrins.h >
#define uchar unsigned char
#define uint unsigned int
sbit DS18B20 = P2^2; //DS18B20傳感器I/O口定義
void DelayT_10us(uchar count)
{
while(count--)
{ //模擬10us延時
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
}
void Init_DS18B20(void)
{
//單片機拉低總線并延時600us
DS18B20 = 0;
DelayT_10us(50);
//單片機釋放總線并延時60us
DS18B20 = 1;
DelayT_10us(6);
//當DS18B20返回低電平時,表示總線上存在傳感器
while(!DS18B20);
DelayT_10us(50);
}
如上代碼所示,Init_DS18B20()為初始化函數,DelayT_10us()為 10us 延時函數。DS18B20 為自定義的傳感器 I/O 口名稱。首先由單片機將 I/O 口拉低 500us,滿足 480us 到 960us 持續時間要求。然后由單片機將 I/O 口拉高,即釋放總線,持續時間為 60us,而時序要求里面表示在 15us 到 60us 之內傳感器會給出存在信號,為了保證一定能收到存在信號,我們這里延時最大的 60us。最后一直檢測傳感器是否給出了低電平的存在信號,當檢測到存在信號后繼續延時 500us。
12.2.2 DS18B20 單 bit 數據讀寫操作
對 DS18B20 溫度傳感器而言,需要通過對它寫字節命令或讀字節命令來實現溫度值的傳輸。而作為單總線傳感器,字節命令都是通過連續的 8 次單 bit 命令來實現的,這節的主要內容為,單 bit 數據讀寫操作時序講解。主機向 DS18B20 寫“0”或“1”時序如下:
如上所示,圖中左半邊為寫“0”時序,右邊為寫“1”時序。如左邊所示,首先將總線拉低持續時間最低 60us 最高 120us。傳感器 DS18B20 最快在第 15us 采集總線上的低電平,最典型的時間為第 30us,最慢也在第 60us 能采集完畢 ,也就是說只要我們保持低電平至少 60us,就能將“0”寫入到傳感器中。與寫“0”類似,當要向傳感器寫入“1”的時候,首先由主機將總線拉低,持續時間大于 1us,隨后立馬將總線拉高,同樣傳感器最快在第 15us 采集總線上的高電平,最典型的時間為第 30us,最慢也在第 60us 能采集完畢。因此我們將寫“0”和寫“1”整合到一個函數中。主機向 DS18B20 傳感器寫數據函數:
void WrByte_18B20(uchar dat)
{
uchar j;
bit flag;
for(j=1;j<=8;j++)
{ //從低到高一次將1Byte數據寫入DS18B20
flag = dat&0x01;
dat=dat >>1;
DS18B20 = 0;//拉低總線并延時2us
_nop_();
_nop_();
DS18B20 = flag;//將要寫的位放到總線
DelayT_10us(6);//延時60us
DS18B20 = 1;//拉高釋放總線
}
}
單片機讀 DS18B20 傳感器時序如下圖所示:
如上圖所示,當主機需要讀取傳感器的“0”時,首先將主機拉低,并在 15us 之內讀取總線值,隨后釋放總線。當主機需要讀取“1”時,首先將主機拉低,并延時超過 1us,并在 15us 之內讀取總線值,隨后釋放總線。因此我們將讀“0”和寫“1”整合到一個函數中,如下主機讀 DS18B20 函數:
uchar RdByte_18B20(void)
{
uchar dat,flag,j;
for(j=1;j<=8;j++)
{
DS18B20 = 0;//拉低總線并延時2us
_nop_();
_nop_();
DS18B20 = 1;//拉高釋放總線并延時2us
_nop_();
_nop_();
flag = DS18B20;//采集
DelayT_10us(6);//延時60us
//讀出的值最低位在前面
dat=(dat >>1)|(flag< 7);
}
return dat;
}
12.2.3 ROM 操作命令
下面介紹兩個采集溫度用到的寫入不同的字節實現的功能,其他請參考 DS18B20 數據手冊。
a) 寫入字節[CCh]
功能:Skip ROM( 跳過 ROM ),在單點總線系統中,此命令通過允許總線。不給主機提供 64 位 ROM 編碼而訪問存儲器操作來節省時間。如果在總線上存在多于一個的從屬器件而且在 Skip ROM 命令之后發出讀命令,那么由于多個從片同時發送數據,會在總線上發生數據沖突(漏極開路下拉會產生線與的效果)。
b) 寫入字節[44h]
功能:Convert T(溫度變換),這條命令啟動一次溫度轉換而無需其他數據。溫度轉換命令被執行,而后 DS18B20 保持等待狀態。如果總線控制器在這條命令之后跟著發出讀時間隙,而 DS18B20 又忙于做時間轉換的話,DS18B20 將在總線上輸出“0”,若溫度轉換完成,則輸出“1”。如果使用寄生電源,總線控制器必須在發出這條命令后立即起動強上拉,并保持 500ms。
12.2.4 存儲器操作命令
單片機通過向 DS18B20 寫入相應的字節命令完成對 DS18B20 存儲器中數據的讀寫功能。本系統用到的功能為讀取存儲器中的溫度值,寫入字節[BEh]。
功能為:Read Scratchpad(讀暫存存儲器),這個命令讀取暫存器的內容。讀取將從字節 0 開始,一直進行下去,直到第 9(字節 8,CRC)字節讀完。如果不想讀完所有字節,控制器可以在任何時間發出復位命令來中止讀取。讀取的前兩個字節為存儲了溫度值。
12.2.5 處理數據
溫度存儲于上述的前兩個字節中,通過讀取前兩個字節便可獲得溫度,兩個字節內容與實際溫度值對應所示,按照下關系如圖 12-3 所示,按圖進行相應的轉換即可,另外在上電時溫度的初始值為 85℃。
根據前面介紹,溫度采集的步驟總結如下:
a) 溫度傳感器初始化;
b) 寫入字節[CCh],跳過 ROM;
c) 寫入字節[44h],啟動一次溫度轉換;
d) 溫度傳感器初始化;
e) 寫入字節[CCh],跳過 ROM;
f) 寫入字節[BEh],發送讀溫度命令;
g) 讀取返回的前兩個字節,并轉化為溫度值。
溫度采集函數代碼如下:
uint GetT_18B20(void)
{
uchar Temp_L,Temp_H;
uint Temp;
Init_DS18B20(); //初始化
WrByte_18B20(0xCC);//跳過ROM
WrByte_18B20(0x44);//啟動溫度轉換
Init_DS18B20(); //初始化
WrByte_18B20(0xCC);//跳過ROM
WrByte_18B20(0xBE);//發送讀溫度命令
//讀取兩個字節的溫度值
Temp_L = RdByte_18B20();
Temp_H = RdByte_18B20();
Temp = ((uint)Temp_H< 8) + Temp_L;//將溫度組合成16變量
return Temp;
}
為了方便后續使用,我們將與 DS18B20 有關的函數都放到“Drive_DS18B20.h”、 “Drive_DS18B20.c”文件中。
“Drive_DS18B20.h”文件代碼如下所示:
#ifndef __18b20_H__
#define __18b20_H__
extern unsigned int GetT_18B20(void);
#endif
“Drive_DS18B20.h”文件代碼如下所示:
#include< reg52.h >
#include < intrins.h >
#define uchar unsigned char
#define uint unsigned int
sbit DS18B20 = P2^2; //DS18B20傳感器I/O口定義
void DelayT_10us(uchar count)
{
while(count--)
{ //模擬10us延時
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
}
void Init_DS18B20(void)
{
//單片機拉低總線并延時600us
DS18B20 = 0;
DelayT_10us(50);
//單片機釋放總線并延時60us
DS18B20 = 1;
DelayT_10us(6);
//當DS18B20返回低電平時,表示總線上存在傳感器
while(!DS18B20);
DelayT_10us(50);
}
void WrByte_18B20(uchar dat)
{
uchar j;
bit flag;
for(j=1;j<=8;j++)
{ //從低到高一次將1Byte數據寫入DS18B20
flag = dat&0x01;
dat=dat >>1;
DS18B20 = 0;//拉低總線并延時2us
_nop_();
_nop_();
DS18B20 = flag;//將要寫的位放到總線
DelayT_10us(6);//延時60us
DS18B20 = 1;//拉高釋放總線
}
}
uchar RdByte_18B20(void)
{
uchar dat,flag,j;
for(j=1;j<=8;j++)
{
DS18B20 = 0;//拉低總線并延時2us
_nop_();
_nop_();
DS18B20 = 1;//拉高釋放總線并延時2us
_nop_();
_nop_();
flag = DS18B20;//采集
DelayT_10us(6);//延時60us
//讀出的值最低位在前面
dat=(dat >>1)|(flag< 7);
}
return dat;
}
uint GetT_18B20(void)
{
uchar Temp_L,Temp_H;
uint Temp;
Init_DS18B20(); //初始化
WrByte_18B20(0xCC);//跳過ROM
WrByte_18B20(0x44);//啟動溫度轉換
Init_DS18B20(); //初始化
WrByte_18B20(0xCC);//跳過ROM
WrByte_18B20(0xBE);//發送讀溫度命令
//讀取兩個字節的溫度值
Temp_L = RdByte_18B20();
Temp_H = RdByte_18B20();
Temp = ((uint)Temp_H< 8) + Temp_L;//將溫度組合成16變量
return Temp;
}
將上述兩個文件添加到工程中,主程序文件中調用函數便可實現溫度采集了。
12.3 DS18B20 的應用
下面我們講解 DS18B20 的應用,要實現的功能為:單片機每秒采集一次溫度值,并將溫度值顯示到液晶顯示模塊上。用定時器中斷來時實現 1s 的定時,建立工程,將 1602、18B20 的文件添加到工程中,在主程序中調用相關大函數來實現顯示和溫度的采集,主程序代碼如下所示:
#include< reg52.h >
#include"Drive_DS18B20.h"
#include"Drive_1602.h"
#define uchar unsigned char
#define uint unsigned int
uint Temp;
uchar str[10]=0;
#define FOSC 11059200 //單片機晶振頻率
#define T_1ms (65536 - FOSC/12/1000) //定時器初始值計算
uint flag = 0;
uint T_count = 0;
uint Sec = 0;
sbit DU = P2^7;//數碼管段選、位選引腳定義
sbit WE = P2^6;
void main(void)
{
Init_1602();//1602初始化
P0 = 0xff;//關閉所有數碼管
WE = 1;
WE = 0;
TMOD = 0x01; //定時器工作模式配置
TL0 = T_1ms; //裝載初始值
TH0 = T_1ms >>8;
TR0 = 1; //啟動定時器
ET0 = 1; //允許定時器中斷
EA = 1; //開總中斷
Disp_1602_str(1,3,"RongYi RY-51");//第1行第3列開始顯示"RongYi RY-51"
while(1)
{
if(T_count >=1000)//1s進行一次溫度的采集以及顯示
{
EA=0;//關閉中斷,防止定時器中斷影響溫度傳感器的讀寫
T_count =0;
Sec++;
Temp = GetT_18B20(); //采集溫度
str[0] = (Temp >>4)/10 + '0';//左移4位獲得溫度整數部分
str[1] = (Temp >>4)%10 + '0';
str[2] = '.';
if((Temp >>3)%10)
str[3] = '5';
else
str[3] = '0';
str[4] = '?';
Disp_1602_str(2,3,str);//第2行第3列開始顯示溫度值
EA = 1;//顯示完成后,開總中斷
}
}
}
void timer0() interrupt 1
{
TL0 = T_1ms;//重裝初始值
TH0 = T_1ms >>8;
T_count++;
}
12.4 本章小結
本章詳細介紹了DS18B20的工作原理,通信時序,以及函數的編寫,后面使用時只需調用函數即可了,無需重復造輪子咯。
-
傳感器
+關注
關注
2550文章
51035瀏覽量
753084 -
單片機
+關注
關注
6035文章
44554瀏覽量
634667 -
DS18B20
+關注
關注
10文章
779瀏覽量
80825 -
數字溫度傳感器
+關注
關注
0文章
188瀏覽量
15448
發布評論請先 登錄
相關推薦
評論