程序如下:用開發板的程序改了三極管驅動的數碼管的程序
//溫度顯示程序==LED顯示,精度0.1攝氏度
//晶振:12M
/******************************************
跳線設置:默認
注意事項:ds18b20切勿插反,有爆炸燙傷的危險,方向是ds18b20的平面(有字的一面)朝旁邊的三極管Q4
***/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P3^0;
sbit led3=P3^2;
sbit led4=P3^3;
sbit led1=P3^4;
sbit led2=P3^5;
//數據口define interface
uint temp,r; //溫度值 variable of temperature
//不帶小數點
unsigned char code table[] = {0x48,0xee,0x54,0x64,0xe2,0x61,0x41,
0xec,0x40,0x60};
//帶小數點
unsigned char code table1[] = {0x08,0xae,0x14,0x24,0xa2,0x21,0x01,0xac,0x00,0x20};
/*************精確延時函數*****************/
void delay(unsigned char i)
{
while(--i);
}
/******************************************
此延時函數針對的是12Mhz的晶振
delay(0):延時518us 誤差:518-2*256=6
delay(1):延時7us (原帖寫"5us"是錯的)
delay(10):延時25us 誤差:25-20=5
delay(20):延時45us 誤差:45-40=5
delay(100):延時205us 誤差:205-200=5
delay(200):延時405us 誤差:405-400=5
*******************************************/
void pdelay(unsigned char i)
{
uint x,y;
for(x=i;x>0;x--)
for(y=110;y>0;y--);
}
/*****************DS18B20******************/
void Init_Ds18b20(void) //DS18B20初始化send reset and initialization command
{
DQ = 1; //DQ復位,不要也可行。
delay(1); //稍做延時
DQ = 0; //單片機拉低總線
delay(250); //精確延時,維持至少480us
DQ = 1; //釋放總線,即拉高了總線
delay(100); //此處延時有足夠,確保能讓DS18B20發出存在脈沖。
}
uchar Read_One_Byte() //讀取一個字節的數據read a byte date
//讀數據時,數據以字節的最低有效位先從總線移出
{
uchar i = 0;
uchar dat = 0;
for(i=8;i>0;i--)
{
DQ = 0; //將總線拉低,要在1us之后釋放總線
//單片機要在此下降沿后的15us內讀數據才會有效。
_nop_(); //至少維持了1us,表示讀時序開始
dat >>= 1; //讓從總線上讀到的位數據,依次從高位移動到低位。
DQ = 1; //釋放總線,此后DS18B20會控制總線,把數據傳輸到總線上
delay(1); //延時7us,此處參照推薦的讀時序圖,盡量把控制器采樣時間放到讀時序后的15us內的最后部分
if(DQ) //控制器進行采樣
{
dat |= 0x80; //若總線為1,即DQ為1,那就把dat的最高位置1;若為0,則不進行處理,保持為0
}
delay(10); //此延時不能少,確保讀時序的長度60us。
}
return (dat);
}
void Write_One_Byte(uchar dat)
{
uchar i = 0;
for(i=8;i>0;i--)
{
DQ = 0; //拉低總線
_nop_(); //至少維持了1us,表示寫時序(包括寫0時序或寫1時序)開始
DQ = dat&0x01; //從字節的最低位開始傳輸
//指令dat的最低位賦予給總線,必須在拉低總線后的15us內,
//因為15us后DS18B20會對總線采樣。
delay(10); //必須讓寫時序持續至少60us
DQ = 1; //寫完后,必須釋放總線,
dat >>= 1;
delay(1);
}
}
uint Get_Tmp() //獲取溫度get the temperature
{
float tt;
uchar a,b,c;
Init_Ds18b20(); //初始化
Write_One_Byte(0xcc); //忽略ROM指令
Write_One_Byte(0x44); //溫度轉換指令
Init_Ds18b20(); //初始化
Write_One_Byte(0xcc); //忽略ROM指令
Write_One_Byte(0xbe); //讀暫存器指令
a = Read_One_Byte(); //讀取到的第一個字節為溫度LSB
b = Read_One_Byte();
c=b&0x80;
if(c==0x80)
{
r=1;
temp=b;
temp<<=8;
temp=temp|a;
tt=~temp+1;
tt=tt*0.0652;
temp=tt*10+0.5;
return temp;
}
else
{
r=0; //讀取到的第一個字節為溫度MSB
temp = b; //先把高八位有效數據賦于temp
temp <<= 8; //把以上8位數據從temp低八位移到高八位
temp = temp|a; //兩字節合成一個整型變量
tt = temp*0.0625; //得到真實十進制溫度值
//因為DS18B20可以精確到0.0625度
//所以讀回數據的最低位代表的是0.0625度
temp = tt*10+0.5; //放大十倍
return temp; //這樣做的目的將小數點后第一位也轉換為可顯示數字
} //同時進行一個四舍五入操作。
}
/****************數碼碼動態顯示函數**************/
void Display(uint temp) //顯示程序
{
uchar A1,A2,A3;
A1 = temp/100; //百位
A2 = temp%100/10; //十位
A3 = temp%10; //個位
if(r==1)
{
led1=1;
P1=0xf7;
pdelay(5);
led1=0;
}
else
{
led1=0;
}
P1=table[A1]; //顯示百位
led2=1;
pdelay(5);
led2=0;
P1 = table1[A2]; //顯示十位,使用的是有小數點的數組(因為temp值擴大了10倍,雖然是十位,實際為個位)
led3 =1;
pdelay(5);
led3=0;
P1 = table[A3]; //顯示個位
led4 = 1;
pdelay(5);
led4=0;
}
void main()
{
while(1)
{
Display(Get_Tmp());
}
}
17.5為正常溫度值,顯示期間不定時跳到錯誤顯示然后恢復。
|