創(chuàng)建好“ds18b20.c”和“ds18b20.h”文件,把下面代碼添加進(jìn)各自的文件。
1.ds18b20.c代碼
我們?cè)谒卫蠋煹拇a基礎(chǔ)上添加了溫度轉(zhuǎn)換函數(shù),原理在上一講已經(jīng)講解清楚了。
#include <reg52.h> #include <ds18b20.h> #include <intrins.h> unsigned char temp_i=0;//定義全局變量temp_i用來(lái)幫助液晶屏靈活顯示 /* 軟件延時(shí)函數(shù),延時(shí)時(shí)間(t*10)us */ void DelayX10us(unsigned char t) { do { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } while (--t); } /* 復(fù)位總線,獲取存在脈沖,以啟動(dòng)一次讀寫操作 */ unsigned char Get18B20Ack() { unsigned char ack; EA = 0; //禁止總中斷 IO_18B20 = 0; //產(chǎn)生500us復(fù)位脈沖 DelayX10us(50); IO_18B20 = 1; DelayX10us(6); //延時(shí)60us ack = IO_18B20; //讀取存在脈沖 while(!IO_18B20); //等待存在脈沖結(jié)束 EA = 1; //重新使能總中斷 return ack; } /* 向DS18B20寫入一個(gè)字節(jié),dat-待寫入字節(jié) */ void Write18B20(unsigned char dat) { unsigned char mask; EA = 0; //禁止總中斷 for (mask=0x01; mask!=0; mask<<=1) //低位在先,依次移出8個(gè)bit { IO_18B20 = 0; //產(chǎn)生2us低電平脈沖 _nop_(); _nop_(); if ((mask&dat) == 0) //輸出該bit值 IO_18B20 = 0; else IO_18B20 = 1; DelayX10us(6); //延時(shí)60us IO_18B20 = 1; //拉高通信引腳 } EA = 1; //重新使能總中斷 } /* 從DS18B20讀取一個(gè)字節(jié),返回值-讀到的字節(jié) */ unsigned char Read18B20() { unsigned char dat; unsigned char mask; EA = 0; //禁止總中斷 for (mask=0x01; mask!=0; mask<<=1) //低位在先,依次采集8個(gè)bit { IO_18B20 = 0; //產(chǎn)生2us低電平脈沖 _nop_(); _nop_(); IO_18B20 = 1; //結(jié)束低電平脈沖,等待18B20輸出數(shù)據(jù) _nop_(); //延時(shí)2us _nop_(); if (!IO_18B20) //讀取通信引腳上的值 dat &= ~mask; else dat |= mask; DelayX10us(6); //再延時(shí)60us } EA = 1; //重新使能總中斷 return dat; } /* 啟動(dòng)一次18B20溫度轉(zhuǎn)換,返回值-表示是否啟動(dòng)成功 */ unsigned char Start18B20() { unsigned char ack; ack = Get18B20Ack(); //執(zhí)行總線復(fù)位,并獲取18B20應(yīng)答 if (ack == 0) //如18B20正確應(yīng)答,則啟動(dòng)一次轉(zhuǎn)換 { Write18B20(0xCC); //跳過(guò)ROM操作 Write18B20(0x44); //啟動(dòng)一次溫度轉(zhuǎn)換 } return !ack; //ack==0表示操作成功,所以返回值對(duì)其取非,返回值就是1了 } /* 讀取DS18B20轉(zhuǎn)換的溫度值,返回值-表示是否讀取成功 */ unsigned char Get18B20Temp(int *temp) { unsigned char ack; unsigned char LSB, MSB; //16bit溫度值的低字節(jié)和高字節(jié) ack = Get18B20Ack(); //執(zhí)行總線復(fù)位,并獲取18B20應(yīng)答 if (ack == 0) //如18B20正確應(yīng)答,則讀取溫度值 { Write18B20(0xCC); //跳過(guò)ROM操作 Write18B20(0xBE); //發(fā)送讀命令 LSB = Read18B20(); //讀溫度值的低字節(jié) MSB = Read18B20(); //讀溫度值的高字節(jié) *temp = ((unsigned int)MSB << 8) + LSB; //合成為16bit整型數(shù) } return !ack; //ack==0表示操作成功,所以返回值對(duì)其取非,返回值就是1了 } /* 溫度轉(zhuǎn)換 */ unsigned char TEMP_CONV(unsigned int *temp, unsigned char *str) { unsigned char res; float temp_float; res = Get18B20Temp(temp); //讀取當(dāng)前溫度,傳入的參數(shù)是指針類型 if (res) //讀取成功時(shí),進(jìn)行溫度轉(zhuǎn)換 { if( (*temp>>11)==0 ) //溫度大于等于0度 { temp_float=( (float)(*temp) ) *0.0625*10.0; //*temp就是沒有轉(zhuǎn)換時(shí)的16位那個(gè)變量,然后再把實(shí)際溫度值再乘以10倍 *temp=(unsigned int)temp_float; //得到16位整型的數(shù)值 str[0]='0'+( (*temp/1000)%10 ); //當(dāng)溫度大于等于100度時(shí)需要顯示百位數(shù) str[1]='0'+( (*temp/100)%10 ); //當(dāng)溫度大于等于10度時(shí)需要顯示十位數(shù) str[2]='0'+( (*temp/10)%10 ); //當(dāng)溫度大于等于1度時(shí)需要顯示個(gè)位數(shù) str[3]='.'; str[4]='0'+( (*temp)%10 ); //溫度必須顯示小數(shù)點(diǎn)后的一位 if(str[0]=='0')temp_i++; if(str[1]=='0')temp_i++; return 1;//讀取溫度成功,返回值一律為1 } else if( (*temp>>11)>0 )//溫度小于0度 { *temp=(*temp)&0x07FF; //清除掉高5位使其變?yōu)? *temp=2048-(*temp); //此時(shí)的temp為補(bǔ)碼 temp_float=( (float)(*temp) )*0.0625*10.0; //實(shí)際溫度值再乘以10倍 *temp=(unsigned int)temp_float; //得到16位整型的數(shù)值 str[0]='-'; //添加負(fù)數(shù)的符號(hào) str[1]='0'+( (*temp/100)%10 ); //當(dāng)溫度在-10度以下時(shí)需要顯示十位數(shù) str[2]='0'+( (*temp/10)%10 ); //溫度必須顯示個(gè)位數(shù),哪怕是0,比如“-0.5” str[3]='.'; str[4]='0'+( (*temp)%10 ); //溫度必須顯示小數(shù)點(diǎn)后的一位 if(str[1]=='0') { str[1]='-'; temp_i=1;//實(shí)際溫度大于-10.0度的時(shí)候,假如是-5.4度,那么“LcdShowStr(0, 0, str+temp_i);”就是顯示“-5.4”,小數(shù)點(diǎn)就是在第3個(gè)顯示格上顯示 //實(shí)際溫度小于等于-10.0度的時(shí)候,假如是-12.6度,str[1]不等于‘0’, //這樣temp_i是等于0的,那么“LcdShowStr(0, 0, str+temp_i);”顯示“-12.6”,小數(shù)點(diǎn)就是在第4個(gè)顯示格上顯示 } return 1; //讀取溫度成功,返回值一律為1 } } return 0;//讀取溫度不成功,返回值為0 }
2.ds18b20.h代碼
#ifndef __DS18B20_H__ #define __DS18B20_H__ sbit IO_18B20 = P3^2; //DS18B20通信引腳 extern unsigned char temp_i; //在main.c中要用該變量需要進(jìn)行全局變量聲明 void DelayX10us(unsigned char t); //軟件延時(shí)函數(shù),延時(shí)時(shí)間(t*10)us unsigned char Get18B20Ack(); //復(fù)位總線,獲取存在脈沖,以啟動(dòng)一次讀寫操作 void Write18B20(unsigned char dat); //向DS18B20寫入一個(gè)字節(jié),dat-待寫入字節(jié) unsigned char Read18B20(); //從DS18B20讀取一個(gè)字節(jié),返回值-讀到的字節(jié) unsigned char Start18B20(); //啟動(dòng)一次18B20溫度轉(zhuǎn)換,返回值-表示是否啟動(dòng)成功 unsigned char Get18B20Temp(int *temp); //讀取DS18B20轉(zhuǎn)換的溫度值,返回值-表示是否讀取成功 unsigned char TEMP_CONV(unsigned int *temp, unsigned char *str); //溫度轉(zhuǎn)換 #endif
3.main.c測(cè)試代碼
#include <reg52.h> #include <function.h>//詳見第六章第8講 #include <timer.h> //詳見第八章第11講 #include <lcd.h> //詳見第十一章第3講 #include <ds18b20.h> u8 flag1s=0; void main() { u16 temp; u8 str[10]; EA = 1; Start18B20(); //啟動(dòng)DS18B20 InitLcd1602(); //初始化液晶 TIM0_Init(10000,11); //定時(shí)10ms,11是微調(diào)使定時(shí)更精確 while (1) { if (flag1s) //每秒更新一次溫度 { flag1s = 0; if( TEMP_CONV(&temp,str)==1 ) //返回值為1代表讀取溫度成功 { LcdShowStr(0, 0, str+temp_i); //顯示到液晶屏上 temp_i=0; } else //讀取失敗時(shí),提示錯(cuò)誤信息 { LcdShowStr(0, 0, "error!"); } Start18B20(); //必須要重新啟動(dòng)下一次轉(zhuǎn)換 } } } void TIM0_IRQHandler() interrupt 1 { static u8 tmr1s = 0; TH0 = T0RH; //重新加載重載值 TL0 = T0RL; tmr1s++; if (tmr1s >= 100) //定時(shí)1s { tmr1s = 0; flag1s = 1; } }
筆者親自把開發(fā)板放進(jìn)冰箱進(jìn)行冷凍10分鐘,拿出來(lái)上電時(shí),確實(shí)可以把0度以下的溫度測(cè)試出來(lái)并完整的顯示在液晶屏上。
C語(yǔ)言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競(jìng)賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:
一點(diǎn)編程也不會(huì)寫的:零基礎(chǔ)C語(yǔ)言學(xué)練課程
解決困擾你多年的C語(yǔ)言疑難雜癥特性的C語(yǔ)言進(jìn)階課程
從零到寫出一個(gè)爬蟲的Python編程課程
只會(huì)語(yǔ)法寫不出代碼?手把手帶你寫100個(gè)編程真題的編程百練課程
信息學(xué)奧賽或C++選手的 必學(xué)C++課程
藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競(jìng)賽課入門課程
手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程