51單片機(jī)學(xué)習(xí)筆記:DS18B20測(cè)溫程序
C代碼
#include"my51.h"
#include"smg.h"
#include"ds18b20.h"
voidmain()//測(cè)試,6位數(shù)碼管顯示溫度值
{
u8i=0;
u16temp=0;
while(1)
{
temp=ds18b20_readTemperaData();
for(i=0;i<100;i++)
{
displaySMG(ds18b20_processTempData(temp));
}
}
}
C代碼
#ifndef_DS18B20_H
#define_DS18B20_H
#include"my51.h"
#include"smg.h"
externu8smgWela[7];//數(shù)碼管位選數(shù)據(jù)
sbitDQ=P2^2;//總線定義
boolds18b20_init();//初始化函數(shù)
u8*ds18b20_processTempData(u16temp);//將temp數(shù)據(jù)處理成數(shù)碼管可顯示數(shù)據(jù)
u16ds18b20_readTemperaData();//讀溫度
u8ds18b20_readByte();//讀一個(gè)字節(jié)
voidds18b20_writeByte(u8dat);//mcu向18b20寫一個(gè)字節(jié)
#endif
C代碼
#include"ds18b20.h"
/******************************************************************
當(dāng)主機(jī)總線t0時(shí)刻從高拉至低電平時(shí)就產(chǎn)生寫時(shí)間隙
從to時(shí)刻開始的1us之后,15us之前將所需寫的位送到總線上
DSl820在t0后的15-60us對(duì)總線采樣若低電平寫入的位是0,若高電平寫入的位是1
連續(xù)寫2個(gè)位之間的間隙應(yīng)大于1us
寫1,總時(shí)間大于60us,在t0開始延時(shí)1us就可以寫1,15us之后ic來(lái)采樣,采樣時(shí)間最大45us
寫0,總時(shí)間是60~120us,15~60us是ic在采樣,120以外就沒必要了,mcu總得釋放總線吧
不管寫1還是寫0,大于60us的話,ic肯定已經(jīng)采樣完成了,那mcu就可以釋放了
*******************************************************************/
voidds18b20_writeByte(u8dat)//mcu向ic寫一個(gè)字節(jié)
{
u8i;
u8tmep=dat;
for(i=0;i<8;i++)
{
DQ=0;//產(chǎn)生讀寫時(shí)序的起始信號(hào)
_nop_();//要求至少1us的延時(shí)
DQ=dat&0x01;//對(duì)總線賦值,從最低位開始寫起
delayXus(10);//延時(shí)74us,寫0在60~120us之間釋放,寫1的話大于60us均可釋放
DQ=1;//釋放總線,為下一次mcu送數(shù)據(jù)做準(zhǔn)備,
dat>>=1;//有效數(shù)據(jù)移動(dòng)到最低位,2次寫數(shù)據(jù)間隙至少需1us
}
}
/**************************************************************************
下降沿產(chǎn)生讀時(shí)序
整個(gè)讀時(shí)序必須至少有60us的持續(xù)時(shí)間,相鄰兩個(gè)讀時(shí)序必須要有至少1us的恢復(fù)時(shí)間
DS18B20在讀時(shí)序產(chǎn)生1us后輸出數(shù)據(jù)到總線上,也有可能需要2~3個(gè)微秒,但不會(huì)更多
而要求主機(jī)釋放總線和采樣總線等動(dòng)作要在15μs內(nèi)完成,那么讓mcu采樣的最佳時(shí)機(jī)
是讀時(shí)序產(chǎn)生后的5~13us之間,在15~60us這段時(shí)間是18b20的私有時(shí)間,它會(huì)在這段
時(shí)間內(nèi)的任意時(shí)刻釋放總線,是不穩(wěn)定期,我們不要讓mcu在這段時(shí)間里對(duì)總線操作
*******************************************************/
u8ds18b20_readByte()//mcu讀一個(gè)字節(jié)
{
u8i,value=0;
for(i=0;i<8;i++)
{
DQ=0;//起始信號(hào)
value>>=1;//順便延時(shí)3~4個(gè)機(jī)器周期
DQ=1;//mcu釋放總線
_nop_();_nop_();_nop_();//再延時(shí)3.3us
if(DQ)
{
value|=0x80;//保存高電平數(shù)據(jù),低電平的話不用保存,移位后默認(rèn)是0
}
delayXus(8);//延時(shí)60.76us
}
returnvalue;
}
u16ds18b20_readTemperaData()//讀取溫度值
{
u16temp=0;
if(ds18b20_init())
{
ds18b20_writeByte(0xcc);//寫指令:跳過(guò)rom檢測(cè)
ds18b20_writeByte(0x44);//寫指令:溫度轉(zhuǎn)換
//delayms(750);//轉(zhuǎn)換延時(shí)需要750ms以上,我們不等它
//首次轉(zhuǎn)換未完成時(shí),得到的初始化數(shù)據(jù)是85度,處理一下就可以了
//溫度轉(zhuǎn)換電路是硬件獨(dú)立的,不會(huì)阻塞初始化功能
if(ds18b20_init())
{
ds18b20_writeByte(0xcc);//寫指令:跳過(guò)檢測(cè)rom
ds18b20_writeByte(0xbe);//寫指令:讀取溫度值
temp=ds18b20_readByte();//先讀低8位數(shù)據(jù)
temp|=(u16)ds18b20_readByte()<<8;//再讀高8位數(shù)據(jù),然后合并
temp&=0x0FFF;//高4位數(shù)據(jù)反正沒用上,我們用來(lái)存放錯(cuò)誤碼
}
else
{
led5=0;//調(diào)試代碼
temp=0x2000;//錯(cuò)誤碼,初始化失敗
}
}
else
{
led6=0;//調(diào)試代碼
temp=0x1000;//錯(cuò)誤碼,初始化失敗,可能器件損壞
}
returntemp;
}
boolds18b20_init()//初始化
{
u8checkState=0;
DQ=1;//總線初始狀態(tài)