初步認識51單片機-2.3單片機控制DS18B20溫度傳感器模塊
在DS18B20中有一個溫度傳感器(如上圖所示),它能感知周圍環(huán)境溫度,并能將溫度的結果直接轉成數字信號存儲起來。溫度信號轉成數字信號的過程我們可以不用關心。那么數字信號存在哪里了?DS18B20中有一個叫做ScratchPad的存儲器,一共9個字節(jié)(Byte0-Byte8),數字信號就存儲在Byte0_LSM和Byte1_MSB中。其中Byte0為低位,Byte1為高位。事實上,我們的目的就是讀出Byte0和Byte1中存儲的數字信號而已。由此可見,雖然名字是溫度傳感器模塊,但是在我們的思考過程中絲毫不用關心傳感的過程,這一點與前面講到的LCD1602其實是一樣,我們要做的事情只是去讀或者寫。這就是模塊的作用,我們可以把它當作黑盒子,按照它的規(guī)則,只要掌握往里面輸入,它會產出什么就行了,不需要關注中間的過程。我們把Byte0_LSM和Byte1_MSB組合成一個16bit的數字信號,Byte0_LSB為低位,Byte1_MSB為高位,并給它取個名字叫”T-16bit”,如上圖所示。那么如何把這個”T-16bit”的數字信號轉換成溫度呢?從圖中看出,bit11-bit15為S,表示溫度的正負,如果S=0,那么溫度為正,如果S=1那么溫度為負。后面的bit10-bit0,數值每增加一就表示溫度增加0.0625°C,舉個例子: 假如LSB中讀出來的是1100 0011,MSB讀出來的是0000 0110,那么LSB和MSB結合起來”T-16bit”就是0000 0110 1100 0011,高5位為0,表示溫度為正,余下11位bit10-bit0(110 1100 0011=1731),把1731×0.0625=108.1875,那么測量的溫度為+108.1875°C. 如果LSB和MSB結合起來”T-16bit”為1111 1110 1100 0011,那么測量的溫度為-108.1875°C. 在”T-16bit”中,我們也可以這樣理解,bit0位每加1,表示20×0.0625°C,bit1位每變化1表示21×0.0625°C, 依此類推, bit4位每變化1為24×0.0625°C=1°C.
本文引用地址:http://m.butianyuan.cn/article/201611/319544.htm接著就是Byte2_TH和Byte3_TL報警的功能了,圖中Byte2_TH表示設置的最高溫度,Byte3_TL表示設置的最低溫度。同樣S表示溫度的正負,如果S=0,那么表示正,如果S=1,那么溫度為負。Byte2_TH和Byte3_TL就表示設定溫度的范圍了。注意這里的Byte2_TH與Byte3_TL與”T-16bit”中的bit11到bit4是對應的,如圖中藍色部分所示。前面講了,在”T-16bit”中,bit4每變化1為1°C,因此在Byte2_TH與Byte3_TL中的最低位每變化1,表示溫度變化1°C. 比如Byte2_TH設定為,01111001(十進制為121),首位為0,表示+121°C, Byte3_TL為01001001(十進制為73),首位為0,表示+73°C .因此溫度的設定范圍為:73-121°C. 當”T-16bit”中的溫度高于/等于+121°C,或者低于/等于73°C時,將觸發(fā)報警。
接下來就是溫度采集的精度設置了,如圖中的Byte4_Config所示。bit5和bit6分別為R0和R1,其他幾位是固定的。R0和R1分別可以取0或者1,因此可以組合成4種情況,00/01/10/11,分別對應不同的精度,如下表所示:
Byte5-Byte7未給出,Byte8為CRC用與通信錯誤檢測,我們暫且不用管它,我們先考慮簡單的部分
通過上面的講解,相信對DS18B20有了初步的認識,現在再來談談它與單片機如何溝通的。DS18B20一共三個引腳,兩個電源引腳(電源正負極),一個數據引腳DQ.其結構圖如下所示。黑色殼體朝上,引腳朝下,平面對著自己,左手邊第一個引腳為GND. DS18B20的正負極如果接反,可能會燒掉。
可見單片機與DS18B20的溝通只能靠這一根線了,另外這一根線上可以同時接很多個DS18B20. 那么單片機是如何通過這一根線準確的與多個DS18B20溝通的呢?單片機是不知道DQ線上有沒有DS18B20的,或者有多個,或者有但是壞了。與人的溝通方式一樣,當你不知道屋里情況的時候,會先打個招呼,問下有人沒。同樣,單片機也一樣,先來個初始化,打個招呼,看看DQ線上有沒有18B20。怎么樣打招呼呢,與前面講LCD1602一樣,當然按照DS18B20的規(guī)則。單片機先要把DQ拉低至少480μS, 然后釋放DQ,大約在15-60μS后,如果線上有DS18B20并能正常工作,那么DS18B20將DQ拉低并維持60-240μS. 單片機通過檢查這個信號,從而判斷線上是否有能正常工作的DS18B20,有多少個信號就掛著多少個DS18B20,這個就是DS18B20的規(guī)則,具體如下,
初始化后之后就可以與DS18B20溝通了?線上如果有多個DS18B20,你到底是要與哪個溝通呢?因此溝通之前要先來個確定對象。這里我們取最簡單一個DS18B20,搞懂了一個,自然會做控制多個DS18B20了。我們來看看初始化代碼如何寫,
step1:首先DQ拉低,要維持至少480Us,這里我們取500Us保險一點
step2:釋放總線(DQ=1),大約等待15-60Us后,DS18B20會把DQ拉低。那么這里到底是選15Us,還是60Us?
step3:此時DS18B20把DQ拉低信號(L_DQ)能持續(xù)60-240Us.那么到底選60Us還是240Us?
注意我們這里的目的是要檢測出DS18B20是否拉低DQ的信號(L_DQ)。那么在step2中,釋放總線(DQ=1)后,我們到底要延時多長時間(Tdelay),去讀DQ是否等于0的信號?
我們來個極端假設,最小值和最大值
(1)在step2中, 單片機釋放總線(DQ=1),等待15Us(最小值)后,DS18B20把DQ拉低,在step3中,DQ拉低持續(xù)了60Us(最小值)
在這種情況下,如果Tdelay>75Us,你就不能檢測到L_DQ信號了。因此Tdelay要小于75Us.
(2)在step2中, 單片機釋放總線(DQ=1),等待60Us(最大值)后,DS18B20把DQ拉低,在step3中,DQ拉低持續(xù)了60/240Us(兩種情況)
在這種情況下,如果Tdelay<60Us,你就檢測不到L_DQ信號了。比如你設置Tdelay=50Us然后去讀DQ,此時DQ仍然為1,為什么?因為60Us后
DS18B20才把DQ拉低。因此Tdelay>60Us.
綜上所述,保險時間為:75Us>Tdelay>60Us,代碼如下:
void ds18b20_init(void)
{
DQ=0;//總線拉低
delayUs(240); //延時526Us
DQ=1;//釋放總線
delayUs(28);//延時66Us(60-75Us之間)
if(DQ==0)
{
LED1=0;//(設置一個LED,如果檢測到DQ=0,就把LED1點亮)
}
else
{
LED2=0;
}
delayUs(240);//注意讀完DQ后要繼續(xù)延時480Us
}
DS18B20的ID信號在ROM中,因此這里我們可以跳過讀ROM(Skip ROM[CCh]).
接下來就到了與DS18B20溝通的部分了。DS18B20一上電的時候是鈍態(tài)的,就是說它是被動的,沒有指令它就不干活。所以,單片機給DS18B20的第一個指令就是讓它開始測量溫度(Convert T [44h]). 當DS18B20收到這條指令后干什么呢?這里就要回到前面的我們講的圖1,DS18B20開始感知周圍溫度并把溫度高低轉成數字信號存儲在ScratchPad中的Byte0和Byte1中。從這里我們知道,我們僅僅通過一條指令Convert T,就讓DS18B20開始溫度測量并存儲,至于這個過程怎么發(fā)生的我們并不關心。從這里我們看到,其實控制DS18B20模塊與LCD1602模塊沒有本質上區(qū)別,我們要做的事情僅僅是去讀懂規(guī)則,這些規(guī)則來源與它們的芯片手冊,那么簡單的講就是閱讀理解芯片手冊。這一點其實被很多初學者忽略了,不愿意或者不習慣查看芯片手冊。DS18B20把溫度信號轉成數字信號需要一定的時間,因此在發(fā)布下一條指令前,我們這里需要檢測DS18B20是否仍處于工作之中,如果你想簡化,來個延時也行。轉換完成后,DS18B20又處于鈍態(tài)了,這個轉換過程不是持續(xù)的,因此你想讓它再轉換,那么就必須再發(fā)一次Convert T指令。
那么怎么發(fā)指令呢?這個就涉及到‘DS18B20寫’的部分了。參考數據手冊,找到‘寫時序
首先看單片機如何往DS18B20中寫0和1,
(1)寫0:DQ拉低,維持至少60Us,在大約15-60Us的時候,DS18B20開始接受數據
(2)寫1: DQ拉低,延時2Us,然后釋放DQ,此時,上拉電阻會把DQ拉高,延時至少60Us,在15-60Us的時候,DS18B20開始接受數據
因此寫指令的代碼如下
void ds18b20_com(unsigned char mycom)
{
unsigned char temp;
unsigned char i;
for (i=0;i<8;i++)
{
temp=mycom & 0x01;
if (temp==1)
{
DQ=0;
_nop_();
_nop_();
DQ=1;
delayUs(35);
}
else
{
DQ=0;
delayUs(35);
DQ=1;
}
mycom>>=1;
}
}
所以,如果你要發(fā)指令 ds18b20_com(0xcch)//skip rom,DS18B20就知道了要跳過讀ROM,如果要發(fā)指令Convert T, ds18b20_com(0x44h),DS18B20就開始溫度轉換,并存儲在ScratchPad中的前兩個字節(jié)。
當轉換完成后,數據存儲在Byte0和Byte1中,下面的任務就是去讀Byte0和Byte1了。這里需要注意的是,再單片機每發(fā)一次指令之前都要: 初始化->ROM指令->功能指令。這個是芯片手冊上規(guī)定的。因此在讀Byte0和Byte1之前要再初始化一次,Skip ROM([CCh]), 就可以讀Byte0和Byte1了。之后將Byte0和Byte1合并,然后轉換成溫度就可以了。
現在我們來看看如何讀DS18B20,同樣查看芯片手冊,找到讀的時序圖
DS18B20要把數據發(fā)送給單片機,那么DS18B20怎么知道單片機什么時候開始要數據呢?這里同樣有個規(guī)則,當單片機將DQ拉低,延時1Us,然后釋放DQ。此時,DS18B20就知道了,哦,單片機開始要數據了。如果此時DS18B20要給0,就把DQ拉低,相反,如果要寫1就讓DQ維持高的狀態(tài)。從單片機發(fā)出讀數據信息,DS18B20給數據,單片機采集數據,這個過程要在15Us完成,之后需要延時45Us,為保險,我們這里取65Us。兩個讀之間,至少要有1Us的間隔。因此很容易得出單片機讀DS18B20的代碼:
unsigned int ds18b20_read(void)
{
unsigned char temp1=0;
unsigned int temp2=0;
unsigned int temp=0;
unsigned char i;
for (i=0;i<8;i++)
{
temp1>>=1;
DQ=0;
_nop_();
_nop_();
DQ=1;
if(DQ==1)
temp1 |=0x80;
delayUs(35);
}
for (i=0;i<8;i++)
{
temp2>>=1;
DQ=0;
_nop_();
_nop_();
DQ=1;
if(DQ==1)
temp2 |=0x80;
delayUs(35);
}
temp2 <<=8;
temp=temp1+temp2;
return temp;
}
通過LCD1602和DS18B20兩個例子可以看出,對這兩個模塊的控制,其實只用了單片機的引腳控制和延時程序。重點和難點其實在理解各模塊的控制規(guī)則。其實這些只需要通過仔細閱讀對應的芯片手冊就能找到。而單片機引腳的控制和延時部分與LED的操作并無區(qū)別,難怪有人說,如果你把操作LED的過程真正搞懂了,單片機你就學會了一半。后面我們會反復的使用LED作為例子,講解單片機其它相關內容。
評論