supermice 发表于 2011-10-25 16:33:22

求一个ds18b20例案,正负数都可以显示,精度到0.1的

最简单的skip rom方案 或者给我讲一下最后接收到的两个byte的数据怎么处理就行了
谢谢了

torpedoingstar 发表于 2011-10-25 19:05:49

比如说收到的字节是TH和TL
则hh=TH*256+TL;
然后温度就等于hh*0.0625*10+0.5就是温度的十倍就好了
显示的时候除以10

yao1 发表于 2011-10-25 19:18:03

********************************************************************
//获取当前温度值
int getTmpValue()
{
    unsigned int tmpvalue;
    int value; //存放温度数值
    float tt;
    unsigned char low, high;
    sendReadCmd();
    //连续读取两个字节数据
    low = readByte();
    high = readByte();
    //将高低两个字节合成一个整形变量
    //计算机中对于负数是利用补码来表示的
    //若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
    tmpvalue = high;
    tmpvalue <<= 8;
    tmpvalue |= low;
    value = tmpvalue;
    //使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
    tt = value * 0.0625;
    //将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
    //如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
    //如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
    value = tt * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
    return value;
}
*******************************************************************************************
//向DS18B20发送读取数据命令获取当前温度值
uint tmp()
{
    float 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位
    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是整型
}

Ilove51andAVR 发表于 2011-10-25 20:23:21

回复【2楼】yao1
-----------------------------------------------------------------------

yao1的解释很精辟啊!佩服!

Ilove51andAVR 发表于 2011-10-25 20:25:59

回复【2楼】yao1

temp<<=8;    //将高低两个字节合成一个整形变量 temp为16位 高8位左移8位 低8位补0

-----------------------------------------------------------------------

有一点不明白,temp前面定义为类型的变量?
51不是8位单片机吗?怎么temp可以为16位的数据呢?

bigeblis 发表于 2011-10-25 22:22:20

很容易
读来的数据,是个双字节有符号数,用C写的话,直接除16就是温度值,计算结果保留小数点后一位即可
不过我喜欢用汇编,为了简化处理,一般不考虑负值。此时低字节位的低4位就是小数值,先乘10再除16,结果就是小数值。然后把高位字节的低4位保留,去除高4位,高低4位交换,最后与去除低4位的低字节位合并,就是整数部分。这样的处理都可以用C51自带的运算指令完成,速度快,程序简单。
要显示负值则需要加负数判断并求补码的程序,也是很容易的

telefunken 发表于 2011-10-25 23:14:25

+_+#
18b20本身就做不到0.1度.....
你程序怎么写都没用.....

yao1 发表于 2011-10-27 09:24:20

回复【4楼】Ilove51andAVR
-----------------------------------------------------------------------
有一点不明白,temp前面定义为类型的变量?
51不是8位单片机吗?怎么temp可以为16位的数据呢?
-----------------------------------------------------------------------
unsigned int tmpvalue; 16位 ......
unsigned char low,high; 8位 ......

18B20:
    测量数据以16位带符号位扩展的二进制补码形式存放
    单片机读取温度,一次读2字节16位,读完将低11位的二进制转化为十进制后乘0.0625即为实际温度,只需要判断11位即可
还需要判断温度正负:前5位为符号位,1为负,0为正
1)前5位为1时,读取温度为负值,实际温度=测得数值需要取反加1再乘0.0625
-55——11111 10010010000——低11位取反011 0110 1111(十进制879)——加1(880)——乘0.0625——实际温度880*0.0625=55(11111为负)   
2)前5位为0时,读取温度为正值,实际温度=测得数值乘0.0625
+125 ——00000 11111010000——低11位十进制为2000 ——2000*0.0625=12500000位正

上面的程序只能读正的 要读负值 增加判断(注意变量名不一样)
把tplsb和tpmsb都是8位的合成一个16位的有符号数t;temp为浮点数
t=tpmsb<<8;
t=t|tplsb
if(t<0)   //负温度
{
    temp=(~t+1)*0.0625*10+0.5; //负温度时,取反加1再乘以0.0625得实际温度,乘10+0.5显示小数点一位,且四舍五入
}
else   //正温度
{   
    temp=t*0.0625*10+0.5;    //正温度 实际温度=测得数值乘0.0625
}

XA144F 发表于 2011-10-27 09:43:51

还在乘以0.0625……这就是右移4位啊!浮点乘法增加多少运算量?

chill520 发表于 2011-10-27 10:33:18

http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_689077KF6V2Q.JPG
(原文件名:表1.JPG)

yao1 发表于 2011-10-27 19:45:34

//初学者先理解算法了 再用移位法 理解是关键
//移位原理:
//用10进制来理解,如果把123456这个数右移4位,是不是得到12?也就是除以10的4次方10000得到的(因为是整型,小数部分被舍去了)。
//二进制右移4位,自然是除以2的4次方16了。
//因0.0625=1/16 所以T*0.0625=T/16=T>>4

void v_TemperatureUpdate_f( void )   
{      
    uint16 TempDat ;   
    float Temp ;   
    TempDat = v_Ds18b20ReadTemp_f() ;   
    if( TempDat & 0xf000 )   
    {   
      Tflag = 1 ;                           
      TempDat = ~ TempDat + 1 ;   
    }   
    Temp =    TempDat >> 4; // (TempDat * 0.0625)浮点数运算很慢,效率不高,改成移位      
    TempDat = Temp * 10;// 保留1位小数
    Temperature[ 0 ] = Tflag ;                   //温度正负标志
   
    Temperature[ 1 ] = TempDat / 100;          //温度十位值   
    Temperature[ 2 ] = (TempDat % 100) / 10;   //温度个位值   
    Temperature[ 3 ] = TempDat % 10;            //温度小数位---- 0.1

// Temperature[ 4 ] = (TempDat%10)/10;            //温度小数位---- 0.01
}

NemoGu 发表于 2011-10-27 19:50:51

数字温度传感器 做不到那么高的精度吧
DS18B25的精度只有±0.5℃,分辨率0.0625℃
MAXIM官方的datasheet上有精度的曲线

liudaolunhui 发表于 2011-10-29 01:15:19

二楼的帖子是不错的,赞一个

liudaolunhui 发表于 2011-10-29 01:16:24

对了,14楼的帖子也不错

yiyeguzhou 发表于 2011-10-30 21:49:23

主要给获取温度的代码吧:
         void gettemperature()
{
        uchar temp1,temp2,temp,tflag ;
    reset();
        writebyte(0xcc);
        writebyte(0x44);
        reset();
    writebyte(0xcc);
        writebyte(0xbe);
        temp1=readchar();
        temp2=readchar();
        temp=(temp2<<8)|temp1;

        if(temp<0x0fff)
           tflag=1;
       else
       {
          tflag=0;
          temp=~temp+1;//负温度时,使其取反加一
       }
          d_temp=temp*(0.625);//正温度
          tempshi=d_temp/100;
          tempge=d_temp%100/10;
          tempxiaoshu=d_temp%10;
}

jdlu 发表于 2011-11-13 15:59:26

十六楼这么解释很好。通俗易懂。同样讲一件事,讲_法不同,效果也不同。

jdlu 发表于 2011-11-13 16:01:10

是十四楼啊?!刚才看错了。

wxty 发表于 2012-6-13 15:10:12

yao1 发表于 2011-10-27 09:24 static/image/common/back.gif
回复【4楼】Ilove51andAVR
-----------------------------------------------------------------------
...

xiexie !         

vagrand 发表于 2012-6-14 18:31:32

yao1 发表于 2011-10-27 19:45 static/image/common/back.gif
//初学者先理解算法了 再用移位法 理解是关键
//移位原理:
//用10进制来理解,如果把123456这个数右移4位 ...

“Temp =    TempDat >> 4; // (TempDat * 0.0625)浮点数运算很慢,效率不高,改成移位”
这一句中右移四位小数位就没有了吧,后面一句乘以10还有用吗?

xiaoaf 发表于 2012-6-14 18:52:43

void get_tem()
{
        uchar teml,temh;
        reset();
        Write_Byte(0xcc);//跳过读序列号的操作
        Write_Byte(0x44);//启动温度转换
        delay_ms(750);//750ms
        reset();
        Write_Byte(0xcc);
        Write_Byte(0xbe);//读取温度转换结果
        teml=Read_Byte();
        temh=Read_Byte();
       
        if((temh&0xf0)==0xf0)//如果是负温度
                {
                        flag_low=1;
                        temper=(~((temh)*256+(teml))+1)*6.25;
                }

        else
                temper=(temh*256+teml)*6.25;//放大100倍
}

692446 发表于 2012-12-8 22:09:52

{:titter:}{:titter:}{:titter:}{:titter:}

xuan12321 发表于 2012-12-9 10:13:19

请问,有没有人用cvavr做过 啊,你们是用什么来做精确延时的啊,我用自带的延时,就是读不出数据求高手帮忙看看,我发的贴不好,都没人理,只好到这边来拉人啦,求高手指点http://www.amobbs.com/thread-5509739-1-4.html

JamesErik 发表于 2012-12-9 10:37:34

都没有人响应精度问题?

hsztc 发表于 2012-12-9 11:58:27

前面整数部份我就不说了,我只给个最后一位小数得到的方法,结果四舍五入。

x为18B20提取的小数部份,z为输出。

z=(((unsigned char)(x*10u))+8u)>>4;
页: [1]
查看完整版本: 求一个ds18b20例案,正负数都可以显示,精度到0.1的