DS18B20是由DALLAS半導體公司推出的一種單總線接口的溫度傳感器,與傳統的熱敏電阻等測溫元件相比,它是一種新型的體積小、實用電壓寬、與微處理器接口簡單的數字化溫度傳感器。
DS18B20的內部結構以下圖示編程
ROM中的64位序列號是出廠前就被光刻好的,能夠看作是DS18B20的地址序列號。64位光刻ROM的排列是:8位產品類型標號+48位DS18B20序列號+8位循環冗餘校驗碼。光刻ROM 的做用是使每個DS18B20都各不相同,這樣就能夠實現一根總線上掛接多個DS18B20markdown
DS18B20的內部存儲器(9個字節)包括一個高速暫存器RAM和一個EEPROM,EEPROM裏存放高溫和低溫觸發器和配置寄存器,存儲器詳細組成見下圖:異步
配置寄存器是配置不一樣的位數來肯定溫度和數字的轉化,其結構下圖示:低五位都是1,TM是測試模式位(設置工做模式或測試模式,默認爲0即工做模式),R1和R0用來設置精度,可設9~12位精度,對應的溫度分辨率爲0.5, 0.25, 0.125, 0.0625℃
全部的單總線器件都要求採樣嚴格的信號時序,以保證設局的完整性。DS18B20的時序有:初始化時序、寫(0和1)時序、讀(0和1)時序。DS18B20發送全部的命令和數據都是字節的低位在前,下面介紹這幾個信號的時序:ide
⏩ 初始化時序函數
內置閃存模塊能夠在通用地址空間直接尋址,任何32位數據的讀操做都能訪問閃存模塊的內容並獲得相應的數據。
⏩ 寫時序測試
寫時序包括寫0和寫1時序。全部寫時序至少須要60us,而且在2次獨立的寫時序之間至少須要1us的恢復時間,兩種寫時序均起始於主機拉低總線。寫1時序,主機輸出低電平,延時2us,而後釋放總線,延時60us;寫0時序,主機輸出低電平,延時60us,而後釋放總線,延時2us。寫時序圖以下
⏩ 讀時序ui
單總線器件僅在主機發出讀時序時,才向主機傳輸數據,因此在主機發出讀數據命令後,必須立刻產生讀時序,以便從機可以傳輸數據。全部讀時序至少須要60us,且在2次獨立的讀時序之間至少須要1us的恢復時間。每一個讀時序都由主機發起,至少拉低總線1us,主機在讀時序器件必須釋放總線,而且在時序起始後的15us以內採樣總線狀態。典型的讀時序過程爲,主機輸出低電平延時2us,而後主機轉入輸入模式延時12us,而後讀取單總線當前的電平,而後延時50us
DS18B20的典型溫度讀取過程:復位 --> 發SKIP ROM命令(0XCC) --> 發開始轉換命令(0X44) --> 延時 --> 復位 --> 發SKIP ROM命令(0XCC) --> 發讀存儲器命令(0XBE) --> 連續讀出兩個字節數據(即溫度) --> 結束設計
D1指示燈用來提示系統運行狀態,DS18B20溫度傳感器用來檢測環境溫度,串口1用來打印溫度值3d
指示燈D1code
USART1串口
DS18B20
3.1 STM32CubeMX設置
➡️ RCC設置外接HSE,時鐘設置爲72M
➡️ PC0設置爲GPIO推輓輸出模式、上拉、高速、默認輸出電平爲高電平
➡️ USART1選擇爲異步通信方式,波特率設置爲115200Bits/s,傳輸數據長度爲8Bit,無奇偶校驗,1位中止位
➡️ PG11設置爲GPIO推輓輸出模式、上拉、高速
➡️ 激活TIM7,預分頻因子設爲72-1,向上計數,自動重載值爲65535;所以計數器CNT_CLK = 1MHz,計數器週期爲1us
➡️輸入工程名,選擇路徑(不要有中文),選擇MDK-ARM V5;勾選Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;點擊GENERATE CODE,生成工程代碼
3.2 MDK-ARM軟件編程
➡️ 在tim.c文件下實現微秒延時(us)函數
void delay_us(uint16_t us){ uint16_t differ = 0xffff-us-5; //設定TIM7計數器起始值 __HAL_TIM_SET_COUNTER(&htim7,differ); //啓動定時器 HAL_TIM_Base_Start(&htim7); while(differ < 0xffff-5){ //判斷 //查詢計數器的計數值 differ = __HAL_TIM_GET_COUNTER(&htim7); } HAL_TIM_Base_Stop(&htim7); }
➡️ 建立按鍵驅動文件ds18b20.c 和相關頭文件ds18b20.h
void DS18B20_IO_IN(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_PIN_11; GPIO_InitStructure.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(GPIOG,&GPIO_InitStructure); } void DS18B20_IO_OUT(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_PIN_11; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOG,&GPIO_InitStructure); } void DS18B20_Rst(void){ DS18B 20_IO_OUT(); DS18B20_DQ_OUT_LOW; delay_us(750); DS18B20_DQ_OUT_HIGH; delay_us(15); } uint8_t DS18B20_Check(void){ uint8_t retry = 0; DS18B20_IO_IN(); while(DS18B20_DQ_IN && retry < 200){ retry++; delay_us(1); } if(retry >= 200) return 1; else retry = 0; while(!DS18B20_DQ_IN && retry < 240){ retry++; delay_us(1); } if(retry >= 240) return 1; return 0; } uint8_t DS18B20_Read_Bit(void){ uint8_t data; DS18B20_IO_OUT(); DS18B20_DQ_OUT_LOW; delay_us(2); DS18B20_DQ_OUT_HIGH; DS18B20_IO_IN(); delay_us(12); if(DS18B20_DQ_IN) data = 1; else data = 0; delay_us(50); return data; } uint8_t DS18B20_Read_Byte(void){ uint8_t i,j,data; data = 0; for(i=1;i<=8;i++){ j = DS18B20_Read_Bit(); data = (j<<7)|(data>>1); } return data; } void DS18B20_Write_Byte(uint8_t data){ uint8_t j; uint8_t testb; DS18B20_IO_OUT(); for(j=1;j<=8;j++){ testb=data&0x01; data=data>>1; if(testb){ DS18B20_DQ_OUT_LOW; delay_us(2); DS18B20_DQ_OUT_HIGH; delay_us(60); }else{ DS18B20_DQ_OUT_LOW; delay_us(60); DS18B20_DQ_OUT_HIGH; delay_us(2); } } } void DS18B20_Start(void){ DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); DS18B20_Write_Byte(0x44); } uint8_t DS18B20_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_PIN_11; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOG,&GPIO_InitStructure); DS18B20_Rst(); return DS18B20_Check(); } short DS18B20_Get_Temperature(void){ uint8_t temp; uint8_t TL,TH; short temperature; DS18B20_Start(); DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); DS18B20_Write_Byte(0xbe); TL = DS18B20_Read_Byte(); TH = DS18B20_Read_Byte(); if(TH>7){ TH = ~TH; TL = ~TL; temp = 0; }else temp = 1; temperature = TH; temperature <<= 8; temperature += TL; temperature = (float)temperature*0.625; if(temperature) return temperature; else return -temperature; }
➡️ 在main.c文件下編寫ds18b20測試代碼
int main(void){ float temperature; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM7_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ while(DS18B20_Init()){ printf("DS18B20 checked failed!!!\r\n"); HAL_Delay(500); } printf("DS18B20 checked success!!!\r\n"); /* USER CODE END 2 */ while (1){ temperature = DS18B20_Get_Temperature(); if(temperature < 0) printf("temperature = -%.2f degree\r\n",temperature/10); else printf("temperature = %.2f degree\r\n",temperature/10); HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0); HAL_Delay(200); } }
編譯無誤下載到開發板後,能夠看到D1指示燈不斷閃爍,串口不斷打印出當前溫度值