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