//DS18B20温度计C语言程序
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit ds=P1^7; //温度传感器信号线
sbit A1=P1^0; //千
sbit A2=P1^1; //百
sbit A3=P1^2; //十
sbit A4=P1^3; //个
sbit A5=P1^4; //段选控制
sbit D =P0^2; //小数点
sbit sound=P3^3; //定义控制蜂鸣器的单片机引脚。
uint temp,t,i,b,xs;
unsigned char yima[]={0xeb,0x88,0xb3,0xba,0xd8,0x7a,0x7b,0xa8,0xfb,0xfa};
void delayms(unsigned int i);/*延时函数*/
//**********************************************************************************
//延时函数, 对于12MHz时钟, 例z=10,则大概延时10ms.
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--);
for(y=124;y>0;y--);
}
//**********************************************************************************
//**********************************************************************************
//初始化DS18B20
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
void dsreset(void)
{ //对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于?us
uint i;
ds=0;
i=103; //拉低约800us, 符合协议要求的480us以上
while(i>0)i--;
ds=1; //产生一个上升沿, 进入等待应答状态
i=4;
while(i>0)i--;
}
//**********************************************************************************
//**********************************************************************************
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit tempreadbit(void)
{
uint i;
bit dat;
ds=0;
i++; //i++起延迟作用 延时约8us, 符合协议要求至少保持1us
ds=1;
i++;i++; //延时约16us, 符合协议要求的至少延时15us以上
dat=ds;
i=8;
while(i>0)i--; //延时约64us, 符合读时隙不低于60us要求
return(dat);
}
//**********************************************************************************
//**********************************************************************************
//读取一字节数据, 通过调用tempreadbit()来实现
uchar tempread(void)
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tempreadbit();
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在dat里
}
return(dat);
}
//**********************************************************************************
//**********************************************************************************
//向DS18B20写入一字节数据
void tempwritebyte(uchar dat)
{
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb) //写"1", 将ds拉低15us后, 在15us~60us内将ds拉高, 即完成写1
{
ds=0;
i++;i++; //拉低约16us, 符号要求15~60us内
ds=1;
i=8;while(i>0)i--; //延时约64us, 符合写时隙不低于60us要求
}
else //写"0", 将ds拉低60us~120us
{
ds=0;
i=8;while(i>0)i--; //拉低约64us, 符号要求
ds=1;
i++;i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
}
}
}
//**********************************************************************************
//**********************************************************************************
//向DS18B20发送温度转换命令
void tempchange(void)
{
dsreset(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
delay(1); //延时1ms, 因为DS18B20会拉低ds 60~240us作为应答信号
tempwritebyte(0xcc); //写跳过读ROM指令
tempwritebyte(0x44); //写温度转换指令
}
//**********************************************************************************
//**********************************************************************************
//向DS18B20发送读取数据命令 获取当前温度值
uint tmp()
{
float tt;
// int tt;
uchar low,high;
dsreset();
delay(1);
tempwritebyte(0xcc); //写入跳过序列号命令字 Skip Rom
tempwritebyte(0xbe); //写入读取数据令字 Read Scratchpad
//连续读取两个字节数据
low =tempread(); //读低8位
high=tempread(); //读高8位
temp=high; //高8位赋予temp
temp<<=8; //将高低两个字节合成一个整形变量 temp为16位 高8位左移8位 低8位补0
temp=temp|low; //高低8位相或=temp为16位=高8位+低8位
xs=low&0x0f; //低4位为小数部分
tt=temp>>4; //整数部分
// temp=tt*100+xs*100/16;
temp=tt*10+((((xs*5)>>2)+1)>>1);
// **************************************
//y=(((x*5)>>2)+1)>>1;
//等效y=((x*5)/4+1)/2;
//再等效y=((x*20)/16+1)/2;
//y=2*(x*10/16+0.5)/2;
//实际上y=x*10/16+0.5; //+0.5为 四舍五入
// **********************************************
// tt=temp*0.0625; //DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
// temp = tt * 100 + (temp > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
// temp=tt*100; //将它放大100倍, 使显示时可显示小数点后两位(t=11.0625,计算得temp = 1106, 即11.06 度)
return temp; //temp是整型
}
//**********************************************************************************
//**********************************************************************************
//显示函数
void display(uint t)
{
unsigned char a1=0,a2=0,a3=0,a4=0; //临时变量
static int k=0;
a1=t/1000; //取t的千位//
a2=t%1000/100;//取t的百位//
a3=t%100/10; //取t的十位//
a4=t%10; //取t的个位//
if (k==0){A1=1;A2=0;A3=0;A4=0;P0=yima[a1];}
else if(k==1){A1=0;A2=1;A3=0;A4=0;P0=yima[a2];}
else if(k==2){A1=0;A2=0;A3=1;A4=0;P0=yima[a3];}
else if(k==3){A1=0;A2=0;A3=0;A4=1;P0=yima[a4];}
k++;
if(k>3) k=0;
}
//**********************************************************************************
main()
{
/* TMOD=0X01;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
EA =1;
TR0=1;
ET0=1; */
while(1)
{
tempchange(); //启动温度转换
//启动温度转换以后需要延时,大概在750ms
for(i=0;i<40;i++) //显示5次(不加for 前面3位数码管很暗)或者显示函数改用中断写
{
display(t);
delay(1);
}
t=tmp();
}
}
/*
void t0()interrupt 1 using 1 //中断程序负责显示t的值
{
unsigned char a1=0,a2=0,a3=0,a4=0; //临时变量
static int k=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
a1=t/1000; //取t的千位//
a2=t%1000/100;//取t的百位//
a3=t%100/10; //取t的十位//
a4=t%10; //取t的个位//
if (k==0){A1=1;A2=0;A3=0;A4=0;P0=yima[a4];}
else if(k==1){A1=0;A2=1;A3=0;A4=0;P0=yima[a3];}
else if(k==2){A1=0;A2=0;A3=1;A4=0;P0=yima[a2];}
else if(k==3){A1=0;A2=0;A3=0;A4=1;P0=yima[a1];}
k++;
if(k>3) k=0;
// TH0=240;//扫描速度
} */
我给你发一个我写的吧,11.0592的晶振,
void delay_ds(uchar g)
{
while(--g);
}
uchar rdata_ds()
{
uchar a,i;
for (i=0;i<8;i++)
{
ds=0;
_nop_();
a>>=1;
ds=1;
delay_ds(1);
if (ds)
{
a|=0x80;
}
delay_ds(10);
}
return a;
}
void cmd_ds(uchar a)
{
uchar i;
for (i=0;i<8;i++)
{
ds=0;
_nop_();
ds=a&0x01;
delay_ds(10);
ds=1;
a>>=1;
delay_ds(1);
}
}
void init_ds()
{
ds=1;
delay_ds(1);
ds=0;
delay_ds(250);
ds=1;
delay_ds(100);
}
uint ds18()
{
uchar a,b;
uint c;
float t;
init_ds();
cmd_ds(0xcc);
cmd_ds(0x44);
init_ds();
cmd_ds(0xcc);
cmd_ds(0xbe);
a=rdata_ds();
b=rdata_ds();
c=b;
c<<=8;
c|=a;
t=c*0.0625;
c=t+0.5;
return c;
}
ds18();就是温度值,
看不懂的地方可以问我。
肯定是程序问题,你先保证硬件没问题,再用别人的程序试试...
DS1820是个娇气的东东,对时序操作很严格,如果一点不对,都可能测不出温度,你的晶振到底是多少?这个要确定,不能大概,还有那些延时程序,必须要精确延时,按DATASHEET上的标准来,不然都不行。