DS18B20是一種常用的溫度傳感器,可以實現(xiàn)多點網(wǎng)絡(luò)式測量,這里簡單介紹單個ds18b20的使用。 DS18B20看起來像一個三極管,有三個引腳,1:地,2:數(shù)據(jù)端,3:電源,DS18B20的通信方式有點特別,僅靠一根線進行通信,而且多個DS18B20也是連在一個線上的,所以通信協(xié)議僅靠高低電平實現(xiàn),而且速度較慢,因為傳輸數(shù)據(jù)較少,所以時間還是可以忍受。 
簡單起見,這里介紹單個DS18B20的使用方法,忽略地址匹配等方法,下面結(jié)合程序,說明一下主流程:unsigned int ds18b20_read_temperature(void)
{
unsigned int temperature;
ds18b20_init(); //初始化(復(fù)位)
ds18b20_write_byte(0xCC); //發(fā)送命令,跳過ROM
ds18b20_write_byte(0x44); //溫度轉(zhuǎn)換
delayms(1000); //給必要的轉(zhuǎn)換時間
ds18b20_init(); //DS1302 復(fù)位
ds18b20_write_byte(0xCC); //跳過ROM
ds18b20_write_byte(0xbe); //讀取RAM
temperature = ds18b20_read_byte(); //讀低八位,LS Byte, RAM0
temperature |= ds18b20_read_byte() << 8; //讀高八位,MS Byte, RAM1
return temperature*0.0625; //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
}
很簡單,啟動溫度轉(zhuǎn)換,等待,讀取結(jié)果。
下面介紹DS18B20的單線通信方式:
這個要細細研究手冊的時序圖,才能寫好程序。
1.DS18B20的復(fù)位:

總線先給一個480us的低電平,等待15-60us,DS18B20會有一個60-240us的低電平響應(yīng),注意用時候可能因為軟件或硬件的問題,并沒有使DS18B20成功初始化,這樣程序會進入無限等待的死循環(huán)里,這里為了防止死循環(huán)的發(fā)生,使用最大延時限制,一旦延時到且初始化未成功,就重新初始化。
程序如下:void ds18b20_init(void)
{
int i;
again: //這里為了方便,用了一個C語言的禁忌指令:goto label
TD = 1; //T 為輸出狀態(tài)
TO = 0; //輸出低電平
delayus(500); //延遲480~960 us
TO = 1; //釋放總線
TD = 0; //DQ 位輸狀入態(tài)
#define MAX 480 //定義一個最大延時數(shù),防止死循環(huán)
for(i=MAX;i>0;i--)
{
if(!TI) break;//檢測到低電平,跳到下一步
}
if(i == 0) goto again;//最大延時到,重新檢測
for(i=MAX;i>0;i--)
{
if(TI) break;//檢測到高電平,跳到下一步
}
if(i == 0) goto again;//最大延時到,重新檢測
}
2.向DS18B20寫一位:
如果寫0,則給60~120us的低電平;如果寫1,先給至少1us的低電平,然后給高電平,直至60us。 void write_bit(char b)
{
TD = 1;
TO = 0;//拉低總線
delayus(2); //至少1us
TO = !!b; // !!是為了把非零數(shù)轉(zhuǎn)換 為1
delayus(58); //保證60us
TO = 1; //釋放總線
} 3.讀DS18B20一位:
先給至少1us的低電平,然后在15us內(nèi)讀取,高為1,低為0,在等待,直至60us。
char read_bit(void)
{
char b;
TD = 1;//置位輸出
TO = 0;//拉低總線,至少1us
delayus(2);
TO = 1;
TD = 0;//置位輸入
delayus(4);//必須在15us內(nèi)讀取
b = TI;
delayus(54);
TD = 1;//置位輸出
TO = 1;//釋放總線
return b;
}
下面是完整的程序:
編譯器:IAR
單片機:ATmega32 或 16
#include "main.h" //定義 T 引腳
#define TD DDRC_Bit7
#define TO PORTC_Bit7
#define TI PINC_Bit7 //根據(jù)時序圖,先給至少1us的低電平,
//寫1則拉高 直至60us
//寫0則繼續(xù)保持 直至60us
void write_bit(char b)
{
TD = 1;
TO = 0;//拉低總線
delayus(2); //至少1us
TO = !!b; // !!是為了把非零數(shù)轉(zhuǎn)換 為1
delayus(58); //保證60us
TO = 1; //釋放總線
} void ds18b20_write_byte(char val)
{
char i;
for(i=0;i<8;i++)
{
write_bit( val&(1<<i) );
}
} //根據(jù)時序圖,先給至少1us的低電平,
//然后在15us內(nèi)讀取
//高為1 直至60us
//低為0 直至60us
char read_bit(void)
{
char b;
TD = 1;//置位輸出
TO = 0;//拉低總線,至少1us
delayus(2);
TO = 1;
TD = 0;//置位輸入
delayus(4);//必須在15us內(nèi)讀取
b = TI;
delayus(54);
TD = 1;//置位輸出
TO = 1;//釋放總線
return b;
} char ds18b20_read_byte(void)
{
char i;
char value=0; //讀出溫度
for(i=0;i<8;i++)
{
value |= read_bit() << i;
}
return(value);
} //根據(jù)時序圖,先給一個480~960us的低電平,然后釋放總線等待DS18B20響應(yīng)(一個低脈沖)
//為了穩(wěn)定性,使用延時循環(huán)以防止了死循環(huán)的發(fā)生
void ds18b20_init(void)
{
int i;
again: //這里為了方便,用了一個C語言的禁忌指令:goto label
TD = 1; //T 為輸出狀態(tài)
TO = 0; //輸出低電平
delayus(500); //延遲480~960 us
TO = 1; //釋放總線
TD = 0; //DQ 位輸狀入態(tài)
#define MAX 480 //定義一個最大延時數(shù),防止死循環(huán)
for(i=MAX;i>0;i--)
{
if(!TI) break;//檢測到低電平,跳到下一步
}
if(i == 0) goto again;//最大延時到,重新檢測
for(i=MAX;i>0;i--)
{
if(TI) break;//檢測到高電平,跳到下一步
}
if(i == 0) goto again;//最大延時到,重新檢測
} unsigned int ds18b20_read_temperature(void)
{
unsigned int temperature;
ds18b20_init();
ds18b20_write_byte(0xCC); //跳過ROM
ds18b20_write_byte(0x44); //溫度轉(zhuǎn)換
delayms(1000);//給必要的轉(zhuǎn)換時間
ds18b20_init(); //DS1302 復(fù)位
ds18b20_write_byte(0xCC); //跳過ROM
ds18b20_write_byte(0xbe); //讀取RAM
temperature = ds18b20_read_byte(); //讀低八位,LS Byte, RAM0
temperature |= ds18b20_read_byte() << 8; //讀高八位,MS Byte, RAM1
return temperature*0.0625; //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
}
/*
int main( void )
{
unsigned int Temp;
while(1)
{
Temp = ds18b20_read_temperature(); //調(diào)用讀取溫度函數(shù)
// delayus(100); //稍微延遲
}
} */
|