

#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit DQ=P2^6;
sbit lcdrs=P1^0;
sbit lcdrw=P1^1;
sbit lcden=P1^2;
void disp(uint a);
void init(void);
void delay(uint i);
uchar ds18b20_init(void);
void write_byte(uchar byte);
uchar read_byte(void);
uint read_ds18b20(void);
void delay50us(void);
void delayms(uint a);
void lcd1602_wr_com(uchar com);
void lcd1602_wr_data(uchar dat);
void lcd_init(void);
uchar code str[]="temperature";
void main(void)
{
init();
while(1)
{
disp(read_ds18b20());
delayms(50);
}
}
void init(void)
{
uchar i;
lcd_init();
lcd1602_wr_com(0x80+0x02); //顯示的地址
for(i=0;i<11;i++)
{
lcd1602_wr_data(str[i]);
delayms(2);
}
}
void disp(uint a)
{
uchar bai,ge,shi,dp,symbol;
uint b;
b=a&0x8000;
if(b==0x8000) //負溫度
{
a&=0x7fff; //將最高位置0
symbol=0x2d; //符號為“-”
}
else symbol=0x2b; //符號為“+”
bai=a/1000+0x30;
shi=a00/100+0x30;
ge=a0/10+0x30;
dp=a+0x30;
if(bai==0x30)
{
bai=0x20; //如果百位為0,不顯示
if(shi==0x30)shi=0x20; //如果百位為零,十位也為0,不顯示
}
lcd1602_wr_com(0x80+0x43);
lcd1602_wr_data(symbol);
delayms(2);
lcd1602_wr_data(bai);
delayms(2);
lcd1602_wr_data(shi);
delayms(2);
lcd1602_wr_data(ge);
delayms(2);
lcd1602_wr_data(0x2e);
delayms(2);
lcd1602_wr_data(dp);
delayms(2);
lcd1602_wr_data(0xdf);
delayms(2);
lcd1602_wr_data(0x43);
delayms(2);
}
void delay(uint i)
{
while(i--);
}
uchar ds18b20_init(void)
{
uchar n;
DQ=1; //初始化時序從高到低,因此先置高
delay(4); //延時等待穩定
DQ=0; //拉低
delay(60); //延時大約500us
DQ=1; //主機放開
delay(6); //延時15~60us
n=DQ; //讀信號線狀態,如為低,則說明線上有設備,否則說明沒有或壞了
delay(6);
return n;
}
void write_byte(uchar byte)
{
uchar i;
for(i=0;i<8;i++)
{
DQ=0; //復位信號線
DQ=byte&0x01; //低位開始寫入,0繼續拉低信號線,1則被拉高
delay(5); //延時大約45us左右,等待設備采樣數據
byte>>=1; //右移一位
DQ=1;
}
delay(4);
}
uchar read_byte(void)
{
uchar i,temp;
for(i=0;i<8;i++)
{
DQ=0;
temp>>=1; //右移一位
DQ=1; //主機釋放信號線
_nop_();
if(DQ)temp|=0x80; //將讀出數據放在最高位,如果是0,信號線會設備繼續拉低,1則為高
delay(4);
}
return temp; //返回讀出的一字節數據
}
uint read_ds18b20(void)
{
uchar numh,numl;
uint value;
if(ds18b20_init()==0) //判斷設置是否正常,0為正常
{
write_byte(0xcc); //跳過ROM序列號讀取
write_byte(0x44); //啟動溫度轉換
if(ds18b20_init()==0) //再次初始化
{
write_byte(0xcc);//跳過ROM序列號讀取
write_byte(0xbe);//讀溫度寄存器
numl=read_byte();//讀低位數據
numh=read_byte();//讀高位數據
value=numh;
value=value<<8|numl; //將數據組合成16位數據
if(value<0x0fff) //正溫度
{
value=value*0.0625*10+0.5; //最一位小數,并進行4舍5入
}
else //負溫度
{
value=~value+1; //內存中數據是以補碼存放的,負數補碼為絕對值按位取反加1
//而補碼的補碼為原碼,這樣就可以求得負數的絕對值
value=value*0.0625*10+0.5; //最一位小數,并進行4舍5入,這是負數的絕對值
value=value|0x8000; //將最高位置1,表示此溫度為負溫度
}
}
}
return value;
}
void delay50us(void)
{
uint j;
j=4;
while(j--);
}
void delayms(uint a)
{
uint i,j;
for(i=a;i>0;i--)
for(j=122;j>0;j--);
}
void lcd1602_wr_com(uchar com)
{
lcdrs=0;
P0=com;
delayms(2);
lcden=1;
delay50us();
lcden=0;
}
void lcd1602_wr_data(uchar dat)
{
lcdrs=1;
P0=dat;
delayms(2);
lcden=1;
delay50us();
lcden=0;
}
void lcd_init(void)
{
lcden=0;
lcdrw=0;
lcd1602_wr_com(0x38); //顯示模式設置
lcd1602_wr_com(0x0c); //開顯示,不顯示光標
lcd1602_wr_com(0x06); //寫字符后地址指針加1,整屏顯示不移動
lcd1602_wr_com(0x01); //清屏
}