找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4917|回復(fù): 6
收起左側(cè)

ds18b20溫度感應(yīng)詳解

[復(fù)制鏈接]
ID:68618 發(fā)表于 2014-11-11 19:04 | 顯示全部樓層 |閱讀模式
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); //稍微延遲
  }
}
*/

回復(fù)

使用道具 舉報

ID:7485 發(fā)表于 2014-11-13 18:46 | 顯示全部樓層
游客 183.69.216.x 發(fā)表于 2014-11-12 11:26
比較詳細,不錯,18B20最不好弄的是時間,比如1US的延時程序,不同的IC不同的晶振,沒有示波器的話,不太好 ...

沒有這么難吧?
只要按照資料上給出的時間隙編寫程序不會有問題的。時間隙的彈性還是比較大的。最好是使用匯編寫這一段。
回復(fù)

使用道具 舉報

ID:68356 發(fā)表于 2014-11-13 22:16 | 顯示全部樓層
學(xué)習(xí)了,收藏
回復(fù)

使用道具 舉報

ID:67678 發(fā)表于 2014-11-13 23:08 | 顯示全部樓層
學(xué)習(xí)了
謝謝
回復(fù)

使用道具 舉報

ID:75749 發(fā)表于 2015-3-30 23:56 | 顯示全部樓層
支持一下
回復(fù)

使用道具 舉報

ID:111517 發(fā)表于 2016-4-3 12:57 | 顯示全部樓層
請問下樓主那個讀“0”操作中的45us是做什么用的,可以不用嗎,讀取過后直接用個大于1us的延時(即兩個讀時序的恢復(fù)期),然后進行下次的讀操作可以嗎??
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表