本文檔參照Maxim公司DS18B20的Datasheet而完成。其中,加了灰框的部分為原文檔內(nèi)容,其中英文部分為官方文檔內(nèi)容,中文部分為本人的翻譯。限于本人水平,本文檔可能存在錯誤或者讓人誤解的內(nèi)容,對于因此引起的一切問題作者概不負(fù)責(zé)。
INITIALIZATION PROCEDURE—RESET AND PRESENCE PULSES
初始化序列——復(fù)位和存在脈沖
All communication with the DS18B20 begins with an initialization sequence that consists of a reset pulse from the master followed by a presence pulse from the DS18B20. This is illustrated in Figure 13. When the DS18B20 sends the presence pulse in response to the reset, it is indicating to the master that it is on the bus and ready to operate.
DS18B20的所有通信都由由復(fù)位脈沖組成的初始化序列開始。該初始化序列由主機(jī)發(fā)出,后跟由DS18B20發(fā)出的存在脈沖(presence pulse)。下圖(即如下截圖)闡述了這一點(diǎn)。當(dāng)發(fā)出應(yīng)答復(fù)位脈沖的存在脈沖后,DS18B20通知主機(jī)它在總線上并且準(zhǔn)備好操作了。
During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus low for a minimum of 480μs. The bus master then releases the bus and goes into receive mode (RX).
在初始化步驟中,總線上的主機(jī)通過拉低單總線至少480μs來產(chǎn)生復(fù)位脈沖。然后總線主機(jī)釋放總線并進(jìn)入接收模式。
When the bus is released, the 5kΩ pullup resistor pulls the 1-Wire bus high. When the DS18B20 detects this rising edge, it waits 15μs to 60μs and then transmits a presence pulse by pulling the 1-Wire bus low for 60μs to 240μs.
當(dāng)總線釋放后,5kΩ的上拉電阻把單總線上的電平拉回高電平。當(dāng)DS18B20檢測到上升沿后等待15到60us,然后以拉低總線60-240us的方式發(fā)出存在脈沖。
如文檔所述,主機(jī)將總線拉低最短480us,之后釋放總線。由于5kΩ上拉電阻的作用,總線恢復(fù)到高電平。DS18B20檢測到上升沿后等待15到60us,發(fā)出存在脈沖:拉低總線60-240us。至此,初始化和存在時序完畢。
根據(jù)上述要求編寫的復(fù)位函數(shù)為:
首先是延時函數(shù):(由于DS18B20延時均以15us為單位,故編寫了延時單位為15us的延時函數(shù),注意:以下延時函數(shù)晶振為12MHz)
void Delayxus_DS18B20(unsigned int t)
{
for(t;t>0;t--)
{
_nop_();_nop_();_nop_();_nop_();
}
_nop_(); _nop_();
}
延時函數(shù)反匯編代碼(方便分析延時公式)
C:0x0031 7F01 MOV R7,#0x01
C:0x0033 7E00 MOV R6,#0x00
C:0x0035 1206A6 LCALL delayxus(C:06A6)
38: void Delayxus_DS18B20(unsigned int t)
39: {
40: for(t;t>0;t--)
C:0x06A6 D3 SETB C
C:0x06A7 EF MOV A,R7
C:0x06A8 9400 SUBB A,#0x00
C:0x06AA EE MOV A,R6
C:0x06AB 9400 SUBB A,#0x00
C:0x06AD 400B JC C:06BA
41: {
42: _nop_();_nop_();_nop_();_nop_();
C:0x06AF 00 NOP
C:0x06B0 00 NOP
C:0x06B1 00 NOP
C:0x06B2 00 NOP
43: }
C:0x06B3 EF MOV A,R7
C:0x06B4 1F DEC R7
C:0x06B5 70EF JNZ Delayxus_DS18B20 (C:06A6)
C:0x06B7 1E DEC R6
C:0x06B8 80EC SJMP Delayxus_DS18B20 (C:06A6)
44: _nop_(); _nop_();
C:0x06BA 00 NOP
C:0x06BB 00 NOP
45: }
C:0x06BC 22 RET
分析上述反匯編代碼,可知延時公式為15*(t+1)
bit RST_DS18B20()
{
bit ret="1";
DQ=0;
Delayxus_DS18B20(32);
DQ=1;
Delayxus_DS18B20(4);
ret=DQ;
Delayxus_DS18B20(14);
DQ=1;
return(~ret);
}
寫時序:
READ/WRITE TIME SLOTS
讀寫時隙
The bus master writes data to the DS18B20 during write time slots and reads data from the DS18B20 during read time slots. One bit of data is transmitted over the 1-Wire bus per time slot.
主機(jī)在寫時隙向DS18B20寫入數(shù)據(jù),并在讀時隙從DS18B20讀入數(shù)據(jù)。在單總線上每個時隙只傳送一位數(shù)據(jù)。
WRITE TIME SLOTS
寫時間隙
There are two types of write time slots: “Write 1” time slots and “Write 0” time slots. The bus master uses a Write 1 time slot to write a logic 1 to the DS18B20 and a Write 0 time slot to write a logic 0 to the DS18B20. All write time slots must be a minimum of 60μs in duration with a minimum of a 1μs recovery
time between individual write slots. Both types of write time slots are initiated by the master pulling the 1-Wire bus low (see Figure 14).
有兩種寫時隙:寫“0”時間隙和寫“1”時間隙??偩€主機(jī)使用寫“1”時間隙向DS18B20寫入邏輯1,使用寫“0”時間隙向DS18B20寫入邏輯0.所有的寫時隙必須有最少60us的持續(xù)時間,相鄰兩個寫時隙必須要有最少1us的恢復(fù)時間。兩種寫時隙都通過主機(jī)拉低總線產(chǎn)生。
To generate a Write 1 time slot, after pulling the 1-Wire bus low, the bus master must release the 1-Wire bus within 15μs. When the bus is released, the 5kΩ pullup resistor will pull the bus high. To generate a Write 0 time slot, after pulling the 1-Wire bus low, the bus master must continue to hold the bus low for the duration of the time slot (at least 60μs).
為產(chǎn)生寫1時隙,在拉低總線后主機(jī)必須在15μs內(nèi)釋放總線。在總線被釋放后,由于5kΩ上拉電阻的作用,總線恢復(fù)為高電平。為產(chǎn)生寫0時隙,在拉低總線后主機(jī)必須繼續(xù)拉低總線以滿足時隙持續(xù)時間的要求(至少60μs)。
The DS18B20 samples the 1-Wire bus during a window that lasts from 15μs to 60μs after the master initiates the write time slot. If the bus is high during the sampling window, a 1 is written to the DS18B20. If the line is low, a 0 is written to the DS18B20.
在主機(jī)產(chǎn)生寫時隙后,DS18B20會在其后的15到60us的一個時間窗口內(nèi)采樣單總線。在采樣的時間窗口內(nèi),如果總線為高電平,主機(jī)會向DS18B20寫入1;如果總線為低電平,主機(jī)會向DS18B20寫入0。
如文檔所述,所有的寫時隙必須至少有60us的持續(xù)時間。相鄰兩個寫時隙必須要有最少1us的恢復(fù)時間。所有的寫時隙(寫0和寫1)都由拉低總線產(chǎn)生。
為產(chǎn)生寫1時隙,在拉低總線后主機(jī)必須在15us內(nèi)釋放總線(拉低的電平要持續(xù)至少1us)。由于上拉電阻的作用,總線電平恢復(fù)為高電平,直到完成寫時隙。
為產(chǎn)生寫0時隙,在拉低總線后主機(jī)持續(xù)拉低總線即可,直到寫時隙完成后釋放總線(持續(xù)時間60-120us)。
寫時隙產(chǎn)生后,DS18B20會在產(chǎn)生后的15到60us的時間內(nèi)采樣總線,以此來確定寫0還是寫1。
滿足上述要求的寫函數(shù)為:
void WR_Bit(bit i)
{
DQ=0;//產(chǎn)生寫時序
_nop_();
_nop_();//總線拉低持續(xù)時間要大于1us
DQ=i;//寫數(shù)據(jù) ,0和1均可
Delayxus_DS18B20(3);//延時60us,等待ds18b20采樣讀取
DQ=1;//釋放總線
}
void WR_Byte(unsigned char dat)
{
unsigned char i="0";
while(i++<8)
{
WR_Bit(dat&0x01);//從最低位寫起
dat>>=1; //注意不要寫成dat>>1
}
}讀時序:
READ TIME SLOTS
讀時間隙
The DS18B20 can only transmit data to the master when the master issues read time slots. Therefore, the master must generate read time slots immediately after issuing a Read Scratchpad [BEh] or Read Power Supply [B4h] command, so that the DS18B20 can provide the requested data. In addition, the master can generate read time slots after issuing Convert T [44h] or Recall
E 2[B8h] commands to find out the status of the operation as explained in the DS18B20 Function Commands section.
DS18B20只有在主機(jī)發(fā)出讀時隙后才會向主機(jī)發(fā)送數(shù)據(jù)。因此,在發(fā)出讀暫存器命令 [BEh]或讀電源命令[B4h]后,主機(jī)必須立即產(chǎn)生讀時隙以便DS18B20提供所需數(shù)據(jù)。另外,主機(jī)可在發(fā)出溫度轉(zhuǎn)換命令T [44h]或Recall命令E 2[B8h]后產(chǎn)生讀時隙,以便了解操作的狀態(tài)(在 DS18B20操作指令這一節(jié)會詳細(xì)解釋)。
All read time slots must be a minimum of 60μs in duration with a minimum of a 1μs recovery time between slots. A read time slot is initiated by the master device pulling the 1-Wire bus low for a minimum of 1μs and then releasing the bus (see Figure 14). After the master initiates the read time slot, the DS18B20 will begin transmitting a 1 or 0 on bus. The DS18B20 transmits a 1 by leaving the bus high and transmits a 0 by pulling the bus low. When transmitting a 0, the DS18B20 will release the bus by the end of the time slot, and the bus will be pulled back to its high idle state by the pullup resister. Output data from the DS18B20 is valid for 15μs after the falling edge that initiated the read time slot. Therefore, the master must release the bus and then sample the bus state within 15μs from the start of the slot.
所有的讀時隙必須至少有60us的持續(xù)時間。相鄰兩個讀時隙必須要有最少1us的恢復(fù)時間。所有的讀時隙都由拉低總線,持續(xù)至少1us后再釋放總線(由于上拉電阻的作用,總線恢復(fù)為高電平)產(chǎn)生。在主機(jī)產(chǎn)生讀時隙后,DS18B20開始發(fā)送0或1到總線上。DS18B20讓總線保持高電平的方式發(fā)送1,以拉低總線的方式表示發(fā)送0.當(dāng)發(fā)送0的時候,DS18B20在讀時隙的末期將會釋放總線,總線將會被上拉電阻拉回高電平(也是總線空閑的狀態(tài))。DS18B20輸出的數(shù)據(jù)在下降沿(下降沿產(chǎn)生讀時隙)產(chǎn)生后15us后有效。因此,主機(jī)釋放總線和采樣總線等動作要在15μs內(nèi)完成。
Figure 15 illustrates that the sum of TINIT, TRC, and TSAMPLE must be less than 15μs for a read time slot.
插圖15表明了對于讀時隙,TINIT(下降沿后低電平持續(xù)時間), TRC(上升沿)和TSAMPLE(主機(jī)采樣總線)的時間和要在15μs以內(nèi)。
Figure 16 shows that system timing margin is maximized by keeping TINIT and TRC as short as possible and by locating the master sample time during read time slots towards the end of the 15μs period.
下圖顯示了最大化系統(tǒng)時間寬限的方法:讓TINIT 和TRC盡可能的短,把主機(jī)采樣總線放到15μs這一時間段的尾部。
由文檔可知,DS18B20只有在主機(jī)發(fā)出讀時隙時才能發(fā)送數(shù)據(jù)到主機(jī)。因此,主機(jī)必須在BE命令,B4命令后立即產(chǎn)生讀時隙以使DS18B20提供相應(yīng)的數(shù)據(jù)。另外,在44命令,B8命令后也要產(chǎn)生讀時隙。
所有的讀時隙必須至少有60us的持續(xù)時間。相鄰兩個讀時隙必須要有最少1us的恢復(fù)時間。所有的讀時隙都由拉低總線,持續(xù)至少1us后再釋放總線(由于上拉電阻的作用,總線恢復(fù)為高電平)產(chǎn)生。DS18B20輸出的數(shù)據(jù)在下降沿產(chǎn)生后15us后有效。因此,釋放總線和主機(jī)采樣總線等動作要在15us內(nèi)完成。
滿足以上要求的函數(shù)為:
unsigned char Read_Bit()
{
unsigned char ret;
DQ=0;//拉低總線
_nop_(); _nop_();
DQ=1;//釋放總線
_nop_(); _nop_();
_nop_(); _nop_();
ret=DQ;//讀時隙產(chǎn)生7 us后讀取總線數(shù)據(jù)。把總線的讀取動作放在15us時間限制的后面是為了保證數(shù)據(jù)讀取的有效性
Delayxus_DS18B20(3);//延時60us,滿足讀時隙的時間長度要求
DQ=1;//釋放總線
return ret; //返回讀取到的數(shù)據(jù)
}
unsigned char Read_Byte()
{
unsigned char i;
unsigned char dat="0";
for(i=0;i<8;i++)
{
dat>>=1;//先讀最低位
if(Read_Bit())
dat|=0x80;
}
return(dat);
}
void Start_DS18B20()
{
DQ=1;
RST_DS18B20();
WR_Byte(0xcc);// skip
WR_Byte(0x44);//啟動溫度轉(zhuǎn)換
}
int Read_Tem()
{
int tem="0";
RST_DS18B20();
WR_Byte(0xcc);// skip
WR_Byte(0xbe);//發(fā)出讀取命令
tem=Read_Byte();//讀出溫度低八位
tem|=(((int)Read_Byte())<<8);//讀出溫度高八位
return tem;
}
注: DS18B20官方文檔中沒有說明讀寫數(shù)據(jù)位的順序,查了下資料,DS18B20讀寫數(shù)據(jù)都是從最低位讀寫的。
*共陽極4位數(shù)碼管顯示,請根據(jù)自己的電路圖再定義端口*/
#i nclude
sbit warmer=P1^4;
sbit led_run=P1^0;
//sbit k_power=P3^3;
sbit zf=P2^0;
sbit bai=P2^1;
sbit shi=P2^2;
sbit ge=P2^3;
sbit dots=P2^4;
sbit xs=P2^5;
sbit DQ =P3^3; //定義通信端口
//延時函數(shù)
unsigned char tab[]={ 0xc0,0xf9,0xa4,0xb0, // 0, 1, 2, 3
0x99,0x92,0x82,0xf8,0x80,0x90, 0xff};
//4 5 6 7 8 9
unsigned int t=0;
unsigned char tflag;
unsigned char data disdata[4];
void delay(unsigned char i)
{
while(i--);
}
//初始化函數(shù)
Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1; //DQ復(fù)位
delay(8); //稍做延時
DQ = 0; //單片機(jī)將DQ拉低
delay(80); //精確延時 大于 480us
DQ = 1; //拉高總線
delay(14);
x=DQ; //稍做延時后 如果x=0則初始化成功 x=1則初始化失敗
delay(20);
}
//讀一個字節(jié)
ReadOneChar(void)
{
unsigned char i=0;
unsigned char dat = 0;
for (i=8;i>0;i--)
{
DQ = 0; // 給脈沖信號
dat>>=1;
DQ = 1; // 給脈沖信號
if(DQ)
dat|=0x80;
delay(4);
}
return(dat);
}
//寫一個字節(jié)
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;
delay(5);
DQ = 1;
dat>>=1;
}
delay(4);
}
//讀取溫度
ReadTemperature(void)
{
unsigned char a=0;
unsigned char b=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳過讀序號列號的操作 發(fā)送指令0xcc
WriteOneChar(0x44); // 啟動溫度轉(zhuǎn)換 發(fā)送指令0x44
Init_DS18B20();
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度 發(fā)送指令0xbe
a=ReadOneChar(); //讀取溫度值低位
b=ReadOneChar(); //讀取溫度值高位
t=b;
t<<=8; //值左移8位
//a=a>>4; //低位右移4位,舍棄小數(shù)部分
//t=b<<4; //高位左移4位,舍棄符號位
//t=t|a;
t=t|a; //合并高低位數(shù)值
if(t<0xfff)
tflag=1;
else
{
tflag=0;
t=~t+1; //負(fù)值換算
}
t=t*(0.625); //溫度擴(kuò)大10倍,精確到1位小數(shù)
return(t);
}
void display_temper(unsigned int i)
{
disdata[0]=i/1000; //百位數(shù)
disdata[1]=i00/100; //十位數(shù)
disdata[2]=i0/10; //個位數(shù)
disdata[3]=i; //小數(shù)位
if(tflag==1)
tflag=0xff; //正號,不顯示
else
tflag=0xbf; //負(fù)號,顯示-
P2=0xff;
zf=0;
P0=tflag;
delay(150);
P0=0xff;
zf=1;
bai=0;
if(disdata[0]>0)P0=tab[disdata[0]];
delay(150);
bai=1;
shi=0;
P0=tab[disdata[1]];
delay(150);
shi=1;
ge=0;
P0=tab[disdata[2]];
delay(100);
ge=1;
dots=0;
P0=0x7f;
delay(150);
dots=1;
xs=0;
P0=tab[disdata[3]];
delay(150);
P0=0xff;
P2=0xff;
}
void main(void)
{unsigned int temp;
while(1) //主循環(huán)
{ temp=ReadTemperature();
display_temper(temp);
}
}