STM32F407VET6 -- FreeRTOS -- DS18B20溫度檢測
1、DS18B20 單線數字溫度傳感器,即“一線器件”,其具有獨特的優點:
a、采用單總線的接口方式 與微處理器連接時僅需要一根線即可實現微處理器與 DS18B20 的雙向通訊。單總線具有經濟性好,抗干擾能力強,適合於惡劣環境的現場溫度測量。
b、測量溫度范圍寬,測量精度高 DS18B20 的測量范圍為 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C范圍內,精度為 ± 0.5°C 。
c、在使用中不需要任何外圍元件。
d、支持多點組網功能,多個 DS18B20 可以並聯在惟一的單線上,實現多點測溫。
e、供電方式靈活 DS18B20 可以通過內部寄生電路從數據線上獲取電源。因此,當數據線上的時序滿足一定的要求時,可以不接外部電源,從而使系統結構更趨簡單,可靠性更高。
f、測量參數可配置 DS18B20 的測量分辨率可通過程序設定 9~12 位。
g、負壓特性電源極性接反時,溫度計不會因發熱而燒毀,但不能正常工作。
h、掉電保護功能 DS18B20 內部含有 EEPROM ,在系統掉電以后,它仍可保存分辨率及報警溫度的設定值。
2、DS18B20內部結構:
DS18B20內部主要包括,64位ROM、2字節溫度輸出寄存器、1字節上下警報寄存器(TH和TL)和1字節配置寄存器。ROM中的64位序列號是出廠前被光刻好的,它可以看作是該DS18B20的地址序列碼,每個DS18B20的64位序列號均不相同,這樣就可以實現一根總線掛接多個DS18B20的目的。配置寄存器允許用戶將溫度 - 數字轉換的分辨率設置為9,10,11或12位。DS18B20控制引腳需要一個上拉電阻,並通過開漏模式連接到總線。DS18B20無需外部電源也可運行,當總線為高電平時,通過DQ引腳提高電源,並將電存儲在Cpp電容中,在總線處於低電平時為器件供電,這種方法稱為“寄生電源”。另外DS18B20也可通過VDD供電。
3、DS18B20內部構成:
高速暫存存儲器由9個字節組成,分別為:
1、溫度的低八位數據
2、溫度的高8位數據
3、高溫閾值
4、低溫閾值
5、配置寄存器
6、保留
7、保留
8、保留
9、CRC校驗
器件斷電時,EEPROM寄存器中的數據保留,上電后,EEPROM數據被重新加載到相應的寄存器位置,也可以使用命令隨時將數據從EEPROM重新加載到暫存器中。
4、溫度寄存器數據格式:
DS18B20中的溫度傳感器數據用16位二進制形式提供,其中S為符號位(正數S=0,負數S=1)。溫度傳感器的分辨率可由用戶配置為9、10、11或12位,分別對應0.5℃、0.25 ℃、0.125℃和0.0625℃的增量。開機時的默認分辨率是12位。如果DS18B20配置為12位分辨率,那么溫度寄存器中的所有位都將包含有效數據。對於11位分辨率,bit0沒有定義。對於10位分辨率,bit1和bit0沒有定義,對於9位分辨率,bit2、bit1和bit0沒有定義。
5、TH和TL報警寄存器格式:
TH和TL寄存器存儲溫度報警觸發值,符號位S表示值是正還是負,對於正數,S=0,對於負數,S=1。DS18B20執行溫度轉換后,將溫度值與用戶定義的兩個報警觸發值進行比較,由於TH和TL是8位寄存器,因此在比較TH和TL時只使用溫度寄存器的第11位到第4位,如果被測溫度低於或等於TL值,或高於或等於TH值,則在DS18B20內部存在報警條件,並設置報警標志。主設備可以通過發出一個[EC]命令來檢查總線上所有DS18B20的報警標志狀態。TH和TL寄存器是非易失性的(EEPROM),當設備斷電時,它們將保留數據。可以通過內存部分暫存器的字節2和字節3訪問TH和TL。
6、配置寄存器數據格式:
在配置寄存器中,我們可以通過R0和R1設置DS18B20的轉換分辨率,DS18B20在上電后默認R0=1和R1=1(12分辨率),寄存器中的第7位和第0位到4位保留給設備內部使用。
7、 初始化時序:


static ePinType_t pin;
static eGpioType_t gpio;
static float TemperatureValue = 0.0f;
* 函數功能:DS18B20器件復位
* 形 參:無
* 返 回 值:0=成功,1=失敗
********************************************************/
static unsigned char ds18b20_reset(void)
{
unsigned char status = 0;
unsigned short timeout = 0;
delay_us(520); // 持續最少480us
gpio_set_pin(gpio, pin, 1); // 釋放總線
delay_us(10); // 需要等待15 - 60us
gpio_config(gpio, pin, eGPIO_IN_UP, 1); // 設置總線為輸入模式
while(gpio_read_pin(gpio, pin) != 0)
{
if(++timeout > 0xFFF0U)
{
status = 1;
break;
}
}
timeout = 0;
while(gpio_read_pin(gpio, pin) == 0)
{
if(++timeout > 0xFFF0U)
{
status = 1;
break;
}
}
return status;
}
* 函數功能:向DS18B20寫一個字節數據
* 形 參:寫入的字節數據
* 返 回 值:無
********************************************************/
static void ds18b20_write_byte(unsigned char dat)
{
unsigned char i = 0;
{
gpio_set_pin(gpio, pin, 0);
delay_us(2); // 總線拉低持續時間要大於1us
if(dat & (0x01U << i)) // 低位先發
{
gpio_set_pin(gpio, pin, 1);
}
delay_us(60); // 延時60us,等待ds18b20采樣讀取
gpio_set_pin(gpio, pin, 1); // 釋放總線
delay_us(2);
}
}
/********************************************************
* 函數功能:從DS18B20讀一個字節數據
* 形 參:無
* 返 回 值:讀出的字節數據
********************************************************/
static unsigned char ds18b20_read_byte(void)
{
unsigned char i = 0;
unsigned char dat = 0;
for(i = 0; i < 8; i++)
{
gpio_set_pin(gpio, pin, 0); // 拉低總線
delay_us(2);
gpio_set_pin(gpio, pin, 1); // 釋放總線
gpio_config(gpio, pin, eGPIO_IN_UP, 1); // 設置總線為輸入模式
delay_us(10);
if(gpio_read_pin(gpio, pin) != 0) // 讀時隙產生7 us后讀取總線數據
{
dat |= 0x01U << i; // 低位先收
}
delay_us(50); // 延時60us,滿足讀時隙的時間長度要求
gpio_config(gpio, pin, eGPIO_OUT_PP_UP, 1); // 釋放總線
delay_us(2);
}
return dat;
}
/********************************************************
* 函數功能:DS18B20溫度采集線程
* 形 參:parg:線程形參
* 返 回 值:無
********************************************************/
static void ds18b20_task(void *parg)
{
unsigned char data = 0;
unsigned short temp = 0;
while(1)
{
if(ds18b20_reset() != 0)
{
continue;
}
os_critical_enter(); // 進入臨界區
ds18b20_write_byte(0xCC); // skip rom
ds18b20_write_byte(0x44); // 啟動溫度轉換
os_critical_exit(); // 退出臨界區
os_delay(500);
if(ds18b20_reset() != 0)
{
continue;
}
os_critical_enter(); // 進入臨界區
ds18b20_write_byte(0xCC); // skip rom
ds18b20_write_byte(0xBE); // 發出讀取命令
data = ds18b20_read_byte(); // 讀出溫度低八位
temp = ds18b20_read_byte(); // 讀出溫度高八位
// 計算溫度值
temp = (temp << 8) | data;
// 高五位為符號位,當溫度為正的時候,高五位的字節是0,當溫度為負的時候,高五位字節為1
if((temp & 0xF800) != 0)
{
temp = (~temp) + 1; // 正溫度值直接計算,負溫度值需取反加1
TemperatureValue = -0.0625f; // 溫度為負
}
else
{
TemperatureValue = 0.0625f;
}
// DS18B20的分辨率是0.0625度
TemperatureValue = TemperatureValue * temp;
os_critical_exit(); // 退出臨界區
os_delay(1500); // 1.5s采集一次溫度數據
}
}
/********************************************************
* 函數功能:DS18B20初始化
* 形 參:gpiox:引腳端口
pinx:引腳號
* 返 回 值:無
********************************************************/
unsigned int ds18b20_init(eGpioType_t gpiox, ePinType_t pinx)
{
gpio = gpiox;
pin = pinx;
// 初始化引腳
gpio_config(gpio, pin, eGPIO_OUT_PP_UP, 1);
// 創建溫度采集線程
if(os_task_create(ds18b20_task, NULL, 128, eOS_PRIO_LL) != 0)
{
return 1; // 創建失敗
}
return 0;
}
/********************************************************
* 函數功能:讀取溫度值
* 形 參:無
* 返 回 值:溫度值
********************************************************/
float ds18b20_temperature_value_get(void)
{
return TemperatureValue;
}