ds18b20温度转换指令_【Proteus】DS18B20简易温控器
前言
DS18B20是單片機課設或者仿真項目中一個比較常用的數字溫度傳感器,因此使用DS18B20仿真一個簡易的溫控器,超過溫度就打開風扇,低于某溫度就用繼電器打開加熱絲。整個程序我都會附在最后,如果懶得復制粘貼,要所有的工程以及仿真的話,就給我點贊賞吧。
整個仿真如圖:
首先便是查找DS18B20的手冊,編寫DS18B20的驅動程序。閱讀手冊可知:
DS18B20的數據類型
DS18B20提供9位與12位攝氏溫度測量進度,上電默認是12位,如果我們就用默認的12位精度的話,那么最后從DS18B20讀出來的數據要乘以0.0625,之后得到的就是實際溫度,單位攝氏度。測量范圍為 -55℃至125℃。
DS18B20的通信方式
DS18B20是單總線接口,也就是說,只需要一個通信接口與單片機進行通信,DS18B20看起來就比較像三極管,但它是兩根電源線+一根通信線,每個DS18B20都有一個獨一無二的64位序列號,也就是說,在一個總線上可以連接多個DS18B20設備,控制不同的DS18B20來讀取多點溫度。
DS18B20的外圍電路
DS18B20的電路部分也很簡單,不需要外圍元件,使用3V-5.5V供電。
DS20B20的控制流程
DS18B20上電默認是12位精度,主設備必須向DS18B20發送溫度轉換命令[44H]才能開始溫度轉換。當然DS18B20進行溫度轉換需要時間,當發送完[44H]讀命令之后,主設備就可以執行讀數據時序了,等待DS18B20轉換完成,在DS18B20轉換完成之前,都會返回0,轉換完成之后,就會返回1。
DS18B20的溫度數據是以一個16位二進制補碼數的形式存儲在溫度寄存器中。我們現在就確定使用12位精度的形式,那么首位就為符號位,之后是數據位,如圖:
此外要注意這個上電復位時默認是85℃,有些人看到上電85度還以為是錯的,因此瘋狂修改程序,其實是正?,F象,自己程序注意一下即可。
了解了這些,我們就開始著手寫DS18B20的驅動程序。
手冊上對于事件流程的說明如圖:
注意最后一句話:當執行完這些ROM命令之后,主設備必須回到上述步驟中的第一步。也就是說,我們首先需要進行初始化,然后發送ROM命令,然后發送功能命令。之后便是等待ROM命令執行完,如果要發送下一個ROM命令,則又需要重新回到第一步初始化,再發送下一個ROM命令,再發送功能命令。這一點需要記住。
那么我們的整個讀取流程就基本確定了:
初始化->跳過讀序列號(ROM命令)->啟動溫度轉化(功能命令)->延時等待ROM命令與溫度轉換執行結束->初始化->跳過讀序列號(ROM命令)->讀取溫度(功能命令)
因為我們就使用一個DS18B20,因此可以跳過這個讀序列號。下面我們就按照這個流程來編寫各部分程序。
初始化
由時序圖可知,初始化程序首先需要將總線拉為低電平至少480us的時間,然后釋放總線,總線置為高電平,DS18B20就會檢測這個上升沿,檢測到上升沿之后,等待15-60us,將總線再拉低至少480us,也就是說,高電平的時間也要持續15-60us。
初始化程序如下:
/@@**************************************************************************** 函數功能:延時子程序 ****************************************************************************/ void delay(uint k) {while(k--); } /@@**************************************************************************** 函數功能:DS18B20初始化子程序 ****************************************************************************/ void ds18b20_init(void) {DQ=1; //DQ先置高delay(16); //延時DQ = 0; //發送復位脈沖delay(80); //延時(>480us)DQ = 1; //拉高數據線delay(16); //等待(15~60us)delay(60);DQ = 1; }寫數據
寫數據分為寫0和寫1,在DS18B20中分為寫0時段和寫1時段,每個寫時段最小必須由60us的時序時間并且要有1us的恢復時間。
在寫1時段,在總線拉低之后,主設備必須在15us之內釋放總線,總線釋放后,上拉電阻將總線拉高;在寫0時段,在總線拉低后,整個時段必須一致拉低總線,至少60us。
簡單來說,就是這樣:在主設備初始化寫時段后,DS18B20會在15-60us內對總線進行采樣,如果采樣時候是高電平,則DS18B20會寫入1,反之則寫入0。
程序如下:
/****************************************************************************函數功能:向DS18B20寫一字節數據入口參數:dat出口參數:****************************************************************************/ void WriteOneChar(uchar dat) {uchar i=0;DQ=1;delay(1);for(i=8;i>0;i--){DQ=0;DQ=dat&0x01;delay(5);DQ=1;dat>>=1;} }讀數據
主設備在執行完讀暫存寄存器[BEh]之后,需要即使生成讀時段,才可以讀取數據。每個讀時段最小必須有60us的持續時間與1us的恢復時間。從DS18B20中發送出來的數據在讀時序后僅有15us的有效時間,因此,主設備在開始讀時段后的15us之內必須釋放總線來讀取數據。時序如上圖所示。
程序如下:
/****************************************************************************函數功能:向DS18B20讀一字節數據入口參數:出口參數:dat****************************************************************************/uchar ReadOneChar(void){uchar i=0;uchar dat=0;DQ=1;delay(1);for (i=8;i>0;i--){DQ=0;dat>>=1;DQ=1;delay(1);if(DQ)dat|=0x80;delay(30);DQ=1;}return dat; }然后就是根據手冊查找一些重要的命令,包括跳過讀序列號,讀取溫度命令等等,這一部分就不再贅述。然后我們就可以按照我們之前總結的讀取溫度的流程來編寫整個讀取溫度的程序:
/****************************************************************************函數功能:向DS18B20讀溫度值 入口參數: 出口參數:temperature溫度讀取流程: 初始化->跳過讀序列號->啟動溫度轉化->延時->初始化->跳過讀序列號->讀取溫度并顯示****************************************************************************/ float ReadTemperature(void) {float temperature = 0.0;uint temflag = 0;uint tt = 0;uchar tempL=0; //臨時變量低位uchar tempH=0; //臨時變量高位ds18b20_init(); //初始化WriteOneChar(0xcc); //跳過讀序列號的操作WriteOneChar(0x44); //啟動溫度轉換delay(125); //轉換需要一點時間,延時ds18b20_init(); //初始化WriteOneChar(0xcc); //跳過讀序列號的操作WriteOneChar(0xbe); //讀溫度寄存器(頭兩個值分別為溫度的低位和高位)tempL=ReadOneChar(); //讀出溫度的低位LSBtempH=ReadOneChar(); //讀出溫度的高位MSB//溫度轉換,把高低位做相應的運算轉化為實際溫度tt = tempH<<8;tt = tt|tempL;if(tt&0xf800) //判斷是否是負溫度{ //是負溫度tt = ~tt + 1; temflag = 0;}else{tt = tt; temflag = 1;}temperature = (float)tt;temperature = temperature * 0.0625; // delay(200);/*負溫度*/if(temflag == 0){temperature = -temperature;}/*正溫度*/else{temperature = temperature;}return temperature; //返回溫度值 }然后就是用1602來顯示出來,看一下我們的程序對不對,關于1602的驅動程序,在我之前的文章中有說明,這里就不再說明。
測試主程序如下:
/@@*顯示函數*/ void display(void) {char *string1 = "TEM : ";char *string2 = " C ";char *string3 = "High:";char *string4 = "Low:"; char Display1[16]; //第一行顯示數組char Display2[16]; //第二行顯示數組//顯示溫度sprintf((char*)Display1,"%s%d%s",string1,temp,string2); print_string(Display1,1); //顯示過溫低溫點sprintf((char*)Display2,"%s%d %s%d",string3,tempOver,string4,tempLow); print_string(Display2,2); } void main() {lcd_init();SW = 0;Motor = 0;while(1){temp = (int)ReadTemperature(); //讀取溫度display(); //顯示} }測試結果:
這里的顯示程序中我加了閾值顯示,這里設置的是高溫閾值為30,低溫閾值為27。因為為了后續方便,所以我就把閾值設置得比較近,這個可以自行修改。
之后就是比較簡單的邏輯了,超過高溫閾值就關閉加熱絲打開風扇,低于低溫閾值就關閉風扇,打開加熱絲。主程序如下:
void main() {lcd_init();SW = 0;Motor = 0;while(1){temp = (int)ReadTemperature(); //讀取溫度display(); //顯示/*過溫 打開風扇,關閉加熱絲*/if(temp > tempOver){SW = 0; Motor = 1;}/*低溫 關閉風扇,打開加熱絲*/else if(temp < tempLow){SW = 1;Motor = 0;}} }關于風扇的電路,我這里就直接用了一個ULN2003,這個是小電流電機的,如果要更換24V大電流電機驅動,或者要加上PWM調速,我后續會更新這方面的文章。
效果如下:
如果要全部的工程,仿真就點贊私聊我喔。
1602程序在之前的文章中有發,因此1602程序就不發了。我的工程目錄如下:
所有源代碼如下:
main.c
#include <reg52.h> #include <stdio.h> #include "1602.h" #include "ds18b20.h" #define uchar unsigned char #define uint unsigned intsbit SW = P1^0; //繼電器控制加熱絲 sbit Motor = P1^1; //電機接口int temp = 0; //存儲溫度 int tempOver = 30; //過溫溫度 int tempLow = 27; //低溫溫度 sbit key1 = P3^0; //增加過溫溫度 sbit key2 = P3^1; //減小過溫溫度 sbit key3 = P3^0; //增加低溫溫度 sbit key4 = P3^1; //減小低溫溫度uint key_result = 0; //保存按鍵結果void key_delay(uchar t) { int j; for(;t!=0; t--) for (j=0;j<255;j++); }/*按鍵檢測 如果按鍵1被按下就返回1 如果按鍵2被按下就返回2 如果沒有按鍵按下就返回0*/ uint key_scan(void) {uint result = 0;/*先將按鍵電平拉高*/key1 = 1;key2 = 1;/*檢測按鍵1是否被按下*/if(key1 == 0){key_delay(5);if(key1 == 0){result = 1;}}/*檢測按鍵2是否被按下*/if(key2 == 0){key_delay(5);if(key2 == 0){result = 2;}} return result; }/*顯示函數*/ void display(void) {char *string1 = "TEM : ";char *string2 = " C ";char *string3 = "High:";char *string4 = "Low:"; char Display1[16]; //第一行顯示數組char Display2[16]; //第二行顯示數組//顯示溫度sprintf((char*)Display1,"%s%d%s",string1,temp,string2); print_string(Display1,1); //顯示過溫低溫點sprintf((char*)Display2,"%s%d %s%d",string3,tempOver,string4,tempLow); print_string(Display2,2); }void main() {lcd_init();SW = 0;Motor = 0;while(1){temp = (int)ReadTemperature(); //讀取溫度display(); //顯示/*過溫 打開風扇,關閉加熱絲*/if(temp > tempOver){SW = 0; Motor = 1;}/*低溫 關閉風扇,打開加熱絲*/else if(temp < tempLow){SW = 1;Motor = 0;}} }DS18B20源文件:
#include <reg52.h> #include <stdio.h> #include "ds18b20.h"/***************************溫度傳感器信號引腳******************************************/ sbit DQ=P1^5; //數據傳輸線接單片機的相應的引腳/****************************************************************************函數功能:延時子程序****************************************************************************/ void delay(uint k) {while(k--); }/****************************************************************************函數功能:DS18B20初始化子程序****************************************************************************/ void ds18b20_init(void) {DQ=1; //DQ先置高delay(16); //延時DQ = 0; //發送復位脈沖delay(80); //延時(>480us)DQ = 1; //拉高數據線delay(16); //等待(15~60us)delay(60);DQ = 1; }/****************************************************************************函數功能:向DS18B20讀一字節數據入口參數:出口參數:dat****************************************************************************/uchar ReadOneChar(void){uchar i=0;uchar dat=0;DQ=1;delay(1);for (i=8;i>0;i--){DQ=0;dat>>=1;DQ=1;delay(1);if(DQ)dat|=0x80;delay(30);DQ=1;}return dat; }/****************************************************************************函數功能:向DS18B20寫一字節數據入口參數:dat出口參數:****************************************************************************/ void WriteOneChar(uchar dat) {uchar i=0;DQ=1;delay(1);for(i=8;i>0;i--){DQ=0;DQ=dat&0x01;delay(5);DQ=1;dat>>=1;} }/****************************************************************************函數功能:向DS18B20讀溫度值 入口參數: 出口參數:temperature溫度讀取流程: 初始化->跳過讀序列號->啟動溫度轉化->延時->初始化->跳過讀序列號->讀取溫度并顯示****************************************************************************/ float ReadTemperature(void) {float temperature = 0.0;uint temflag = 0;uint tt = 0;uchar tempL=0; //臨時變量低位uchar tempH=0; //臨時變量高位ds18b20_init(); //初始化WriteOneChar(0xcc); //跳過讀序列號的操作WriteOneChar(0x44); //啟動溫度轉換delay(125); //轉換需要一點時間,延時ds18b20_init(); //初始化WriteOneChar(0xcc); //跳過讀序列號的操作WriteOneChar(0xbe); //讀溫度寄存器(頭兩個值分別為溫度的低位和高位)tempL=ReadOneChar(); //讀出溫度的低位LSBtempH=ReadOneChar(); //讀出溫度的高位MSB//溫度轉換,把高低位做相應的運算轉化為實際溫度tt = tempH<<8;tt = tt|tempL;if(tt&0xf800) //判斷是否是負溫度{ //是負溫度tt = ~tt + 1; temflag = 0;}else{tt = tt; temflag = 1;}temperature = (float)tt;temperature = temperature * 0.0625; // delay(200);/*負溫度*/if(temflag == 0){temperature = -temperature;}/*正溫度*/else{temperature = temperature;}return temperature; //返回溫度值 } 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的ds18b20温度转换指令_【Proteus】DS18B20简易温控器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 脚气挂什么科室
- 下一篇: 斜视自己怎么纠正过来