|
DS18B20 14.1概念 . 這一章 是關于 DS18B20 實時溫 度傳感器。 相信有學過 c51 單片機 的朋友都對 他不陌生 吧。我恰恰也學習過,不過當初并沒有掌握好。學習板搭配的 DS18B20,一般上給人的 感覺有點 像三極管,其實 DS18B20 的內部結 構與原理也挺猥 瑣的,但是我們使 用也是 為了實現溫度傳感的功能而已,基本上不會介紹過度深入。
14.2DS18B20介紹
 DS18B20 有三只引腳,VCC,DQ ,和 VDD。
而 HJ-2G 板子上,采用了外部供電的鏈接方式,而總線必須鏈接上拉電阻。這一目的告 訴我們,一線總線在空置狀態時,都是一直處于高電平。

DS18B20 的 內 部 有 64 位 的ROM 單元,和 9 字節的暫存器單 元 。 64 位 ROM 包 含 了 ,DS18B20 唯一的序列號(唯一的名字)。
以上是內部 9 個字節的暫存單元(包括 EEPROM)。 字節 0~1 是轉換好的溫度。 字節 2~3 是用戶用來設置最高報警和最低報警值。這個可以用軟件來實現。 字節 4 是用來配置轉換精度,9~12 位。 字節 5~8 就不用看了。
14.3字節 0~1:轉換好的溫度
DS18B20 的溫度操作是使用 16 位,也就是說分辨率是 0.0625。BIT15~BIT11 是符號位, 為了就是表示轉換的值是正數還是負數?纯磾祿謨越o出的例子吧。
要求出正數的十進制值,必須將讀取到的 LSB 字節,MSB 字節進行整合處理,然后乘 以 0.0625 即可。
Eg:假設從,字節 0 讀取到 0xD0 賦值于 Temp1,而字節 1 讀取到 0x07 賦值于 Temp2, 然后求出十進制值。
unsigned int Temp1,Temp2,Temperature;
Temp1=0xD0; // 低八位 Temp2=0x07; // 高八位
Temperature = ((Temp2<<8 ) | Temp1 ) * 0.0625; // 又或者 Temperature = (Temp1 + Temp2 *256) * 0.0625; //Temperature=125
在這里我們遇見了一個問題,就是如何求出負數的值呢?很遺憾的,單片機不像人腦那 樣會心算,我們必須判斷 BIT11~15 是否是 1,然后人為置一負數標志。
Eg. 假設從,字節 0 讀取到 0x90 賦值于 Temp1,而字節 1 讀取到 0xFC 賦值于 Temp2, 然后求出該值是不是負數,和轉換成十進制值。
- unsigned int Temp1,Temp2,Temperature;
- unsigned char Minus_Flag=0;
- Temp1=0x90; // 低八位
- Temp2=0xFC; // 高八位
- //Temperature = (Temp1 + Temp2 *256) * 0.0625; //Temperature=64656
- // 很明顯不是我們想要的答案
- if(Temp2&0xFC) // 判斷符號位是否為 1
- {
- Minus_Flag=1; // 負數標志置一
- Temperature = ((Temp2<<8 ) | Temp1 ) // 高八位第八位進行整合
- Temperature= ((~Temperature)+1); // 求反,補一
- Temperature*= 0.0625; // 求出十進制
- } //Temperature=55;
- else
- {
- Minus_Flag=0;
- Temperature = ((Temp2<<8 ) | Temp1 ) * 0.0625;
- }
復制代碼
那個人為的負數標志,是真的很有用處的。這個要看你你自己的想象力了,如何去利用它。
繼續繼續,以上我們是求出沒有小數點的正數。如果我要求出小數點的值的話,那么我 應該這樣做。
Eg:假設從,字節 0 讀取到 0xA2 賦值于 Temp1,而字節 1 讀取到 0x00 賦值于 Temp2, 然后求出十進制值,要求連同小數點也求出。 - unsigned int Temp1,Temp2,Temperature;
- Temp1=0x90; // 低八位
- Temp2=0xFC; // 高八位
- // 實際值為 10.125
- //Temperature = ((Temp2<<8 ) | Temp1 ) * 0.0625; //10,無小數點
- Temperature = ((Temp2<<8 ) | Temp1 ) * (0.0625 * 10) ; //101 ,一位小數點
- //Temperature = ((Temp2<<8 ) | Temp1 ) * (0.0625 * 100) ; //1012,二位小數點
復制代碼
如以上的例題,我們可以 先將 0.0625 乘以 10,然后再乘以整合后的 Temperature 變量 , 就可以求出后面 一個小數點的值(求出更多的小數 點,方法都是以此類推 )。得出的結 果是 101,然后再利用簡單的算法,求出每一位的值。
unsinged char Ten,One,Dot1
Ten=Temperature/100; //1 One=Temperature%100/10; //0 Dot1=%10; //1
求出負數的思路也一樣,只不過多出人為置一負數標志,求反補一的動作而已。自己發 揮想象力吧。
14.4字節 2~3:TH和 TL配置 TH 與 TL 就是所 謂的溫度最 高界限,和 溫度最低界 限的配置。 其實這些可 以使用軟件 來試驗,所以就無視了。
14.5字節 4:配置寄存器
BIT7 出廠的時候就已經設置為 0,用戶不建議去更改。而 R1 與 R0 位組合了四個不同 的轉換精度, 00 為 9 位轉換精度而轉換時間是 93.75ms,01 為 10 位轉換精度而轉換 時 間是 187.5ms,10 為 11 位轉換精度而轉換時間是 375ms,11 為 12 位轉換精度而轉換時 間是 750ms(默認)。該寄存器還是留默認的好,畢竟轉換精度表示了轉換的質量。
14.6字節 5~7,8:保留位,CRC 無視,無視吧。
14.7單片機訪問 DS18B20 DS18B20 一 般 都是 充 當 從 機的 角 色 , 而單 片 機 就 是主 機 。 單 片機 通 過 一 線總 線 訪 問 DS18B20 的話,需要經過以下幾個步驟:
1.DS18B20 復位。 2.執行 ROM 指令。 3.執行 DS18B20 功能指令(RAM 指令)。
補充一下 。一般上我們都 是使用單點,也就 是說單線總線上 僅有一個 DS18B20 存在而 已。所以 我們無需刻意讀 取 ROM里邊的序 列號來,然后匹 配 那個 DS18B20?而是更 直接的,跳過 ROM 指令,然后直接執行 DS18B20 功能指令。
DS18B20 復位,在某種意義上就是一次訪問 DS18B20 的開始,或者可說成是開始信號。
ROM 指令,也就是訪問,搜索,匹配,DS18B20 個別的 64 位序列號的動作。在單點情 況下,可以直接跳過 ROM 指令。而跳過 ROM 指令的字節是 0xCC。
DS18B20 功能指令有很多種,我就不一一的介紹了 ,數據手冊里有更詳細的介紹。這里 僅列出比較常用的幾個 DS18B20功能指令。
0x44:開始轉換溫度。轉換好的溫度會儲存到暫存器字節 0 和 1。 0xEE :讀暫存指令。讀暫存指令,會從暫存器 0 到 9,一個一個字節讀取,如果要停止 的話,必須寫下 DS18B20 復位。
14.8DS18B20復位
DS18B20 的復位時序如下: 1.單片機拉低總線 480us~950us, 然后釋放總線(拉高電平)。 2.這時 DS18B20 會拉低信號,大約 60~240us 表示應答。 3.DS18B20 拉低電平的 60~240us 之間,單片機讀取總線的電平,如果是低電平,那么表示復位成功。 4.DS18B20 拉低電平 60~240us 之后,會釋放總線。
C 語言代碼:
//DS1302 復位 函數 void DS1302_Res et()
{ DDRA|=BIT(DQ); //DQ 為輸 出狀態 PORTA&=~BIT(DQ); //輸出 低電平Delay_1us (500); //延遲 500 微妙 PORTA|=BIT(DQ); //示范 總線 Delay_1us(60); //延遲 60 微妙 DDRA&=~BIT(DQ); //DQ 位輸 出狀態 while(PINA&BIT (DQ)); //等待 從機 DS18B20 應答 (低電 平有效 ) while(!(PINA&BIT(DQ))); //等待 從機 DS18B20 釋放 總線 }
14.9DS18B20讀寫邏輯 0與 1
 DS18B20 寫邏 輯 0 的步 驟如下 : 1.單片 機拉低 電平大 約 10~15us ,。 2.單片 機持續 拉低電 平大約 20~45us 的時 間。 3.釋放 總線 DS18B20 寫邏 輯 1 的步 驟如下 : 1.單片 機拉低 電平大 約 10~15us ,。 2.單片 機拉高 電平大 約 20~45us 的時 間。 3.釋放 總線
 DS18B20 讀邏 輯 0 的步 驟如下 : 1.在讀 取的時 候單片 機拉低 電平大 約 1us 2.單片 機釋放 總線, 然后讀 取總線 電平。 3.這時 候 DS18B20 會拉 低電平 。 4.讀取 電平過 后,延 遲大約 40~45 微妙 DS18B20 讀邏 輯 1 的步 驟如下 : 1.在讀 取的時 候單片 機拉低 電平大 約 1us 2.單片 機釋放 總線, 然后讀 取總線 電平。 3.這時 候 DS18B20 會拉 高電平 。 4.讀取 電平過 后,延 遲大約 40~ 45 微妙
如果要讀或者寫 一個字節,就要重復以上的步驟八 次。如以下的 C 代碼,使用 for 循環,和數據變 量的左移和或運算,實現一個字節讀與寫。
- //DS18B20 寫字 節函數
- void DS1302_Write(uns igned char Data)
- {
- unsigned char i;
- DDRA|=BIT(DQ); //DQ 為輸 出
- for(i=0;i<8;i++)
- {
- PORTA&=~BIT(DQ); //拉低 總線
- Delay_1us (10); //延遲 10 微妙 (最大 15 微妙 )
- if(Data&0x01) PORTA|=BIT(DQ);
- els e PORTA&=~BIT(DQ);
- Delay_1us (40); //延遲 40 微妙 (最大 45 微妙 )
- PORTA|=BIT(DQ); //釋放 總線
- Delay_1us (1); //稍微 延遲
- Data>>=1;
- }
- }
- //DS18B20 讀字 節函數
- unsigned char DS1302_Read()
- {
- unsigned char i,Temp;
- for(i=0;i<8;i++)
- {
- Temp>>=1; //數據 右移
- DDRA|=BIT(DQ); //DQ 為輸 出狀態
- PORTA&=~BIT(DQ); //拉低 總線, 啟動輸 入 PORTA|=BIT(DQ); //釋放 總線 DDRA&=~BIT(DQ); //DQ 為輸 入狀態
- if(PINA&BIT(DQ)) Temp|=0x80;
- Delay_1us (45); //延遲 45 微妙 (最大 45 微妙 )
- }
- return Temp;
- }
復制代碼
就是這么建檔而已 ,不過這里有一個注意點,就是 Delay_1us(); 函數延遲的時間, 必須模擬非常準 確,因為單線總線對時序的要求敏感點。
14.10簡單歸納 實驗開始之前,簡單的歸納一些重點。單線總線高電平為閑置狀態。單片機訪問 DS18B20 必須遵守, DS18B20 復位-->執行 ROM 指令-->執行 DS18B20 功能指令。而在單點上, 可以直接跳過 ROM 指令。DS18B20 的轉換精度默認為 12 位,而分辨率是 0.0625。
DS18B20 溫度讀取函數參考步驟:
DS18B20 開始轉換: 1.DS18B20 復位。 2.寫入跳過 ROM 的字節命令,0xCC。 3.寫入開始轉換的功能命令,0x44。 4.延遲大約 750~900 毫秒
DS18B20 讀暫存數據: 1.DS18B20 復位。 2.寫入跳過 ROM 的字節命令,0xCC。 3.寫入讀暫存的功能命令,0xee。 4.讀入第 0 個字節 LS Byte,轉換結果的低八位。 5.讀入第 1 個字節 MS Byte,轉換結果的高八位。 6.DS18B20 復位,表示讀取暫存結束。
數據求出十進制: 1.整合 LS Byte 和 MS Byte 的數據 2.判斷是否為正負數(可選) 3.求得十進制值。正數乘以 0.0625,一位小數點乘以 0.625,二位小數點乘以 6.25。 4.十進制的“個位”求出。
14.11實驗:利用 DS18B20實現單點溫度測量,結果輸出在數碼管。
 DS18B20 接口 ATMega 16 對應引腳
實驗的要求是以 DS18B20 默認的配置,亦即 12 位的轉換精度。然而輸出的結果為兩個 小數點 xx.xx。HJ-2G 板子上設計得DS18B20 的接口和典型,沒有什么特別需要注意的。 而 DS18B20 DQ 引腳對應的鏈接是 PA5。
源碼:
- ===================================================================
- //1400-DS18B20.c
- //簡單 的驅動 程式
- //akuei2 08-01-10
- #include "iom16v.h"
- #include "macros .h"
- #include "LED7.h"
- #define DQ PA5
- //微妙 級延遲 函數
- void Delay_1us (unsigned int x)
- {
- unsigned int i;
- x=x*5/4;
- for( i=0;i<x;i++);
- }
- //DS1302 復位 函數
- void DS1302_Res et()
- {
- DDRA|=BIT(DQ); //DQ 為輸 出狀態 PORTA&=~BIT(DQ); //輸出 低電平 Delay_1us(500); //延遲 500 微妙 PORTA|=BIT(DQ); //示范 總線 Delay_1us (60); //延遲60 微妙 DDRA&=~BIT(DQ); //DQ 位輸 出狀態
- while(PINA&BIT (DQ)); //等待 從機 DS18B20 應答 (低電 平有效 )
- while(!(PINA&BIT(DQ))); //等待 從機 DS18B20 釋放 總線
- }
- //DS1302 寫字 節函數
- void DS1302_Write(uns igned char Data)
- {
- unsigned char i;
- DDRA|=BIT(DQ); //DQ 為輸 出
- for(i=0;i<8;i++)
- {
- PORTA&=~BIT(DQ); //拉低 總線
- Delay_1us (10); //延遲 10 微妙 (最大 15 微妙 )
- if(Data&0x01) PORTA|=BIT(DQ);
- els e PORTA&=~BIT(DQ);
- Delay_1us (40); //延遲 40 微妙 (最大 45 微妙 )
- PORTA|=BIT(DQ); //釋放 總線
- Delay_1us (1); //稍微 延遲
- Data>>=1;
- }
- }
- //DS1302 讀字 節函數
- unsigned char DS1302_Read()
- {
- unsigned char i,Temp;
- for(i=0;i<8;i++)
- {
- Temp>>=1; //數據 右移
- DDRA|=BIT(DQ); //DQ 為輸 出狀態
- PORTA&=~BIT(DQ); //拉低 總線, 啟動輸 入 PORTA|=BIT(DQ); //釋放 總線 DDRA&=~BIT(DQ); //DQ為輸 入狀態
- if(PINA&BIT(DQ)) Temp|=0x80;
- Delay_1us (45); //延遲 45 微妙 (最大 45 微妙 )
- }
- return Temp;
- }
- //讀溫 度函數
- unsigned int Read_Temperature()
- {
- unsigned int Temp1,Temp2;
- DS1302_Res et(); //DS1302 復位
- DS1302_Write(0xCC); //跳過 ROM DS1302_Write(0x44); //溫度 轉換
- DS1302_Res et(); //DS1302 復位
- DS1302_Write(0xCC); //跳過 ROM DS1302_Write(0xbe); //讀取 RAM
- Temp1=DS1302_Read(); //讀低 八位, LS Byte, RAM0
- Temp2=DS1302_Read(); //讀高 八位, MS Byte, RAM1
- DS1302_Res et(); //DS1302 復位 ,表示 讀取結 束
- return (((Temp2<<8)|Temp1)*6.25); //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
- }
- void main()
- {
- unsigned int Temp;
- LED7_Init(); //初始 化數碼 管引腳
- while(1)
- {
- Temp=Read_Temperature(); //調用 讀取溫 度函數 Number_Show(Temp); //顯示 溫度Delay_1us (100); //稍微 延遲
- }
- }
- LED7.h 的頭文件
- ===================================================================
- //LED7.H
- // 數碼管顯示
- // 數組聲明并定義在存儲數據區 code
- //0~9
- #pragma data:code
- unsigned char const
- Number[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,}; unsigned char const Number_Dot[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0x00};
- // 延遲函數
- void Delay(unsigned long x)
- {
- while(x--);
- }
- // 數碼管顯示函數
- void Number_Show(unsigned int Num)
- {
- unsigned char Ten,One,Dot1,Dot2; Ten=Num/1000; // 取十位 One=Num%1000/100; // 取個位Dot1=Num%100/10; // 取點數位 Dot2=Num%10; // 取點數位
- // 顯示十位
- PORTB=Number[Ten]; // 送模碼 PORTA|=BIT(PA3); //PA3 高電平PORTA&=~BIT(PA3); //PA3 低電平
- PORTB=~BIT(0); //送位選
- PORTA|=BIT(PA4); //PA3 高電平
- PORTA&=~BIT(PA4); //PA3 低電平
- Delay(600); // 稍微延遲
- // 顯示個位
- PORTB=Number_Dot[One]; // 送模碼
- PORTA|=BIT(PA3); //PA3 高電平
- PORTA&=~BIT(PA3); //PA3 低電平
- PORTB=~BIT(1); //送位選
- PORTA|=BIT(PA4); //PA3 高電平
- PORTA&=~BIT(PA4); //PA3 低電平
- Delay(600); // 稍微延遲
- // 顯示點數位 1
- PORTB=Number[Dot1]; //送模碼
- PORTA|=BIT(PA3); //PA3 高電平
- PORTA&=~BIT(PA3); //PA3 低電平
- PORTB=~BIT(2); //送位選
- PORTA|=BIT(PA4); //PA3 高電平
- PORTA&=~BIT(PA4); //PA3 低電平
- Delay(600); // 稍微延遲
- // 顯示點數位 2
- PORTB=Number[Dot2]; //送模碼
- PORTA|=BIT(PA3); //PA3 高電平
- PORTA&=~BIT(PA3); //PA3 低電平
- PORTB=~BIT(3); //送位選
- PORTA|=BIT(PA4); //PA3 高電平
- PORTA&=~BIT(PA4); //PA3 低電平
- Delay(600); // 稍微延遲
- // 顯示`
- PORTB=0x63; // 送模碼
- PORTA|=BIT(PA3); //PA3 高電平
- PORTA&=~BIT(PA3); //PA3 低電平
- PORTB=~BIT(4); //送位選
- PORTA|=BIT(PA4); //PA3 高電平
-
- PORTA&=~BIT(PA4);Delay(600);
-
- //PA3 低電平
- // 稍微延遲
- // 顯示 C
-
- PORTB=0x39;PORTA|=BIT(PA3);PORTA&=~BIT(PA3);
-
- // 送模碼
- //PA3 高電平
- //PA3 低電平
- PORTB=~BIT(5);
-
- //送位選
- PORTA|=BIT(PA4);PORTA&=~BIT(PA4);Delay(1000);
-
- //PA3 高電平
- //PA3 低電平
- // 稍微延遲
- }
-
-
- //IO 初始化函數
- void LED7_Init()
- {
- DDRA|=BIT(PA3); //PA3 狀態為輸出
- DDRA|=BIT(PA4); //PA4 狀態為輸出
- DDRB|=0xff; //PB 狀態為輸出
- }
復制代碼
以上的程式只有一個注意點就是 :DS18B20 的轉啟動換頻率不要超過 750ms。其他的沒 有什么需要特別注意了。
14.12一個多點測溫的假想
以上是多點測溫的一個假想,就是利用 GND 作于片選的角色。該方法有一個好處就是可以省去猥瑣 的 ROM 指令,但是最為代價需要犧牲 IO 口,而且還控制好每一個 DS18B20 的執行次序。
|
評分
-
查看全部評分
|