通过DS18B20学时序
DS18B20是單總線通信,所以它的時序相對來說也比較簡單,從它開始入門再適合不過了
準備工具:
- 單片機
- DS18B20傳感器
- DS18B20 datasheet
關于DS18B20的詳細介紹大家可以看它的datasheet,這里只針對時序做一些介紹,參考正點原子的代碼,從datasheet出發做詳細的闡述,DS18B20有著嚴格的時序要求,稍有差錯,就容易無法正常工作,接下來我們來分析它初始化序列的時序:
reset pulse&presence pulse
單總線上的所有通信都是以初始化序列開始。
第一階段:主機輸出低電平,保持低電平時間至少480us,以產生復位脈沖。
接第二階段:主機釋放總線,4.7K的上拉電阻將單總線拉高,延時15~60 us,并進入接收模式(Rx)。
第三階段:DS18B20拉低總線60~240us,以產生低電平應答脈沖。
//復位DS18B20 void DS18B20_Rst(void) { DS18B20_IO_OUT(); //SET PG11 OUTPUT DS18B20_DQ_OUT=0; //拉低DQdelay_us(750); //拉低750usDS18B20_DQ_OUT=1; //DQ=1 拉高釋放總線delay_us(15); //15US//進入接收模式,等待應答信號 }?
//等待DS18B20的回應 //返回1:未檢測到DS18B20的存在 //返回0:存在 u8 DS18B20_Check(void) { u8 retry=0;DS18B20_IO_IN();//SET PG11 INPUT 接收模式,等待DS18B20拉低總線 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; //240us以內是正常的應答 return 0; }WRITE TIME SLOTS
寫時序包括寫0時序和寫1時序。所有寫時序至少需要60us,且在2次獨立的寫時序之間至少需要1us的恢復時間,兩種寫時序均起始于主機拉低總線。
寫1時序:主機輸出低電平,延時2us,然后釋放總線,延時60us。
寫0時序:主機輸出低電平,延時60us,然后釋放總線,延時2us。
?
//寫一個字節到DS18B20 //dat:要寫入的字節 void DS18B20_Write_Byte(u8 dat) { u8 j;u8 testb;DS18B20_IO_OUT();//SET PG11 OUTPUT for (j=1;j<=8;j++) {testb=dat&0x01;dat=dat>>1;if (testb) {DS18B20_DQ_OUT=0;// Write 1delay_us(2); DS18B20_DQ_OUT=1;delay_us(60); }else {DS18B20_DQ_OUT=0;// Write 0delay_us(60); DS18B20_DQ_OUT=1;delay_us(2); }} }READ TIME SLOTS
單總線器件僅在主機發出讀時序時,才向主機傳輸數據,所以,在主機發出讀數據命令后,必須馬上產生讀時序,以便從機能夠傳輸數據。
所有讀時序至少需要60us,且在2次獨立的讀時序之間至少需要1us的恢復時間。每個讀時序都由主機發起,至少拉低總線1us。主機在讀時序期間必須釋放總線,并且在時序起始后的15us之內采樣總線狀態。
典型的讀時序過程為:主機輸出低電平延時2us,然后主機轉入輸入模式延時12us,然后讀取單總線當前的電平,然后延時50us
//從DS18B20讀取一個位 //返回值:1/0 u8 DS18B20_Read_Bit(void) // read one bit {u8 data;DS18B20_IO_OUT();//SET PG11 OUTPUTDS18B20_DQ_OUT=0; delay_us(2);DS18B20_DQ_OUT=1; DS18B20_IO_IN();//SET PG11 INPUTdelay_us(12);if(DS18B20_DQ_IN)data=1;else data=0; delay_us(50); return data; } //從DS18B20讀取一個字節 //返回值:讀到的數據 u8 DS18B20_Read_Byte(void) // read one byte { u8 i,j,dat;dat=0;for (i=1;i<=8;i++) {j=DS18B20_Read_Bit();dat=(j<<7)|(dat>>1);} return dat; }DS18B20的典型溫度讀取過程為:
復位>發SKIPROM命令(0XCC)>發開始轉換命令(0X44)>延時>復位→發送SKIP ROM命令(0XCC)>發讀存儲器命令(0XBE)>連續讀出兩個字節數據(即溫度)→結束。
?
轉化后得到的12位數據,存儲在DS18B20的兩個8比特的RAM中,二進制中的bit11-bit5是符號位,如果測得的溫度大于0,這5位為0,只要將測到的數值乘于0.0625即可得到實際溫度;如果溫度小于0,這5位為1,測到的數值需要取反加1再乘于0.0625即可得到實際溫度。例如+125℃的數字輸出為07DOH,,-25.0625℃的數字輸出為FE6FH。
? //從ds18b20得到溫度值 //精度:0.1C //返回值:溫度值 (-550~1250) short DS18B20_Get_Temp(void) {u8 temp;u8 TL,TH;short tem;DS18B20_Start (); // ds1820 start convertDS18B20_Rst();DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip romDS18B20_Write_Byte(0xbe);// convert TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB if(TH>7){TH=~TH;TL=~TL; temp=0;//溫度為負 }else temp=1;//溫度為正 tem=TH; //獲得高八位tem<<=8; tem+=TL;//獲得底八位tem=(double)tem*0.625;//轉換 if(temp)return tem; //返回溫度值else return -tem; }?
?
?
在主程序里,只需要直接調用DS18B20_Get_Temp()即可,再根據自己的需求,將數值呈現到屏上或者打印到串口輸出。
temperature=DS18B20_Get_Temp(); if(temperature<0) {temperature=-temperature; printf("temperature = %d.%d??", temperature/10, temperature%10); } else {printf("temperature = %d.%d??", temperature/10, temperature%10); }?
總結
以上是生活随笔為你收集整理的通过DS18B20学时序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: D3 配色方案篇
- 下一篇: Postgresql + Pgpool