DS18B20是一種半雙工單總線通信方式,它共有6中信號(hào):復(fù)位脈沖,應(yīng)答脈沖,寫0,寫1,讀0和讀1。所有這些信號(hào),除了應(yīng)答脈沖以外,都是由主機(jī)發(fā)出同步信號(hào),并且發(fā)送所有的命令和數(shù)據(jù)都是字節(jié)的低位在前。
復(fù)位脈沖
單總線上的所有通信都是以初始化序列開始。主機(jī)輸出低電平,保持低電平時(shí)間至少480us,以產(chǎn)生復(fù)位脈沖,接著主機(jī)釋放總線,4.7K的上拉電阻將總線拉高,延時(shí)15~16us,并進(jìn)入接收模式。
//復(fù)位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //設(shè)置為輸出模式
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us(至少480us)
DS18B20_DQ_OUT=1; //DQ=1拉高釋放總線
delay_us(15); //15US
}
此時(shí)進(jìn)入接收模式,等待應(yīng)答信號(hào)。
應(yīng)答信號(hào)
將DS18B20總線拉低60~240us,產(chǎn)生低電平應(yīng)答脈沖。
等待DS18B20的回應(yīng)
//返回1:未檢測(cè)到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//SET PA0INPUT
while(DS18B20_DQ_IN&&retry<200)// DS18B20_DQ_IN的作用為讀引腳,觀察其是否為低電平
{
retry++;//如果為高電平,則retry++
delay_us(1);
}
if(retry>=200)//未檢測(cè)到18B20
{
return 1;
}
else
{
retry=0;
}
while(!DS18B20_DQ_IN&&retry<240)
{
retry++;//低電平時(shí)retry++
delay_us(1);
}
if(retry>=240)return1;//由于拉低總線的時(shí)間在60~240us,大于240則沒檢測(cè)到18B20
return 0;
}
寫時(shí)序
寫時(shí)序包括寫0時(shí)序和寫1時(shí)序。所有寫時(shí)序至少需要60us,且在兩次獨(dú)立的寫時(shí)序之間需要1us的恢復(fù)時(shí)間,兩種寫時(shí)序均起始于主機(jī)拉低總線。
寫1時(shí)序:主機(jī)輸出低電平,延時(shí)2us,然后釋放總線,延時(shí)60us。
寫0時(shí)序:主機(jī)輸出低電平,延時(shí)60us,然后釋放總線,延時(shí)2us。
//寫一個(gè)字節(jié)到DS18B20
//dat:要寫入的字節(jié)
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//設(shè)置IO口為輸出
for (j=1;j<=8;j++) //八位數(shù)據(jù),一位一位寫
{
testb=dat&0x01;//取第一位數(shù)據(jù)
dat=dat>>1;//移位
if (testb) //輸出高
{
DS18B20_DQ_OUT=0;//主機(jī)輸出低電平
delay_us(2);//延時(shí)2us
DS18B20_DQ_OUT=1;
delay_us(60); //延時(shí)60us
}
else//輸出低
{
DS18B20_DQ_OUT=0;//主機(jī)輸出低電平
delay_us(60);
DS18B20_DQ_OUT=1;//釋放總線
delay_us(2);
}
}
}
讀時(shí)序
單總線器件僅在主機(jī)發(fā)出讀時(shí)序時(shí),才向主機(jī)傳輸數(shù)據(jù),所以,在主機(jī)發(fā)出讀數(shù)據(jù)命令后,必須馬上產(chǎn)生讀時(shí)序,以便從機(jī)能傳輸數(shù)據(jù)。
所有讀時(shí)序至少需要60us,且在2次獨(dú)立的讀時(shí)序之間至少需要1us的恢復(fù)時(shí)間。每個(gè)讀時(shí)序都由主機(jī)發(fā)起,至少拉低總線1us。主機(jī)在讀時(shí)序期間必須釋放總線,并且在時(shí)序起始后的15us之內(nèi)采樣總線狀態(tài)。
典型的讀時(shí)序過程為:主機(jī)輸出低電平延時(shí)2us,然后主機(jī)轉(zhuǎn)入輸入模式延時(shí)12us,然后讀取單總線當(dāng)前的電平,然后延時(shí)50us。
//從DS18B20讀取一個(gè)位
//返回值:1/0
u8 DS18B20_Read_Bit(void)
{
u8 data;
DS18B20_IO_OUT();//設(shè)置IO口為輸出
DS18B20_DQ_OUT=0; //輸出低電平2us
delay_us(2);
DS18B20_DQ_OUT=1; //拉高釋放總線
DS18B20_IO_IN();//設(shè)置IO口為輸入
delay_us(12);//延時(shí)12us
if(DS18B20_DQ_IN)data=1;//讀取總線數(shù)據(jù)(當(dāng)前電平)
else data=0;
delay_us(50);//延時(shí)50us
return data;
}
//從DS18B20讀取一個(gè)字節(jié)
//返回值:讀到的數(shù)據(jù)
u8 DS18B20_Read_Byte(void)
{
u8 i,j,dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
DS18B20是如何讀取
現(xiàn)在我們來看看DS18B20是怎么讀取溫度的,DS18B20的典型溫度讀取過程為:復(fù)位->發(fā)SKIP ROM命令(0XCC)->發(fā)開始轉(zhuǎn)換命令(0X44)->延時(shí)->復(fù)位->發(fā)送SKIP ROM命令(0XCC)->發(fā)讀存儲(chǔ)器命令(0XBE)->連續(xù)讀出兩個(gè)字節(jié)數(shù)據(jù)(即溫度)->結(jié)束。
//從ds18b20得到溫度值
//精度:0.1C
//返回值:溫度值(-550~1250)
short
DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();//復(fù)位
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);//convert
TL=DS18B20_Read_Byte();// LSB
TH=DS18B20_Read_Byte();// MSB
if(TH>7)//(TH>xxxxx111)溫度為負(fù)
{
TH=~TH;TL=~TL;
temp=0;
}
else temp=1;//溫度為正
tem=TH;//獲得高八位
tem<<=8;
tem+=TL;//獲得底八位
tem=(float)tem*0.625;//轉(zhuǎn)換
if(temp) return tem; //返回溫度值
else return -tem;
}
其中
void
DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
緊接著我們來講后面有關(guān)溫度計(jì)算的問題,首先,我們用DS18B20_Read_Byte()函數(shù)讀取兩個(gè)字節(jié)的溫度,先低后高。
DS18B20 能夠提供兩個(gè)字節(jié)的溫度數(shù)據(jù),共16位數(shù)。但是因?yàn)?8B20是單總線的,數(shù)據(jù)都是一位一位傳輸?shù)摹C看巫x出的操作,DS18B20 僅僅送出8位數(shù)。必須讀出兩次,才能完整的讀出16位數(shù)。兩次讀出時(shí),DS18B20 先輸出的是低八位,后輸出的是高八位。這是器件本身的特性。
轉(zhuǎn)化后得到的12位數(shù)據(jù),存儲(chǔ)在18B20的兩個(gè)8比特的RAM中,二進(jìn)制中的前面5位是符號(hào)位,如果測(cè)得的溫度大于0,這5位為0,只要將測(cè)得的數(shù)值乘以0.0625即可得到實(shí)際溫度;如果溫度小于0,這五位為1,檢測(cè)到的數(shù)值需要取反加1再乘以0.0625即可得到實(shí)際溫度。(源碼中0.625是因?yàn)橐WC精度,在主函數(shù)中溫度有除以10,所以相當(dāng)于0.0625)
由上圖可以看出前五位為符號(hào)位。
主函數(shù)中初始化DS18B20的函數(shù)如下:
//初始化DS18B20的IO口DQ 同時(shí)檢測(cè)DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA時(shí)鐘
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0;//PORTA0 推挽輸出
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0); //輸出1
DS18B20_Rst();
return DS18B20_Check();//未檢測(cè)到DS18B20則返回1
}
既然學(xué)到了這里,想必大家對(duì)這個(gè)都十分熟悉,這里我就不再多說。
以上,DS18B20讀取溫度的方式就講完了。學(xué)會(huì)使用這些函數(shù),就可以在主函數(shù)中調(diào)用他們來讀取外界溫度。