打印

DS18B20死活弄不好

[复制链接]
7571|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
damoyeren|  楼主 | 2013-4-7 16:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位大神,本人写的温度传感器驱动程序,显示数值是个死值,用手摸温度传感器,数值不变化。初始化程序和显示程序经测试是正确的。测试方法:初始化成功收到应答信号蜂鸣;单独给一个数字,显示正常。我怀疑算法那里出问题了,求大神指教,或者谈谈调试方法。
/*温度传感器输出的是二进制码,是以《1/16 摄氏度》为单位的。如果直接显示,其数值,就是实际温度的 16 倍,所以,需要除以 16,或乘以 0.0625*/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
uchar bai,shi,ge,p,q=0;//显示位定义
uchar a;
sbit ENLED1=P1^4;//138使能端为低电平
sbit addr0=P1^0;//A
sbit addr1=P1^1;//B
sbit addr2=P1^2;//C
sbit addr3=P1^3;//138使能端为高电平
uchar code table []={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//0xff为熄灭符
uchar temper[2]={0x00,0x00};//定义一个数组用来存储高低8位温度数值
uchar dis_buf[5]={0x00,0x00,0x00,0x00,0x00};//显示缓冲;
sbit DQ=P3^2;//温度传感器
sbit BUZZ=P1^6;//蜂鸣器检测复位信号
bit yes;//ds18b20复位成功应答信号,返回信号是bit型数据,不能用uchar

/*显示延时函数,毫秒级别,用于人眼可以分别出来的延时*/
void delay1 (uchar z)
{
        uchar x,y;
        for(x=z;x>0;x--)
     for(y=200;y>0;y--);
}

/*蜂鸣函数*/
void beep ()
{
        BUZZ=0;
        delay1(20);
        BUZZ=1;
        delay1(20);
}

/*ds18b20延时函数,微妙级别*/
void delay2 (uint y)
{
        while(y--);
}

/*DS18B20复位函数*/
bit reset (void)
{
        DQ=1;//释放数据总线
        delay2(8);//延时一会,待数据稳定
        DQ=0;//总线复位
        delay2(90);//延时480us
        DQ=1;//释放总线,等待ds18b20发出应答信号
        delay2(8);//延时16-60us
        yes=DQ;
        delay2(100);
        DQ=1;//释放总线
        return( yes);
}

/*写一个字节*/
void writebyte (uchar dat)
{
        uchar i;
        DQ=1;//释放总线
        delay2(8);
        for (i=0;i<8;i++)
        {
                DQ=0;//准备写数据
                DQ=dat&0x01;
            delay2(5);//延时15us,等待ds18b20采样数据
                DQ=1;//释放总线
                dat>>=1;//写数据时低位在前
        }
}

/*读一个字节*/
uchar readbyte (void)
{
        uchar i,dat=0;
        DQ=1;
        delay2(5);//释放总线
        for(i=8;i<0;i--)
        {
                DQ=0;//读数据时先将总线拉低
                 dat>>=1;//利用右移延时
                DQ=1;//释放总线,准备读数
                if(DQ)//如果数据为高,让它和0x80相与,如果数据为低,不用理睬?
                dat|=0x80;
                delay2(4);
        }
        return (dat);/*返回哪里(应该是返回本函数 哪里调用此函数 哪里得到这个返回值)*/
}

/*获取温度函数*/
void gettemperture ()
{
        reset();
        if(yes==0)//如果DS18B20复位成功,执行写命令,读数据操作,如果没有复位成功,那么跳出大循环或者蜂鸣
        {
               
                writebyte(0xcc);//直挂一个温度传感器,跳过序列号
                writebyte(0x44);//启动温度转换
                delay1(550);//等待750ms转换结束,时间需要仿真(此处仿真时间仿真不出来,更改延时数字由不变到变化)
                reset();
                writebyte(0xcc);//直挂一个温度传感器,跳过序列号
                writebyte(0xbe);//读取温度寄存器
                temper[0]=readbyte();//读取低8位
                temper[1]=readbyte();//读取高8位
        }
        else beep();
}

/*温度数据处理函数*/
uchar convdata (void)
{
    uchar temp;
        temp=((temper[1]&0x0f)<<4)|((temper[0]&0xf0)>>4);//将高字节数据和0x0f相与去掉符号位(不完全),将低字节数据和f0相与去掉低字节的小数位,然后组成一个字节
        return (temp);
}

/*显示函数*/
void display ()
{
                        ENLED1=0;
                        addr3=1;

                    a=convdata;//此处在display程序内部定义a的类型为uchar型必须给下边的程序加个while(1)循环;或者将a改为全局变量也行,奇怪
                        dis_buf[2]=a/100;P0=table[dis_buf[2]]     ;addr0=0;addr1=1;addr2=0;delay1(8);//显示百位
                    dis_buf[1]=(a%100/10);P0=table[dis_buf[1]];addr0=1;addr1=0;addr2=0;delay1(8);//显示十位
                        dis_buf[0]=(a%100%10);P0=table[dis_buf[0]];addr0=0;addr1=0;addr2=0;delay1(8);//显示个位
}

/*主函数*/
void main ()
{
        while(1)
        {
                gettemperture();
        //        convdata ();//刚开始写程序的时候并没有写此语句,因为display函数要用该函数的一个返回值,故可以认为调用了该函数
                display();
        }
}

相关帖子

沙发
uuzd| | 2013-4-7 16:56 | 只看该作者
如果确定不是程序的问题,为啥不检查一下焊的电路?我做过一次,程序上无论如何都检查不出问题,最后发现是电路的问题。

使用特权

评论回复
板凳
uet_cache| | 2013-4-7 18:16 | 只看该作者
呵呵,何苦自己写,网上找个正确的,在系统晶振相同的情况下,实验。注意,晶振一定要中程序要求的相同,否则延时不同,通讯不成功。

使用特权

评论回复
地板
lirunze| | 2013-4-7 19:29 | 只看该作者
恩,这个芯片有好多现成的程序的啊

使用特权

评论回复
5
wukunshan| | 2013-4-7 21:56 | 只看该作者
楼主说的这话:“/*温度传感器输出的是二进制码,是以《1/16 摄氏度》为单位的。如果直接显示,其数值,就是实际温度的 16 倍,所以,需要除以 16,或乘以 0.0625*/”
是错误的。对温度传感器DS18B20的温度值的存储理解不透,所以你写不好这个程序。去我的博客看看吧,保证你找到问题所在。

使用特权

评论回复
6
古董| | 2013-4-7 22:53 | 只看该作者
网上给你找一个,有详细说明:http://www.caterwang.com/post/1.html【基于AT89C51的DS18B20温度传感器读写程序】

使用特权

评论回复
7
胡斯哲| | 2013-4-8 12:00 | 只看该作者
我第一次弄的时候也是死的值   调下延时  这个要精确的延时

使用特权

评论回复
8
雁舞白沙| | 2013-4-8 13:30 | 只看该作者

使用特权

评论回复
9
dwdsp| | 2013-4-8 14:40 | 只看该作者
联系我,给你正在用的程序,c代码的 各个mcu通用

使用特权

评论回复
10
xuxikfg| | 2013-4-8 15:22 | 只看该作者
还是延时的问题吧

使用特权

评论回复
11
ningling_21| | 2013-4-8 16:02 | 只看该作者
如果硬件没问题,大部分都是延时的时间不符合要求造成的....

使用特权

评论回复
12
damoyeren|  楼主 | 2013-4-15 08:17 | 只看该作者
问题现在已经确定了:是数据处理的问题。我把这个程序用UART口发给电脑,在软件上显示温度是正确的,由此说明我写的驱动函数是正确的。问题就是出在读取温度数值后的处理和显示上,但是显示函数我给它一个固定的值能显示正确。麻烦各位大神指教

使用特权

评论回复
13
damoyeren|  楼主 | 2013-4-15 08:17 | 只看该作者
uuzd 发表于 2013-4-7 16:56
如果确定不是程序的问题,为啥不检查一下焊的电路?我做过一次,程序上无论如何都检查不出问题,最后发现是 ...

问题现在已经确定了:是数据处理的问题。我把这个程序用UART口发给电脑,在软件上显示温度是正确的,由此说明我写的驱动函数是正确的。问题就是出在读取温度数值后的处理和显示上,但是显示函数我给它一个固定的值能显示正确。麻烦各位大神指教

使用特权

评论回复
14
天命风流| | 2013-4-15 08:53 | 只看该作者
:)

使用特权

评论回复
15
古董| | 2013-4-15 18:39 | 只看该作者
damoyeren 发表于 2013-4-15 08:17
问题现在已经确定了:是数据处理的问题。我把这个程序用UART口发给电脑,在软件上显示温度是正确的,由此说 ...

以下我用的数据处理程序:【http://www.caterwang.com/post/1.html】
//Temperature计算,把从RAM中读出的数计算成一个完整的可以用于表示当前温度的值
////如果温度是0度下则最高位为1,否则为0
float TempCal(unsigned char TPH,unsigned char TPL)
{
unsigned char TempDat[2];//第一位是整数部分,第二位是小数部分
float Temp;
TempDat[0]=(((TPL&0xf0)>>4)|((TPH&0x0f)<<4)); //取整数
TempDat[1]=TPL&0x0f;       //取小数
if(TPH&0xf8)
  {
  TempDat[0]=~TempDat[0];
  TempDat[1]=(TempDat[1]^0x0f)+0x01;
  Temp=((float)(TempDat[0]|0x80)+(float)TempDat[1]*0.0625);
  }
else
  Temp=(float)TempDat[0]+(float)TempDat[1]*0.0625;
return Temp;
}

使用特权

评论回复
16
叶伤| | 2013-4-16 10:14 | 只看该作者
建议试试temper[0]=readbyte();//读取低8位

        temper[1]=readbyte();//读取高8位
readbyte();//共七个,也就是9个字节全部提取,尽量保证时序不会错误

readbyte();
temp=temper[1];//数组无法使用移位(keilC uv3中发现的,估计数组与指针关系较大)
temp<<=4;
temp00=temper[0]&0xf0;//提取低字节
temp+=temp00>>4;
temp00=(temper[0]&0x0f)?5:0;//提取小数位
另外,楼上说了,18B20整数位不需要处理,小数位才需要乘以0.0625。上面的是我从书上抄的,实测通过。
自学C51才三个月,如有错误请不要咂砖头,给俺留点面子,谢谢

使用特权

评论回复
17
叶伤| | 2013-4-16 10:48 | 只看该作者
            a=convdata;//此处在display程序内部定义a的


………………明显少了个(),这函数怎么运行?编译器不报错吗?


dis_buf[2]=a/100 0=table[dis_buf[2]]    ;addr0=0;addr1=1;addr2=0;delay1(8);//显示百位

……………你没看清楚格式,最高位是符号位,不能直接计算


下面是我的distemp函数,用在一个高考倒计时钟上的,你可以参考下
void distemp()
{
if(temp0&0x80){//最高位是1,说明是负的
    flagtemp=0x9f;//置负标志位为-,手机打的,就不给你排格式了
    temp0=(temp0&0x7f)-1;//取反码
    temp0=~temp0;//反码取回
    }
    else flagtemp=0xff;//温度大于0,符号位消隐
if(temp0<100){
    fuflag=6;//说明符号标志位在哪,我这里5~9用于温度显示
    disp[5]=0xff;
    if(temp0<10){
        fuflag=7;
        disp[6]=0xff;
         }
    }
else{//温度大于100
    disp[6]=0x9f;//百位最大为1}
    fuflag=5;
}
disp[7]=HEXtoLED(temp0,2);//用函数的方式提取十位,保证程序的简单,易于移植
disp[fuflag]=flagtemp;//正负标志位及位置,保证符号跟在第一个数前面
disp[8]=HEXtoLED(temp0,1)&0xfe;//个位要带小数点
disp[9]=temp00;//在读温度时处理,只要显示0或5,因为18B20的误差是±0.5,显示太精确没意义。
}

使用特权

评论回复
18
叶伤| | 2013-4-16 10:52 | 只看该作者
disp[6]=0x9f;//百位最大为1}
  fuflag=5;


……………fuflag=5前多了个反大括号,手机打字就是麻烦

使用特权

评论回复
19
damoyeren|  楼主 | 2013-4-22 10:15 | 只看该作者
uet_cache 发表于 2013-4-7 18:16
呵呵,何苦自己写,网上找个正确的,在系统晶振相同的情况下,实验。注意,晶振一定要中程序要求的相同,否 ...

总是模仿人 何时能超越?

使用特权

评论回复
20
damoyeren|  楼主 | 2013-4-22 11:14 | 只看该作者
本帖最后由 damoyeren 于 2013-4-22 11:41 编辑

if(TPH&0xf8)//此处是不是需要一个强制类型转换啊,转换为bit型,要不然一个字节怎么判断?
  {
  TempDat[0]=~TempDat[0];//低字节怎么没加1啊
  TempDat[1]=(TempDat[1]^0x0f)+0x01;
  Temp=((float)(TempDat[0]|0x80)+(float)TempDat[1]*0.0625);  }//此处或上0x80什么意思
else
  Temp=(float)TempDat[0]+(float)TempDat[1]*0.0625;
return Temp;
}

大侠能不能解释下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

126

主题

393

帖子

2

粉丝