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
首先建立讀取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;
} - 如果存在脈衝沒有來則做超時處理,從機接收到主機的復位訊號後,會在15~60us後給主機發一個存在脈衝
/*
-
從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;
}
編譯下載到開發板執行: