DS18B20 是由 DALLAS 半導體公司推出的一種的“一線總線”接口的溫度傳感器。與傳
統的熱敏電阻等測溫元件相比,它是一種新型的體積小、適用電壓寬、與微處理器接口簡單的
數字化溫度傳感器。一線總線結構具有簡潔且經濟的特點,可使用戶輕松地組建傳感器網絡,
從而為測量系統的構建引入全新概念,測量溫度范圍為-55~+125℃ ,精度為±0.5℃。現場溫
度直接以“一線總線”的數字方式傳輸,大大提高了系統的抗干擾性。它能直接讀出被測溫度,
並且可根據實際要求通過簡單的編程實現 9~l2 位的數字值讀數方式。它工作在 3—5. 5 V 的電
壓范圍,采用多種封裝形式,從而使系統設計靈活、方便,設定分辨率及用戶設定的報警溫度
存儲在 EEPROM 中,掉電后依然保存
其內部結構如下所示
DS18B20的通訊方式是單總線的,一般而言,我們遇到的封裝都是如下
其中DQ就是主要的通訊線路,對DS的讀取和寫入都需要主機來控制DQ線路的DQ高低電平的時間來確定,具體如下
一般而言,DQ線需要接一個上拉電阻,所以,才寫操作的最后一步都需要將總線拉高
向DS寫0需要總線拉低至少60US最多120US就算完成,也就是說,1-->0(持續60-120us)-->1 寫入了0
像DS寫入1需要總線拉低最少1us最多15US,然后總線拉高,拉高時間至少15us,一般40us以上即可 1->0(1-15us,推薦5us)-->1(持續15us以上,推薦40us)
由此可見,DS的總線采樣實在總線拉低之后的15us開始的
讀取DS分別為讀取1和讀取0,但是這兩者時序是統一的
首先總線拉低至少1us,最多15us,還是選擇2us,然后釋放總線(也就是說進入輸入模式),等待15us以上的事件,然后采樣,高電平為1低電平為0
1-->0(持續2us,最多15us)-->等待15us以上60us以下-->采樣總線電平,得到1或者0,記得采樣完成之后切換到輸出模式將總線拉高便於下一次使用
DS18B20的命令
DS1820有三個主要數字部件:1)64位激光ROM,2)溫度傳感器,3)非易失性溫度報警觸發器TH和TL
啟動溫度轉換的命令是0X44,讀取命令是0XBE
所以一般而言,對於DS的驅動包含以下幾步
復位-->發 SKIP ROM 命令(0XCC)-->發開始轉換命令(0X44)-->延時-->復
位-->發送 SKIP ROM 命令(0XCC)-->發讀存儲器命令(0XBE)-->連續讀出兩個字節數據(即
溫度)-->結束
我們在讀取的時候只讀取兩個字節的原因在於DS的存儲器布局
前兩個就是我們需要的溫度,當然也可以讀取全部的,擴展驅動達到其他目的
以下是驅動代碼,STM32驅動代碼中使用了位段操作
#ifndef __Ds18b20H #define __Ds18b20H #include "ioremap.h" #include "delay.h" #include "uart.h" //IO方向設置 #define Ds18b20IO_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;} #define Ds18b20IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;} ////IO操作函數 #define Ds18b20DQ_OUT PGout(11) //數據端口 PG11 #define Ds18b20DQ_IN PGin(11) //數據端口 PG11 u8 Ds18b20Init(void); //初始化DS18B20 short Ds18b20GetTemp(void); //獲取溫度 void Ds18b20Start(void); //開始溫度轉換 void Ds18b20WriteByte(u8 dat);//寫入一個字節 u8 Ds18b20ReadByte(void); //讀出一個字節 u8 Ds18b20ReadBit(void); //讀出一個位 u8 Ds18b20Check(void); //檢測是否存在DS18B20 void Ds18b20Rst(void); //復位DS18B20 void Ds18b20Show(void); #endif
#include "ds18b20.h" //復位DS18B20 void Ds18b20Rst(void) { Ds18b20IO_OUT(); //SET PA0 OUTPUT Ds18b20DQ_OUT=0; //拉低DQ DelayUs(750); //拉低750us Ds18b20DQ_OUT=1; //DQ=1 DelayUs(15); //15US } //等待DS18B20的回應 //返回1:未檢測到DS18B20的存在 //返回0:存在 u8 Ds18b20Check(void) { u8 retry=0; Ds18b20IO_IN();//SET PA0 INPUT while (Ds18b20DQ_IN&&retry<200) { retry++; DelayUs(1); }; if(retry>=200)return 1; else retry=0; while (!Ds18b20DQ_IN&&retry<240) { retry++; DelayUs(1); }; if(retry>=240)return 1; return 0; } //從DS18B20讀取一個位 //返回值:1/0 u8 Ds18b20ReadBit(void) // read one bit { u8 data; Ds18b20IO_OUT();//SET PA0 OUTPUT Ds18b20DQ_OUT=0; DelayUs(2); Ds18b20DQ_OUT=1; Ds18b20IO_IN();//SET PA0 INPUT DelayUs(12); if(Ds18b20DQ_IN)data=1; else data=0; DelayUs(50); return data; } //從DS18B20讀取一個字節 //返回值:讀到的數據 u8 Ds18b20ReadByte(void) // read one byte { u8 i,j,dat; dat=0; for (i=1;i<=8;i++) { j=Ds18b20ReadBit(); dat=(j<<7)|(dat>>1); } return dat; } //寫一個字節到DS18B20 //dat:要寫入的字節 void Ds18b20WriteByte(u8 dat) { u8 j; u8 testb; Ds18b20IO_OUT();//SET PA0 OUTPUT; for (j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if (testb) { Ds18b20DQ_OUT=0;// Write 1 DelayUs(2); Ds18b20DQ_OUT=1; DelayUs(60); } else { Ds18b20DQ_OUT=0;// Write 0 DelayUs(60); Ds18b20DQ_OUT=1; DelayUs(2); } } } //開始溫度轉換 void Ds18b20Start(void)// ds1820 start convert { Ds18b20Rst(); Ds18b20Check(); Ds18b20WriteByte(0xcc);// skip rom Ds18b20WriteByte(0x44);// convert } //初始化DS18B20的IO口 DQ 同時檢測DS的存在 //返回1:不存在 //返回0:存在 u8 Ds18b20Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PORTG口時鍾 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PORTG.11 推挽輸出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOG, &GPIO_InitStructure); GPIO_SetBits(GPIOG,GPIO_Pin_11); //輸出1 Ds18b20Rst(); return Ds18b20Check(); } //從ds18b20得到溫度值 //精度:0.1C //返回值:溫度值 (-550~1250) short Ds18b20GetTemp(void) { u8 temp; u8 TL,TH; short tem; Ds18b20Start (); // ds1820 start convert Ds18b20Rst(); Ds18b20Check(); Ds18b20WriteByte(0xcc);// skip rom Ds18b20WriteByte(0xbe);// convert TL=Ds18b20ReadByte(); // LSB TH=Ds18b20ReadByte(); // MSB if(TH>7) { TH=~TH; TL=~TL; temp=0;//溫度為負 }else temp=1;//溫度為正 tem=TH; //獲得高八位 tem<<=8; tem+=TL;//獲得底八位 tem=(short)((float)tem*0.625);//轉換 if(temp)return tem; //返回溫度值 else return -tem; } void Ds18b20Show(void) { short t = 0; t = Ds18b20GetTemp(); printf("ds18b20 temp is %d\r\n",t); }