專注電子技術(shù)學習與研究
當前位置:單片機教程網(wǎng) >> MCU設(shè)計實例 >> 瀏覽文章

51單片機驅(qū)動DS18B20溫度傳感器程序及心得

作者:huqin   來源:本站原創(chuàng)   點擊數(shù):  更新時間:2014年02月28日   【字體:

   關(guān)于DS18B20溫度傳感器,在沒有硬件設(shè)備的輔助下,寫內(nèi)部程序有些困難,因為看不到實際信號波形。對于單片機,我。。。漸漸的有些心灰意冷。。雖然掌握了1_WIRE總線,卻少了很多喜悅,下雨了。。。它是我的愛好,我付出了很多,可是我看不到實際的前景。。以我個人之力,要步入尖端芯片領(lǐng)域,很困難,在這里,采棉花是個普遍性的大問題,大型機械設(shè)備缺陷很多,如果以微控制芯片提高精度,我想效益會相當可觀,可是技術(shù)瓶頸難以逾越。。。硬件研發(fā),失敗了,所有投入赴之東流,成功了,回報豐厚。現(xiàn)在,各行各業(yè)都處于飽和,沒有成熟先進的技術(shù),很難有立足之地,,,,,我開始重新審視我的選擇。。。。。。艱難。。
    /*
  建立時間: 2013年5月2日;
  
 前言:  我用軟件仿真,測算延時時間,效果不錯,但是根據(jù)教程,復(fù)位時,先釋放總線
     (wd高電平),然后主機拉低wd,持續(xù)時間為400--960微妙.后主機拉高wd,持續(xù)15-
  60微妙,后 從機,會拉低電平持續(xù)時間是60--240微妙(此時表示復(fù)位成功),如果
  從機沒有將總線拉低,則復(fù)位失敗.然后,主機拉高電平60--240微妙.復(fù)位結(jié)束;
      可,實驗證明,在,從機,拉低總線電平后,持續(xù)一定時間,從機還會將總線拉高!這
   是教程中的一個重大錯誤!
   temperature sensor reset module finishing time:  23:08:00
     (   溫度     傳感器  復(fù)位  模塊     完成    時間  )
  temperature sensor  操作過程:
  1. reset DS18B20;
        2. 發(fā)出Skip ROM 命令(CCH); (跳躍ROM命令)
  3. 發(fā)出Convert T命令(44H); (溫度轉(zhuǎn)換命令)
  4. reset DS18B20;
  5. 發(fā)出Skip ROM命令(CCH);(跳躍ROM命令)
  6. 發(fā)出讀取命令(BEH);
  7. 讀出兩個字節(jié)的溫度;
  8. 溫度格式轉(zhuǎn)換;
 
    2013年5月8日22:56:44
 
  DS18B20 Temperature sensor read data module accomplish;
   (     溫度    傳感器 讀   數(shù)據(jù)  模塊    完成   )
 
  現(xiàn)在還有溫度顯示模塊沒有完成,硬件是1602液晶屏......
 2013年5月9日19:32:31
   今天,溫度傳感器的程序主體結(jié)構(gòu)全部完成!!!!!
 不容易啊,值得慶祝一下!!!!!!
 一共寫了7天程序!{陸陸續(xù)續(xù)};
 喝個  品酸乳果汁.......
*/
#include <reg52.h>
typedef unsigned char uint8 ;
typedef unsigned int uint16;

sbit wd = P3^2;  //定義數(shù)據(jù)單總線;
sbit e =P1^5; // 定義1602液晶顯示器數(shù)據(jù)使能端口;
sbit rs=P1^0; // 定義數(shù)據(jù)/指令選擇端口;
sbit rw=P1^1; // 定義  讀/寫  選擇端口;
sbit BF=P0^7; // 定義繁忙位;
bit w=0;  //定義一個全局一位變量;
 
//===========1602液晶顯示器模塊;===============
busy() //液晶屏繁忙檢測函數(shù);
{ e=0;
    rs=0;
 rw=0;
   P0=0xff;
  do
  { e=0;   //使能位清零;
    rs=0;   //指令;
 rw=1;   //讀;
 e=1;   //數(shù)據(jù)傳輸啟動;
  }while(BF); //如果BF==0;則液晶處于空閑狀態(tài);
   e=0;
}
play_data(uint8 wr) //液晶寫入數(shù)據(jù);
{
   busy();   //繁忙檢測;
   P0=wr;   //裝載數(shù)據(jù);
   rs=1;   //數(shù)據(jù);
   rw=0;   //寫入;
   e=1;    //傳輸開始;
   e=0;       //傳輸結(jié)束;
}
play_cmd(uint8 cmd)  //液晶寫入指令;
{
  busy(); //繁忙檢測;
  P0=cmd; //裝載數(shù)據(jù);
  rs=0;     //指令;
  rw=0;     //寫入;
  e=1;      //傳輸開始;
  e=0;      //傳輸結(jié)束;
}
reset_1602()   //1602液晶顯示器初始化函數(shù);
{
  play_cmd(0x38);
  play_cmd(0x0c);
  play_cmd(0x06);
  play_cmd(0x01);

}

//=========溫度傳感器延時模塊============================

// sbit led= P1^0;
delay(uint8 num )   //如果unm等于1;延時16.28微妙;
{
   while(num--);  //如果num大于一,則16.28+(num-1)*6.51.
}
delay2()    //此函數(shù)延時3.26微秒;
{
   uint8 j=0;
    j=9;
 
 
}

delay3()
{
   uint16 s=60000;
   while(s--);
 
 
}

reset_1820()  //========復(fù)位溫度傳感器; ========
{
 
  while(wd)
  {
   wd=1;
   delay(140);   //拉高總線,延時大概921微妙左右;(延時值自定);
   wd=0;    //總線由單片機拉低,下為延時函數(shù),大概800微秒左右;
   delay(61);  //1個此函數(shù)會延時400微妙左右;
   delay(61);  //兩個是800微妙左右;
   wd=1;    //主機拉高總線,68微秒左右;
   delay(9);      //延時68微妙左右
   if(wd==0)      //如果wd是0就終止復(fù)位;(代表復(fù)位成功);
    {
       while(wd==0);   //總線一旦為低,那么就等待從機再將總線拉高.
    break;    //終止while循環(huán);(reset function end)
    }
   else
     {
     wd=1;
     delay(20);    //延時140微妙;
  }  
   }
      delay(30); //此時總線為高電平并延時205微妙,復(fù)位成功!;
  // if(wd)led=0;//此語句為檢驗是否復(fù)位成功;P1^0外接9012三極管接led小燈;
}
 
write_byte(uint8 dat)
{
    uint8 i=0;
   
 for(i=0;i<8;i++)
      {
      wd=0;      //A點;
   delay2(); //延時
      wd=dat & 0x01;
      dat>>=1;
 
   delay(6);  //A點到此處用時65.11微秒;
   wd=1;   //總線釋放;
   delay2();  //延時3.26微秒;
   }
 }   //========此函數(shù)執(zhí)行完成之后總線為高電平;

uint8  read_byte() //=====讀8位數(shù)據(jù);===================
{
 uint8 j=0,  dat =0;
 
    for(j=0;j<8;j++)
  {
     dat>>=1;
   wd=0;  // A點  mcu拉低電平3.26微秒;
  delay2();   // 延時3.26微秒;
  wd=1; 
  if(wd)
   {
     dat|=0x80;
   }      //讀完數(shù)據(jù)后A點到此處是11.93微秒,保持在15微秒之內(nèi);
   delay(9);   // A點到此處80.29微秒; 理想時間范圍是60--120微秒;
   wd=1;  //釋放總線;
   delay2();  //延時3.26微秒;
  }
 
   return dat;

}

start_sensor()    //啟動傳感器;
{
  reset_1820();
  write_byte(0xcc);  //跳躍命令;
  write_byte(0x44);  //轉(zhuǎn)換temperature(溫度)命令;
}
uint8 read_temp()   //從溫度傳感器度溫度數(shù)據(jù)過程;
{
  uint8 ak[2];
  uint16  dat=0 , j=0;
    reset_1820();   //復(fù)位溫度傳感器
    write_byte(0xcc);  //跳躍rom命令;
    write_byte(0xbe) ;  // 發(fā)出讀數(shù)據(jù)命令;
    ak[0]=read_byte(); //讀取第一個字節(jié)數(shù)據(jù);
    ak[1]=read_byte(); //讀取第二個字節(jié)數(shù)據(jù);
    dat=ak[1];    //要把兩個八位數(shù)據(jù)載入1個16位變量里;
    dat<<=8;
    dat|=ak[0];
       j= dat;

  //==========以下是把溫度傳感器內(nèi)部數(shù)據(jù)編譯成16進制編碼;
     if((j>>11)==0x1f) //此語句是負溫度進入.0x1f是二進制5個全1;
  {
  dat=(~dat)+1;    //負溫度要取反加一操作;
  dat/=16;    //傳感器給的溫度系數(shù)要除以16后,得到的數(shù)才是常規(guī)溫度系數(shù);
  w=0;   //此語句是在主函數(shù)中用來判斷是正溫度還是負溫度;
  return dat;  //向主函數(shù)返回數(shù)據(jù),并終止函數(shù);
  }
     j=dat;
   if((j>>11)==0)   //如果是零則是正溫度;
     {
     dat/=16;    //數(shù)據(jù)直接除以16,就得到了常規(guī)溫度系數(shù);
     w=1;     //1代表正;
     return dat; //向主函數(shù)返回數(shù)據(jù),并終止函數(shù);
 
  }
 
   return 130;  //向主函數(shù)返回數(shù)據(jù),并終止函數(shù);
  
}

delay_ms()  //延時1秒;
{
  uint8 i=250;
  uint16 j=608;
   while(j--)
    { while(i--);
       i=250;
     
    }
 
}
 
error()  //測溫出錯;
{
   uint8 i=5, j=0 ,ak[]="Error!";
 
 while(i--)
 {
     play_cmd(0x82);
     while(ak[j]!='\0')
   {
     play_data(ak[j++]);
   }  j=0;
      delay3();
     play_cmd(0x01);
     delay3(); 
 }  
}

main()
{

  uint8 dat=0 ,j=3,len=0 ,num[]="start.....";
 
  reset_1602();
 
 while(j--)    //這是啟動電源時,液晶顯示:start....(并閃爍3次)
 {   play_cmd(0x82);
    while(num[len]!='\0')
     {
     play_data(num[len++]); 
  }
       len=0;
       delay3();
       play_cmd(0x01);
       delay3();
 }
 
 
 
 while(1)
   {   
     start_sensor();   //啟動溫度傳感器;
  delay_ms();    //等待1秒;
  dat = read_temp(); //讀取溫度數(shù)據(jù)并賦給dat變量;
 
   if(dat==130)    //如果返回來的數(shù)據(jù)是130,表明采集溫度出錯;
   {
     error();
   }
  else if(w==1)  //如果w是1,就代表正溫度.輸出;
   {
     play_cmd(0x83);
    play_data(dat/10+'0');
    play_data(dat%10+'0');
   }
   else    //否則,就是負溫度,輸出時前面加一個負號;
     {
    play_cmd(0x82);
    play_data('-');
    play_data(dat/10+'0');
    play_data(dat%10+'0');
  }
 
   } //我的親娘四舅奶奶啊!!!!!!終于完成了!!!!2013年5月9日19:32:10
 
 
   
}

關(guān)閉窗口

相關(guān)文章