DS18B20溫度傳感器的特性、原理、驅動(華大半導體HC32L136、ESP32驅動)

新冠疫情、元器件漲價,同一家店鋪之前買的DS18B20模組體積有大拇指這么大,最近買體積只有大拇指指甲蓋這么大,以前無論買多少都有6元運費,今年哪怕買一塊都是包郵,今年生意難做了,祈禱國泰民安、國強民富!

言歸正傳,說大事分割線~

1、模組簡介

DS18B20的數字溫度傳感器,可以用來對環境溫度進行定量的檢測。DS18B20數字溫度傳感器是美國DALLAS公司生產的一總線數字溫度傳感器。其測溫范圍 -55℃~+125℃,固有測溫分辨率0.5℃,支持多點組網功能,多個DS18B20可以并聯在唯一的三線上,實現多點測溫,測量結果以9~12位數字量方式串行傳送。模組結構如下圖所示:

模組特性如下所示:?

獨特的1-Wire總線接口僅需要一個管腳來通信。

每個設備的內部ROM上都燒寫了一個獨一無二的64位序列號。

多路采集能力使得分布式溫度采集應用更加簡單。

無需外圍元件。

能夠采用數據線供電,供電范圍為3.0V至5.5V。

溫度可測量范圍為:-55℃至+125℃(-67℉至+257℉)。

溫度范圍超過-10℃至85℃之外時測溫分辨率0.5℃。

內部溫度采集精度可以由用戶自定義為9-Bits至12-Bits。

溫度轉換時間在轉換精度為12-Bits時達到最大值750ms。

用戶自定義非易失性的的溫度報警設置。

定義了溫度報警搜索命令和當溫度超過用戶自定義的設定值時。

可選擇的8-Pin SO (150 mils), 8-Pin μSOP,及3-Pin TO-92封裝。

與DS1822程序兼容。

應用于溫度控制系統,工業系統,民用產品,溫度傳感器,或者任何溫度檢測系統中。

DS18B20管腳定義如下圖所示:

DS18B20采用Maxim公司專有的1-Wire總線協議,該總線協議僅需要一個控制信號進行通信。該控制信號線需要一個喚醒的上拉電阻以防止連接在該總線上的口是3態或者高阻態(DQ信號線是在DS18B20上)。在該總線系統中,微控制器(主設備)通過每個設備的64為序列號來識別該總線上的設備。因為每個設備都有一個獨一無二的序列號,掛在一個總線上的設備理論上是可以無限個的。在下面的“1-Wire總線系統”章節中包含有1-Wire總線協議詳細的命令和時序關系。

DS18B20的另外一個特性就是可以無需外部電源供電。當數據線DQ為高的時候由其為設備供電。總線拉高的時候為內部電容(Spp)充電,當總線拉低是由該電容向設備供電。這種由1-Wire總線為設備供電的方式稱為“寄生電源”。此外,DS18B20也可以由外部電源通過VDD供電。DS18B20內部框圖如下所示:

DS18B20的核心功能是直接溫度—數字測量,上電后工作在低功耗閑置狀態下,其溫度轉換可由用戶自定義為9、10、11、12位精度分別為0.5℃、0.25℃、0.125℃、0.0625℃分辨率,上電默認為12位轉換精度。溫度數據以一個16位標志擴展二進制補碼數的形式存儲在溫度寄存器中,符號標志位(S)溫度的正負極性:正數則S=0,負數則S=1。如果DS18B20被定義為12位的轉換精度,溫度寄存器中的所有位都將包含有效數據。若為11位轉換精度,則BIT 0為未定義的。若為10位轉換精度,則BIT 1和BIT 0為未定義的。 若為9位轉換精度,則BIT 2、BIT 1和BIT 0為未定義的。下表為在12位轉換精度下溫度輸出數據與相對應溫度之間的關系表。

DS18B20的溫度輸出數據時在攝氏度下校準的,若是在華氏度下應用的話,可以用查表法或者常規的數據換算,溫度/數據對應關系如下表所示:

DS18B20可以通過VDD引腳由外部供電,或者可以由“寄生電源”供電,這使得DS18B20可以不采用當地的外部電源供電而實現其功能。

外部電源供電方式具有不需要上拉的MOSFET、該1-Wire總線在溫度轉換期間可執行其他動作的優點,外部電源供電方式如下圖所示:

“寄生電源”供電方式在遠程溫度檢測或空間比較有限制的地方有很大的應用,其由DQ口拉高時向其供電。總線拉高的時候為內部電容(Cpp)充電,當總線拉低是由該電容向設備供電。當DS18B20為“寄生電源”供電模式時,該VDD引腳必須連接到地。“寄生電源”供電方式在溫度超過+100℃時不推薦使用,因為在超過該溫度下時將會有很大的漏電流導致不能進行正常的通信。實際應用中,在類似的溫度狀態下強烈推薦該DS18B20由外部電源供電,“寄生電源”供電方式如下圖所示。

DS18B20存儲器包含了SRAM暫存寄存器、過溫和低溫(TH和TL)溫度報警寄存器、配置寄存器的非易失性EEPROM。當溫度報警功能沒有用到的時候,過溫和低溫(TH和TL)溫度報警寄存器可以當做通用功能的存儲單元。

SRAM暫存寄存器中的Byte 0和Byte 1分別作為溫度寄存器的低字節和高字節,同時這兩個字節是只讀的;Byte 2和Byte 3作為過溫和低溫(TH和TL)溫度報警寄存器;Byte 4保存著配置寄存器的數據;Byte 5、6、7作為內部使用的字節而保留使用,不可被寫入;Byte 8存儲著該暫存寄存器中Byte 0至Byte 7的循環冗余校驗(CRC)值,并且只讀不可寫入,存儲器組織結構如下圖所示:

2、驅動原理

?DS18B20的驅動過程主要依托于1-Wire總線系統,該總線系統可以一個總線主設備控制一個或多個從設備,我們的MCU作為主設備,DS18B20永遠為從設備,1-Wire總線系統上所有的命令或者數據的發送送都是遵循低位先發送的原則。

1-Wire總線系統僅有一根數據線,且需要一個5kΩ左右的外部上拉電阻,因此閑置情況下數據線是高電平。每個設備(主設備或從設備)通過一個漏極開路或3態門引腳連接至數據線上。這就允許每個設備“釋放”數據線,當設備沒有傳遞數據的時其他設備可以有效地使用數據線。DS18B20的1-Wire總線接口(DQ引腳)是其內部電路組成的漏極開路,硬件配置如下圖所示:

實現DS18B20的驅動主要有三步:

第一步:初始化DS18B20;

第二步:ROM命令(緊跟任何數據交換請求);

第三步:DS18B20功能命令(緊跟任何數據交換請求);

每次對DS18B20的訪問都必須遵循這樣的步驟來進行,如果這些步驟中的任何一個丟失或者沒有執行,則DS18B20將不會響應。這只說明驅動的思路,具體參見DS18B20數據手冊。

3、HC32L136驅動

第1步:配置GPIO,這里配置HC32L136的PB03引腳,PB03引腳連接DS18B20數據線,所以IO口的方向(輸入、輸出)在讀、寫過程中是不斷變化的,代碼如下所示:

uint8_t DS18B20_Init(void)

{

? stc_gpio_cfg_t stcGpioCfg;

? DDL_ZERO_STRUCT(stcGpioCfg);

? Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);? //開啟GPIO時鐘門控

? stcGpioCfg.enDir = GpioDirOut;? ? ? ? ? ? ? ? ? ? ? ? ? ///< 端口方向配置->輸出? ?

? stcGpioCfg.enOD = GpioOdDisable;? ? ? ? ? ? ? ? ? ? ? ? ///< 推挽輸出

? stcGpioCfg.enPu = GpioPuDisable;? ? ? ? ? ? ? ? ? ? ? ? ///< 端口上拉配置->禁止

? stcGpioCfg.enPd = GpioPdDisable;? ? ? ? ? ? ? ? ? ? ? ? ///< 端口下拉配置->禁止

? stcGpioCfg.enDrv=GpioDrvH;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ///< 強驅動

? Gpio_Init(GpioPortB,GpioPin8,&stcGpioCfg);? ? ? ? ? ? ? ///< 端口初始化

? Gpio_SetIO(GpioPortB,GpioPin8);? ? ? ? ? ? ? ? ? ? ? ? ? ///< 默認置高電平

}

第2步:配置延時,本案例基于HC32L136 24MHz時鐘頻率下工作的,一個機器周期約為2us(num參數,不是倍數關系,HC32L136延時相當不精準,需要用示波器驗證),代碼如下所示:

void delay_us(uint32_t num)

{

? while(num--)

? {

? ? __NOP();

? }

}

第3步:初始化以及檢測DS18B20是否存在,當DS18B20響應復位信號的存在脈沖后,則其向主設備表明其在該總線上,并且已經做好操作命令。

在初始化序列期間,總線上的主設備通過拉低1-Wire總線超過480us來發送(TX)復位脈沖。之后主設備釋放總線而進入接收模式(RX)。當總線釋放后,5kΩ左右的上拉電阻將1-Wire總線拉至高電平。當DS18B20檢測到該上升邊沿信號后,其等待15us至60us后通過將1-Wire總線拉低60us至240us來實現發送一個存在脈沖。初始化時序如下圖所示:

初始化時序代碼如下所示:

//復位DS18B20

void DS18B20_Rst(void) ?

{? ? ?

? DS18B20_IO_OUT(); ? ? ? ? ? ? ? ? ///< 配置端口輸出

? Gpio_ClrIO(GpioPortB,GpioPin8); ///< 拉低DQ

? delay100us(7);? ? ? ? ? ? ? ? ? ? ? ? ///< 拉低700us

? Gpio_SetIO(GpioPortB,GpioPin8); ///< 拉高DQ

? delay10us(1);? ? ? ? ? ? ? ? ? ? ? ? ///< 拉高15us

}

//等待DS18B20的回應

//返回1:未檢測到DS18B20的存在

//返回0:存在

uint8_t DS18B20_Check(void) ?

{?

? uint8_t retry=0;

? DS18B20_IO_IN(); ///< 配置端口輸入

? while ((Gpio_GetInputIO(GpioPortB,GpioPin8)==1) && (retry<100))? ///< 最多200us

? {

? ? retry++;? ? ? ? ? ?

? ? delay_us(1);? ? ? ? ///< 每次等待2us

? }

? if(retry>=200)

? {

? ? return 1;

? }

? else

? {

? ? retry=0;

? }

? while ((Gpio_GetInputIO(GpioPortB,GpioPin8)==0 )&& (retry<120))? ///< 最多240us

? {

? ? retry++;

? ? delay_us(1);? ? ? ? ///< 每次等待2us

? }

? if(retry>=120)

? {

? ? return 1;

? }

? return 0;

}

運行程序,時序效果如下所示:

第4步:開始轉換DS18B20,寫入ROM命令:0XCC和0X44。寫時段有兩種情況:“寫1”時段和“寫0”時段,主設備通過寫1時段來向DS18B20中寫入邏輯1以及通過寫0時段來向DS18B20中寫入邏輯0。每個寫時段最小必須有60us的持續時間且獨立的寫時段間至少有1us的恢復時間。

為了形成寫1時段,在將1-Wire總線拉低后,主設備必須在15us之內釋放總線。當總線釋放后,5kΩ的上拉電阻將總線拉至高。為了形成寫0時段,在將1-Wire總線拉低后,在整個時段期間主設備必須一直拉低總線(至少60us)。

在主設備初始化寫時段后,DS18B20將會在15us至60us的時間窗口內對總線進行采樣。如果總線在采樣窗口期間是高電平,則邏輯1被寫入DS18B20;若總線是低電平,則邏輯0被寫入DS18B20。讀/寫時段時序如下所示:

轉換DS18B20代碼如下所示:

//寫一個字節到DS18B20

//dat:要寫入的字節

void DS18B20_Write_Byte(uint8_t dat)? ?

{? ? ? ? ? ?

? uint8_t j;

? uint8_t testb;

? DS18B20_IO_OUT(); ? ? ? ? ? ? ? ? ///< 配置端口輸出

? for (j=1;j<=8;j++)

? {

? ? testb=dat&0x01;

? ? dat=dat>>1;

? ? if (testb)? ? ? ? ? ? ? ? ? ? ? ? ///< 寫入1

? ? {

? ? ? Gpio_ClrIO(GpioPortB,GpioPin8); ?

? ? ? delay_us(1);? ? ? ? ? ? ? ? ? ? ///< 拉低2us?

? ? ? Gpio_SetIO(GpioPortB,GpioPin8);

? ? ? delay10us(5);? ? ? ? ? ? ? ? ? ? ///< 拉高64us

? ? }

? ? else? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ///< 寫入0

? ? {

? ? ? Gpio_ClrIO(GpioPortB,GpioPin8);? ?

? ? ? delay10us(5);? ? ? ? ? ? ? ? ? ? ///< 拉低64us

? ? ? Gpio_SetIO(GpioPortB,GpioPin8);

? ? ? delay_us(1);? ? ? ? ? ? ? ? ? ? ///< 拉高2us?

? ? }

? }

}

//開始溫度轉換

void DS18B20_Start(void)

{? ? ? ? ? ? ? ?

? DS18B20_Rst(); ?

? DS18B20_Check();

? DS18B20_Write_Byte(0xCC); ///<? skip rom

? DS18B20_Write_Byte(0x44); ///<? convert

}

運行程序,寫入0XCC(二進制:1100 1100)時序效果如下所示:

寫入0X44(二進制:0100 0100)時序效果如下所示:

第5步:?寫入讀取DS18B20暫存器功能命令:0XCC和0XBE,代碼如下所示:

DS18B20_Write_Byte(0xCC); ///< skip rom

? DS18B20_Write_Byte(0xBE); ///<? convert

運行程序,寫入0XBE(二進制:1011 1110)時序效果如下所示:

第6步:??讀取溫度寄存器數據,這里只需要讀取兩個字節(16位)即可。每個讀時段最小必須有60us的持續時間且獨立的寫時段間至少有1us的恢復時間。讀時段通過主設備將總線拉低超過1us再釋放總線來實現初始化,當主設備初始化完讀時段后,DS18B20將會向總線發送0或者1。DS18B20通過將總線拉至高來發送邏輯1,將總線拉至低來發送邏輯0。當發送完0后,DS18B20將會釋放總線,則通過上拉電阻該總線將會恢復到高電平的閑置狀態。從DS18B20中輸出的數據在初始化讀時序后僅有15us的有效時間,因此,主設備在開始改讀時段后的15us之內必須釋放總線,并且對總線進行采樣。讀時段時序圖如下所示:

讀時段代碼如下所示:

//從DS18B20讀取一個位

//返回值:1/0

uint8_t DS18B20_Read_Bit(void)

{

? uint8_t data;

? DS18B20_IO_OUT(); ///< 配置端口輸出

? Gpio_ClrIO(GpioPortB,GpioPin8);

? delay_us(1);? ? ? ? ? ///< 等待2us

? Gpio_SetIO(GpioPortB,GpioPin8);

? DS18B20_IO_IN(); ///< 配置端口輸入

? delay_us(40);? ? ? ? ///< 等待12us

? if(Gpio_GetInputIO(GpioPortB,GpioPin8)==1)

? {

? ? data=1;

? }

? else

? {

? ? data=0;

? }

? delay10us(4);? ? ? ? ///< 等待52us

? return data;

}

//從DS18B20讀取一個字節

//返回值:讀到的數據

uint8_t DS18B20_Read_Byte(void)? ?

{? ? ? ?

? uint8_t i=0,j=0,dat=0;

? uint8_t num1,num2;

? for (i=1;i<=8;i++)? ? ? ? ? ? ///< 一次讀取一個字節,8位

? {

? ? j=DS18B20_Read_Bit();

? ? num1=j<<7;

? ? num2=dat>>1;

? ? dat=num1|num2;

? }

? return dat;

}

TL=DS18B20_Read_Byte(); ///<? 讀取LSB,低八位數據?

TH=DS18B20_Read_Byte(); ///<? 讀取MSB,高八位數據? ?

運行程序,讀取低八位數據時序效果如下所示:

?讀取高八位數據時序效果如下所示:

所以讀到的數據為,二進制:101101010。

第7步:將十六進制數據轉換為十進制形式,代碼如下所示:

if(TH>7) ///< 溫度為負

{

? TH=~TH;

? TL=~TL;

? temp_flag=0;

}

else? ? ? ? ? ? ? ? ? ? ? ? ? ///<? 溫度為正

{

? temp_flag=1;

} ?

tem=TH;

tem<<=8;? ?

tem+=TL;

temp=(float)tem/16.0; ///<? 轉換數據

if(temp_flag)

{

? return temp;

}

return -temp;? ?

二進制:101101010按照數據手冊轉換為十進制362,362除以16為22.625,與此時程序串口打印效果完全一致,說明轉換無誤。

4、ESP32驅動

閑來無事為了驗證溫度檢測的精準性(HC32L136精度較差),特使用ESP32又寫了一版驅動程序,完整示例代碼如下所示(可直接復制使用):

#include <OneWire.h>

int DS18B20_Pin = D3; //DS18B20信號引腳在D3上

//溫度芯片I/O

OneWire ds(DS18B20_Pin);? //配置數字引腳D3

void setup(void) {

? Serial.begin(9600);

? Serial.println("Start!\n");

}

void loop(void) {

? float temperature = getTemp();

? Serial.println(temperature);

? delay(1000);

}

float getTemp(){

? //獲取DS18B20溫度數據

? byte data[12];

? byte addr[8];

? if ( !ds.search(addr)) {

? ? ? //若無傳感器繼續搜索

? ? ? ds.reset_search();

? ? ? return -1000;

? }

? if ( OneWire::crc8( addr, 7) != addr[7]) {

? ? ? Serial.println("CRC is not valid!");

? ? ? return -1000;

? }

? if ( addr[0] != 0x10 && addr[0] != 0x28) {

? ? ? Serial.print("Device is not recognized");

? ? ? return -1000;

? }

? ds.reset();

? ds.select(addr);

? ds.write(0x44,1); //開始轉換

? byte present = ds.reset();

? ds.select(addr);? ?

? ds.write(0xBE); //讀暫存存儲器

? for (int i = 0; i < 9; i++) { //讀取9個字節

? ? data[i] = ds.read();

? }

? ds.reset_search();

? byte MSB = data[1];

? byte LSB = data[0];

? float tempRead = ((MSB << 8) | LSB);

? float TemperatureSum = tempRead / 16;

? return TemperatureSum;

}

同時運行程序,HC32L136和ESP32同時獲取DS18B20溫度數據基本一致,時序效果如下所示:

串口輸出數據效果如下所示:

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容