DS18B20这个温度传感器是非常常见的,起初使用时也没有太在意,拿原子哥的例程直接跑,发现温度也可以读取到。
但是到实际做项目了发现要用好也没有那么容易。
负温度的换算
负温度换算时要加上1,至于为什么,就是二进制有符号数转换的那个取反加1.
if(TH>7)
{
TH=~TH;
TL=~TL;
TL =TL+1;//这个加1别忘记
temp=0;//温度为负
}else temp=1;//温度为正
读取温度会跳变
由于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+1;
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,所以配置输入时最好直接修改寄存器。因为我在调试中一样的程序可能换一批板子就无法读取到了,但是改成寄存器配置就可以读取到,这个目前我也是比较疑惑,猜测是库函数的配置时间过长导致的,有想法的朋友可以一起讨论一下。