1. 程式人生 > 實用技巧 >3.8 ds18b20溫度感測器實驗

3.8 ds18b20溫度感測器實驗

DS18B20是常用的數字溫度感測器,具有體積小,硬體開銷低,抗干擾能力強,精度高的特點。DS18B20 單線數字溫度感測器,即“一線器件”,其具有獨特的優點:
1,採用單匯流排的介面方式 與微處理器連線時僅需要一條口線即可實現微處理器與 DS18B20 的雙向通訊。單匯流排具有經濟性好,抗干擾能力強,適合於惡劣環境的現場溫度測量,使用方便等優點,使使用者可輕鬆地組建感測器網路,為測量系統的構建引入全新概念。
2,測量溫度範圍寬,測量精度高 DS18B20 的測量範圍為 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C範圍內,精度為 ± 0.5°C 。
3,在使用中不需要任何外圍元件。
4,持多點組網功能多個 DS18B20 可以並聯在惟一的單線上,實現多點測溫。
5,供電方式靈活 DS18B20 可以通過內部寄生電路從資料線上獲取電源。因此,當資料線上的時序滿足一定的要求時,可以不接外部電源,從而使系統結構更趨簡單,可靠性更高。
6,測量引數可配置 DS18B20 的測量解析度可通過程式設定 9~12 位。
7,負壓特性電源極性接反時,溫度計不會因發熱而燒燬。
8,掉電保護功能 DS18B20 內部含有 EEPROM ,在系統掉電以後,它仍可儲存解析度及報警溫度的設定值。
 DS18B20 具有體積更小、適用電壓更寬、更經濟、可選更小的封裝方式,更寬的電壓適用範圍,適合於構建自己的經濟的測溫系統,因此也就被設計者們所青睞。
  DS18B20內部結構:
  主要由4部分組成:64 位ROM、溫度感測器、非揮發的溫度報警觸發器TH和TL、配置暫存器。ROM中的64位序列號是出廠前被光刻好的,它可以看作是該DS18B20的地址序列碼,每個DS18B20的64位序列號均不相同。64位ROM的排的迴圈冗餘校驗碼(CRC=X8+X

5+X^4+1)。 ROM的作用是使每一個DS18B20都各不相同,這樣就可以實現一根總線上掛接多個DS18B20的目的。
首先建立讀取ds18b20的任務:

define TASK_SIZE 256

static OS_STK ds18b20_task_stk[TASK_SIZE];
void UserMain(void)
{

tls_os_task_create(NULL, NULL,
ds18b20_task,
NULL,
(void *)ds18b20_task_stk,
TASK_SIZE * sizeof(u32),
32,
0);
}
在任務中初始化DS18B20,並獲取DS18B20序列號後讀取溫度值。
static void ds18b20_task(void *data)
{
uint8_t uc, ucDs18b20Id [ 8 ];
int i;
printf("\r\n this is a ds18b20 test demo \r\n");

while( DS18B20_Init() )
{
	for(i=0;i<1000;i++)
	{
		us_delay(1000);
	}


printf("\r\n ds18b20 exit \r\n");
}
printf("\r\n ds18b20 ok  \r\n");
 DS18B20_ReadId ( ucDs18b20Id  );           // 讀取 DS18B20 的序列號

 printf("\r\nDS18B20: 0x");

 for ( uc = 0; uc < 8; uc ++ )             // 列印 DS18B20 的序列號
  printf ( "%.2x", ucDs18b20Id [ uc ] );

for( ; ; )
{

	 printf ( "\r\ntemperature: %.1f\r\n", DS18B20_GetTemp_MatchRom ( ucDs18b20Id ) );		// 列印通過 DS18B20 序列號獲取的溫度值
	 DS18B20_DELAY_MS(1000);
}

}
其它函式:

/**

  • @brief DS18B20 初始化函式

  • @param 無

  • @retval 無
    */
    uint8_t DS18B20_Init(void)
    {
    DS18B20_GPIO_Config ();

    DS18B20_DQ_1;

    DS18B20_Rst();

return DS18B20_Presence ();

}
/*

  • 函式名:DS18B20_GPIO_Config

  • 描述 :配置DS18B20用到的I/O口

  • 輸入 :無

  • 輸出 :無
    */
    static void DS18B20_GPIO_Config(void)
    {

    tls_gpio_cfg(DS18B20_DQ_GPIO_PORT, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);//配置為上拉輸出
    }

/*

  • 函式名:DS18B20_Mode_IPU
  • 描述 :使DS18B20-DATA引腳變為輸入模式
  • 輸入 :無
  • 輸出 :無
    */
    static void DS18B20_Mode_IPU(void)
    {
    tls_gpio_cfg(DS18B20_DQ_GPIO_PORT, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING);//配置為上拉輸出
    }

/*

  • 函式名:DS18B20_Mode_Out_PP
  • 描述 :使DS18B20-DATA引腳變為輸出模式
  • 輸入 :無
  • 輸出 :無
    */
    static void DS18B20_Mode_Out_PP(void)
    {
    tls_gpio_cfg(DS18B20_DQ_GPIO_PORT, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);//配置為上拉輸出
    }

/*
*主機給從機發送復位脈衝
/
static void DS18B20_Rst(void)
{
/
主機設定為推輓輸出 */
DS18B20_Mode_Out_PP();

DS18B20_DQ_0;
 /* 主機至少產生480us的低電平復位訊號 */
 us_delay(750);

 /* 主機在產生復位訊號後,需將匯流排拉高 */
 DS18B20_DQ_1;

 /*從機接收到主機的復位訊號後,會在15~60us後給主機發一個存在脈衝*/
 us_delay(15);

}

/*

  • 檢測從機給主機返回的存在脈衝

  • 0:成功

  • 1:失敗
    */
    static uint8_t DS18B20_Presence(void)
    {
    uint8_t pulse_time = 0;

    /* 主機設定為上拉輸入 */
    DS18B20_Mode_IPU();

    /* 等待存在脈衝的到來,存在脈衝為一個60~240us的低電平訊號

    • 如果存在脈衝沒有來則做超時處理,從機接收到主機的復位訊號後,會在15~60us後給主機發一個存在脈衝
      /
      while( DS18B20_DQ_IN() && pulse_time<100 )
      {
      pulse_time++;
      us_delay(1);
      }
      /
      經過100us後,存在脈衝都還沒有到來*/
      if( pulse_time >=100 )
      return 1;
      else
      pulse_time = 0;

    /* 存在脈衝到來,且存在的時間不能超過240us */
    while( !DS18B20_DQ_IN() && pulse_time<240 )
    {
    pulse_time++;
    us_delay(1);
    }
    if( pulse_time >=240 )
    return 1;
    else
    return 0;
    }

/*

  • 從DS18B20讀取一個bit
    */
    static uint8_t DS18B20_ReadBit(void)
    {
    uint8_t dat;

    /* 讀0和讀1的時間至少要大於60us /
    DS18B20_Mode_Out_PP();
    /
    讀時間的起始:必須由主機產生 >1us <15us 的低電平訊號 */
    DS18B20_DQ_0;
    us_delay(10);

    /* 設定成輸入,釋放匯流排,由外部上拉電阻將匯流排拉高 */
    DS18B20_Mode_IPU();
    //us_delay(2);

    if( DS18B20_DQ_IN() == SET )
    dat = 1;
    else
    dat = 0;

    /* 這個延時引數請參考時序圖 */
    us_delay(45);

    return dat;
    }

/*

  • 從DS18B20讀一個位元組,低位先行
    */
    static uint8_t DS18B20_ReadByte(void)
    {
    uint8_t i, j, dat = 0;

    for(i=0; i<8; i++)
    {
    j = DS18B20_ReadBit();
    dat = (dat) | (j<<i);
    }

    return dat;
    }

/*

  • 寫一個位元組到DS18B20,低位先行
    */
    static void DS18B20_WriteByte(uint8_t dat)
    {
    uint8_t i, testb;
    DS18B20_Mode_Out_PP();

    for( i=0; i<8; i++ )
    {
    testb = dat&0x01;
    dat = dat>>1;
    /* 寫0和寫1的時間至少要大於60us /
    if (testb)
    {
    DS18B20_DQ_0;
    /
    1us < 這個延時 < 15us */
    us_delay(8);

     	DS18B20_DQ_1;
     	us_delay(58);
     }
     else
     {
     	DS18B20_DQ_0;
     	/* 60us < Tx 0 < 120us */
     	us_delay(70);
    
     	DS18B20_DQ_1;
     	/* 1us < Trec(恢復時間) < 無窮大*/
     	us_delay(2);
     }
    

    }
    }

/**

  • @brief 跳過匹配 DS18B20 ROM

  • @param 無

  • @retval 無
    */
    static void DS18B20_SkipRom ( void )
    {
    DS18B20_Rst();

    DS18B20_Presence();

    DS18B20_WriteByte(0XCC); /* 跳過 ROM */

}

/**

  • @brief 執行匹配 DS18B20 ROM

  • @param 無

  • @retval 無
    */
    static void DS18B20_MatchRom ( void )
    {
    DS18B20_Rst();

    DS18B20_Presence();

    DS18B20_WriteByte(0X55); /* 匹配 ROM */

}

/*

  • 儲存的溫度是16 位的帶符號擴充套件的二進位制補碼形式

  • 當工作在12位解析度時,其中5個符號位,7個整數位,4個小數位

  •     |---------整數----------|-----小數 解析度 1/(2^4)=0.0625----|
    
  • 低位元組 | 2^3 | 2^2 | 2^1 | 2^0 | 2^(-1) | 2^(-2) | 2^(-3) | 2^(-4) |

  •     |-----符號位:0->正  1->負-------|-----------整數-----------|
    
  • 高位元組 | s | s | s | s | s | 2^6 | 2^5 | 2^4 |

  • 溫度 = 符號位 + 整數 + 小數*0.0625
    /
    /
    *

  • @brief 在跳過匹配 ROM 情況下獲取 DS18B20 溫度值

  • @param 無

  • @retval 溫度值
    */
    float DS18B20_GetTemp_SkipRom ( void )
    {
    uint8_t tpmsb, tplsb;
    short s_tem;
    float f_tem;

    DS18B20_SkipRom ();
    DS18B20_WriteByte(0X44); /* 開始轉換 */

    DS18B20_SkipRom ();
    DS18B20_WriteByte(0XBE); /* 讀溫度值 */

    tplsb = DS18B20_ReadByte();
    tpmsb = DS18B20_ReadByte();

    s_tem = tpmsb<<8;
    s_tem = s_tem | tplsb;

    if( s_tem < 0 ) /* 負溫度 */
    f_tem = (~s_tem+1) * 0.0625;
    else
    f_tem = s_tem * 0.0625;

    return f_tem;

}

/**

  • @brief 在匹配 ROM 情況下獲取 DS18B20 溫度值

  • @param ds18b20_id:用於存放 DS18B20 序列號的陣列的首地址

  • @retval 無
    */
    void DS18B20_ReadId ( uint8_t * ds18b20_id )
    {
    uint8_t uc;

    DS18B20_WriteByte(0x33); //讀取序列號

    for ( uc = 0; uc < 8; uc ++ )
    ds18b20_id [ uc ] = DS18B20_ReadByte();

}

/**

  • @brief 在匹配 ROM 情況下獲取 DS18B20 溫度值

  • @param ds18b20_id:存放 DS18B20 序列號的陣列的首地址

  • @retval 溫度值
    */
    float DS18B20_GetTemp_MatchRom ( uint8_t * ds18b20_id )
    {
    uint8_t tpmsb, tplsb, i;
    short s_tem;
    float f_tem;

    DS18B20_MatchRom (); //匹配ROM

for(i=0;i<8;i++)
DS18B20_WriteByte ( ds18b20_id [ i ] );

DS18B20_WriteByte(0X44);				/* 開始轉換 */


DS18B20_MatchRom ();            //匹配ROM

for(i=0;i<8;i++)
	DS18B20_WriteByte ( ds18b20_id [ i ] );

DS18B20_WriteByte(0XBE);				/* 讀溫度值 */

tplsb = DS18B20_ReadByte();
tpmsb = DS18B20_ReadByte();


s_tem = tpmsb<<8;
s_tem = s_tem | tplsb;

if( s_tem < 0 )		/* 負溫度 */
	f_tem = (~s_tem+1) * 0.0625;
else
	f_tem = s_tem * 0.0625;

return f_tem;

}
編譯下載到開發板執行: