记录DS18B20读取不对的一些小问题以及解决办法

DS18B20这个温度传感器是非常常见的,起初使用时也没有太在意,拿原子哥的例程直接跑,发现温度也可以读取到。
但是到实际做项目了发现要用好也没有那么容易。
负温度的换算
负温度换算时要加上1,至于为什么,就是二进制有符号数转换的那个取反加1.

    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
		TL =TL+1;//这个加1别忘记 这个是错误的会导致一个BUG
        temp=0;//温度为负  
    }else temp=1;//温度为正	

注意!!!上述的计算方法有误
上述的计算会在某些数据上出错,如读取到TH为0XFF,TL为0x00,此时因为TH和TL是分别取反的,所以会导致结果为0x0000,而正确的结果是0x0100,因为TL取反后是0xFF,再加1会变成0x100,但是无法进位所以是错的。
修正后的代码如下

	    u8 TL,TH;
   		short tem,value;
		tem = TH;
		tem = tem<<8;
		tem = tem | TL;
		if(tem < 0)
		{
			tem = (short)((~tem + 1) *0.625);
			tem = -tem;
		}
		else
			tem = (short)(tem *0.625);
		value = tem;

读取温度会跳变
由于DS18B20有可能不是直接焊接在板子上的,如果线过长就会影响到数据的读取,然后读取到不正常的数,导致温度跳变。这里除了可以用一些滤波算法外,更重要的是对数据的校验。DS18B20就自带了CRC8的校验。
代码如下

int DS18B20_Get_Temp(void)
{
    volatile uint8_t temp;
    volatile uint8_t TL,TH;
    volatile short tem;
	volatile int value,calibration;
	uint8_t tab[9],Crc8;
    DS18B20_Start ();           //开始转换
    DS18B20_Rst();
	//DS18B20_Check();
    if(DS18B20_Check()==1)
		{
			tem = -9999;//-9999,表示传感器故障
			return tem;
		}	 

    DS18B20_Write_Byte(0xcc);   // skip rom
    DS18B20_Write_Byte(0xbe);   // convert	    
    tab[0]=TL=DS18B20_Read_Byte();     // LSB   
    tab[1]=TH=DS18B20_Read_Byte();     // MSB   
		tab[2]=DS18B20_Read_Byte();     // 
		tab[3]=DS18B20_Read_Byte();     // 
		tab[4]=DS18B20_Read_Byte();     // 
		tab[5]=DS18B20_Read_Byte();     // 
		tab[6]=DS18B20_Read_Byte();     // 
		tab[7]=DS18B20_Read_Byte();     // 
		tab[8]=DS18B20_Read_Byte();     // CRC
		Crc8 = DS18B20_Crc(tab,8);
		if(Crc8!=tab[8])  //CRC校验
		{
			return 0x7FFF;
		}
    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
		TL =TL;
        temp=0;//温度为负  
    }else temp=1;//温度为正	  	  
    tem=TH; //获得高八位
    tem<<=8;    
    tem+=TL;//获得底八位
    tem=((float)tem)*0.625;//转换    

	if(temp)
	{
		value = tem;
	}
	else 
	{
		value = -tem;
	}		
	return value;  
}
uint8_t DS18B20_Crc(uint8_t *addr, uint8_t len)
{
    uint8_t crc = 0, inbyte, i, mix;

    while (len--)
    {
        // inbyte 存储当前参与计算的新字节
        inbyte = *addr++;

        for (i = 8; i; i--) 
        {
            // 将新字节与CRC从低位到高位, 依次做异或运算, 每次运算完CRC右移一位
            // 如果运算结果值为1, 则将CRC与 1000 1100 作异或
            // 第3,4位代表流程图中的异或运算, 第7位其实就是运算结果移入的1
            mix = (crc ^ inbyte) & 0x01;
            crc >>= 1;
            if (mix) 
            {
                crc ^= 0x8C;
            }
            inbyte >>= 1;
        }
    }
    return crc;
}

数据一直读取到FF
这个问题是由于,在配置IO输入时,使用了库函数,尤其是HAL库,这样会导致某些情况下根本IO根本读取不到低电平,所以虽然DS18B20 正确的返回的数据,(用逻辑分析仪或者示波器看波形都是正确的),但是就是读取的都是FF,所以配置输入时最好直接修改寄存器。因为我在调试中一样的程序可能换一批板子就无法读取到了,但是改成寄存器配置就可以读取到,这个目前我也是比较疑惑,猜测是库函数的配置时间过长导致的,有想法的朋友可以一起讨论一下。
读取到85的问题
在上述原子哥中的程序,DS18B20_Start 启动转换后马上就接着去读取,这个时读取的其实是上一次转换后的值,实际手册中的介绍是开始转换后要等待一定的时间比如1秒去等待DS18B20完成转换后才可以去读取。按照原子哥的写法没有什么大错,但是某些情况下会导致读取到85。建议开始转换后要进行延时等待,这个延时可以用delay空等,也可以使用定时器,比如先开始转换
DS18B20_Start ();
等待定时器计时完成
开始读取数据

int DS18B20_Get_Temp(void)
{
	volatile uint8_t temp;
    volatile uint8_t TL,TH;
    volatile short tem;
	volatile int value,calibration;
	uint8_t tab[9],Crc8;
	DS18B20_Start ();           //开始转换
	//应该要延时等待数据转换完成
    DS18B20_Rst();
省略。。。。
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值