DS18B20數(shù)字傳感器學(xué)習(xí)筆記

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 先輸出的是低八位,后輸出的是高八位。這是器件本身的特性。

1.jpg

轉(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)

2.jpg

由上圖可以看出前五位為符號(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)用他們來讀取外界溫度。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容