//学会DS18B20与单片机的连接方法,掌握程序设计思路及编程调试
#include <REGX52.h>
#include <intrins.h> //使用NOP函数
#define uchar unsigned char
#define uint unsigned int
#define NOP _nop_()
sbit OE=P3^0; //ADC0808的OE端,转换结果数据允许输出
sbit EOC=P3^1; //ADC0808的EOC端,转换结束的信息
sbit CLOCK=P2^6; //ADC0808工作必需的时钟信号
sbit ST=P3^2; //ADC0808的START和ALE端,开始转换的命令
sbit LED4=P2^3;
sbit LED3=P2^2;
sbit LED2=P2^1;
sbit LED1=P2^0;
//温度测量数据线
sbit DQ=P3^5; //温度读取数据线
//共阴数码管显示段码
uchar code tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0,0x40};
//带小数点数字
uchar code tab1[]={0xbF,0x86,0xdB,0xcF,0xe6,0xeD,0xfD,0x87,0xfF,0xeF};
//温度的小数位
uchar code tab2[]={0x00,0x06,0x12,0x19,0x25,0x31,0x38,0x44,0x50,0x56,0x63,0x69,0x75,0x81,0x88,0x94};
uchar dat[]={0,0,0,0}; //显示缓冲区
uchar adc; //存放ADC0809转换后的数据
unsigned int tmp;
uchar temp_h,temp_l; /*温度值变量*/
bit flag; /*正负标志位*/
void Delay(void)
{
unsigned char i;
for(i=0;i<250;i++);
}
//温度DS18B20子程序
//函数功能:延时 us
void Delay_us(uchar n)
{
uchar i;
i=0;
while(i<n)
{i++;}
return;
}
//DS18B20复位
void dsreset(void)
{
unsigned int i;
DQ=0;
i=103;
while(i>0)i--;
DQ=1;
i=4;
while(i>0)i--;
}
//读1个字节数据
uchar ReadByte(void)
{
uchar i,k;
i=8;
k=0;
while(i--) //8位数据循环读
{
DQ=1;
Delay_us(1); //延时1us
DQ=0;
k=k>>1;
DQ=1;
NOP;
if(DQ)k |= 0x80; //读出数据存入K
Delay_us(4);
}
return(k);
}
//写入1个字节数据
void tmpwrite(unsigned char dat)
{ unsigned int i;
unsigned char j;
bit testb; //定义位变量
for(j=1;j<=8;j++)
{ testb=dat&0x01; //求出位数据
dat=dat>>1;
if(testb)
{ DQ=0;i++;i++; //i用于确定高低电平时间
DQ=1;
i=8;while(i>0)i--;
}
else
{
DQ=0;
i=8;while(i>0)i--;
DQ=1;i++;i++;
}
}
}
//启动温度转换
void tmpchange(void)
{
dsreset(); /*复位*/
Delay();
tmpwrite(0xcc); //跳过序列号命令
tmpwrite(0x44); //转换命令
}
//将温度值读出来并转化为显示数组
void temp(void)
{
uint dis; //数据变量
char xiaos,xsxs,jh; //温度的小数位,显示小数数据
dsreset(); //DS18B20复位
Delay();
tmpwrite(0xcc); //写入命令
tmpwrite(0xbe); //写入命令
temp_l=ReadByte(); //读取温度,低位在前
temp_h=ReadByte(); //读取温度,高位在后
flag=temp_h&0xf8; //判断温度正负值
if(flag) //flag1=1,温度为负值
{
temp_h=~temp_h; //把补码变为反码
if(temp_l==0)temp_h++; //若低8位全为0且温度为负,取补时就要向高位进1
temp_l=~temp_l+1;
}
dis=(temp_h*256+temp_l)/16; //求出温度值(此求法只求整数温度值)
xiaos=temp_l&0x0f;
/* switch(xiaos)
{ case 0x00:
xsxs=0;
case 0x01:
xsxs=0x06;
break;
case 0x02:
xsxs=0x12;
break;
case 0x03:
xsxs=0x19;
break;
case 0x04:
xsxs=0x25;
break;
case 0x05:
xsxs=0x31;
break;
case 0x06:
xsxs=0x38;
break;
case 0x07:
xsxs=0x44;
break;
case 0x08:
xsxs=0x50;
break;
case 0x09:
xsxs=0x56;
break;
case 0x0a:
xsxs=0x63;
break;
case 0x0b:
xsxs=0x69;
break;
case 0x0c:
xsxs=0x75;
break;
case 0x0d:
xsxs=0x81;
break;
case 0x0e:
xsxs=0x88;
break;
case 0x0f:
xsxs=0x94;
break;
} */
xsxs=tab2[xiaos];
if (flag) //如果温度是负数,只显示1位整数,1位符号,2位小数
{
dat[0]=tab[11]; //显示符号
dat[1]=tab1[dis%10]; //显示1位整数和小数点
jh=(xsxs>>4);
dat[2]=tab[jh]; //显示两位小数
dat[3]=tab[(xsxs&0x0f)];
}
if((dis<10)&&(!flag)) //温度只1位整数值,最高位不显示
{
dat[0]=tab[10]; //不显示
dat[1]=tab1[dis%10]; //显示1位整数和小数点
jh=(xsxs>>4);
dat[2]=tab[jh]; //显示两位小数
dat[3]=tab[(xsxs&0x0f)];
}
else
{ if ((dis<100)&&(!flag)) //显示2位整数
{
dat[0]=tab[dis/10]; //整数十位
dat[1]=tab1[dis%10]; //显示整数个位和小数点
jh=(xsxs>>4);
dat[2]=tab[jh]; //显示两位小数
dat[3]=tab[(xsxs&0x0f)];
}
else //显示3位整数
{if ((dis>100)&&(!flag))
{ dat[0]=tab1[(dis/10)%10]; //整数十位并标记百位
dat[1]=tab1[dis%100]; //显示整数个位和小数点
jh=(xsxs>>4);
dat[2]=tab[jh]; //显示两位小数
dat[3]=tab[(xsxs&0x0f)];
}
}
}
}
//显示子程序
void disp()
{ uchar i1,wei;
wei=0xfe;
for (i1=0;i1<4;i1++)
{
P0=dat[i1];
P2=wei;
Delay();
P2=0xff;
wei=(wei<<1)|0x01;
}
}
//----------------------------主函数-----------------------------//
void main(void)
{
SP=0x70;
/*
EA=1; ET0=1;
TMOD=0x02; // T0方式2计时
TH0=0x01; // 晶振:12MHz
TL0=0x01; // 晶振:12MHz
TR0=1; // 开中断,启动定时器
*/
//DS18B20读取、转换、显示
while(1)
{
tmpchange(); /*启动温度转换*/
// Delay(); /*等待转换结束,可不用,会对显示产生影响*/
temp(); /*读取温度转换结果*/
disp(); /*温度显示和报警*/
/*ADC0809
ST=0;
ST=1;
ST=0; //启动转换
while(!EOC); //等待转换结束
OE=1; //允许输出
adc=P1; //取转换结果
//数据处理,已备显示
tmp=adc*196; //乘以19.6MV
dat[3]=tmp/10000;
dat[2]=tmp/1000%10;
dat[1]=tmp/100%10;
dat[0]=tmp/10%10;
*/
/*
//数码管显示转换结果
LED1=0;
P0=tab[dat[3]]+0x80;
Delay();
LED1=1;
LED2=0;
P0=tab[dat[2]];
Delay();
LED2=1;
LED3=0;
P0=tab[dat[1]];
Delay();
LED3=1;
LED4=0;
P0=tab[dat[0]];
Delay();
LED4=1;*/
} // end while
} // end main
/* 定时计数器0的中断服务子程序 */
//*
void timer0(void) interrupt 1 using 1 // 50mS中断一次
{
CLOCK=~CLOCK;
}