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