DS18B20是常用的數字溫度傳感器,具有體積小,精度高,占用硬件資源少等優點。
它的突出優點在於采用單總線(1-wire)的接口方式,與微處理器連接時僅需要一根信號線即可實現雙向通訊。甚至供電線也可以不用,直接通過寄生方式從信號線上取電,可只連接信號線(DQ)和GND即可使用。
DS18B20內部具有64位固化在ROM中的序列號,可以用來識別不同器件;所以,在單總線上,可以掛載多個DS18B20,以實現最少的連接掛載多個器件。
本文主要介紹在單總線上掛載多個DS18B20溫度傳感器的使用方法。
首先了解一下單總線的硬件結構,看其datasheet里的結構圖:
這個圖里說明,DS18B20在輸出時,是靠拉低DQ通信線實現低電平輸出,靠釋放DQ通信線(被上拉電阻拉高)來實現高電平輸出。
也就是說它可以實現“線與”。多個DS18B20同時輸出時,只要有一個低電平,則DQ通信線就會被拉低,只有低電平能被識別,只有都為高電平是,總線上才是高電平。單總線上識別不同的DS18B20就是靠“線與”來解決通信沖突的。
當單總線上掛載多個DS18B20時,MCU必須知道每個DS18B20內部固化的64bit序列號,才能分別和它們通信。所以MCU如何獲取DS18B20內部的序列號,就是解決問題的關鍵。
DALLAS官方給出的文檔中,介紹了通過單總線獲取DS18B20內部序列號ID的方法,訪問每個bit時,分為三步:
先讀取第一位;
再讀取第一位的補碼;
通過讀取的數據和補碼,和下表對應的結論,來判斷總線上的器件狀態:
然后寫一位數據,告訴從器件,主機MCU選擇了哪些器件繼續通信;如果從機當前ROM碼全為0,則寫0;如果從機當前ROM碼全為1,則寫;如果從機當前ROM碼有0也有1,則MCU可以先寫0,選擇為0的器件繼續通信;等本次后續的bit位都搜索完后,再回到此處,選擇為1的器件,到另一個分支搜索。
MCU就是通過不斷循環、回溯,完成所有器件的搜索,獲取所有器件的序列號。
描述起來有點難懂,可以看具體的例子:
假如總線上掛載了三個DS18B20,我們命名為a、b、c器件,為簡化處理,假設器件ID只有兩位,分別是:01、00、11;MCU從低位開始讀取。
a)第一輪通信
主機MCU先讀取第1位,a的最低位為1、b的最低位為0、c的最低位為1,由於最低位有0,所以總線數據會被識別為0;
再讀取第1位的補碼,a的最低位補碼為0、b的最低位補碼為1、c的最低位補碼為0,則總線數據也會被識別為0;
主機MCU識別到兩次都為0,則知道總線上有器件為0、也有器件為1;則主機MCU需要選擇一條路徑繼續訪問;如果我們的算法選擇優先訪問0的路徑;則向總線上寫入一個0位;三個從器件收到發送來的0后,只有b器件的對應位符合,則下一次通信時,a、c器件都不會再響應;
b)第二輪通信
主機MCU開始讀取第2位,由於只有b器件響應,則讀到0;
再讀取第2位的補碼,由於只有b器件響應,可以讀到1;
主機MCU兩次讀取到0、1,則可以判定總線上的器件該位為0;
又因為,上一輪選擇的是0路徑,加上本次識別到的0,則可以斷定,總線上有一個器件的ID是00;識別完ID的總長度(2位)后,本次搜索結束。
c)回溯后再次通信
與第一輪通信類似,最后寫入的位改為1;則只有a、c器件的對應位符合,后續只有a、c器件會繼續通信,b器件不再響應;
主機MCU開始讀取第二位,讀取到0;
讀取補碼,讀到0;
則主機可以斷定,第二位有0、也有1;再加上上一輪通信中選擇的1路徑,則可以斷定,總線上有兩個器件:10和11。
至此,所有ID搜索完畢,搜索的示意見下圖:
實際的DS18B20的ID有64bit,搜索的原理是一樣的,以此可以獲取總線上所有器件的ID,之后就可以通過ID來訪問特定器件了。
一種實現搜索ID的方法如下代碼所示:
該算法來源於網絡。另外,DALLAS官方也給出了效率更高的一種實現方法,代碼比較長,這里就不貼了,感興趣的可以在文末留言自行獲取。
如果總線上只掛載了一個器件,通常我們可以不用理會序列號ID,直接跳過ID號識別這個步驟,如下示例來訪問:
Ds18Write(0xcc); //跳過ID號指令
Ds18Write(0xbe); //讀取指令
當獲取了ID號之后,我們就可以通過指定ID號來訪問特定的器件,如下示例訪問:
Ds18Write8Btye(DS18B20_ID); //寫入8Btye(即64bit)的ID號
Ds18Write(0xbe); //讀取指令
這樣,我們就可以分別獲取每個器件的數據了,實現了單總線上掛載多個DS18B20的操作。
本文相關的代碼,可以關注我的公眾號“小白白學電子”,留言“資料”獲取: