第一次玩DS18B20,刚好前几天玩过DS1302,刚开始感觉前者没有后者的时序清楚,费了好大的气力去读DS18B20的datasheet,英文的、中文的,都都研究过。也曾照着datasheet写过一个DS18B20.H的头文件,可是就是用不了,初始化还能成功,就是显示都是0,很明显没有读出温度值(刚上电时应该是85°才对)。看了好多网友的使用手记,感觉几乎每个人的时序都有点差异,一时很迷茫。后来听网友说DS18B20的时序延时函数要很精确,于是怀疑我的延时函数,我一直用的for循环做的延时,估计精度不够。在网上看了一个网友的延时函数,他用_NOP_()函数做的延时,可以精确地延时到us级别,在12M晶振时的延时时间由公式time=15*(T+1)确定。在这里把这个延时函数写出来与大家分享一下:
void DELAY(uint T)
{
uchar n;
for(n=T;n>0;n--)
{
_nop_();_nop_();_nop_();_nop_();
}
_nop_();_nop_();
}
换掉了延时函数,时序基本正常了,但是紧接着出现第二个问题——不清楚从总线上读出的数据格式,也就不清楚数据转换的原理了。参照别人写的一个数据处理部分的代码(在此也写出来一起探讨),在朋友的帮助下,终于解决了这个至关重要的问题。
/*----------------------------------------
获得温度:
------------------------------------------*/
uint get_temperature()
{
float wendu;
uchar a,b;
ds_reset();
delay(1); //约2ms
ds_write_byte(0xcc);
ds_write_byte(0xbe);
a="ds"_read_byte();
b="ds"_read_byte();
temp="b";
temp<<=8;
temp="temp|a";
wendu="temp"*0.0625; temp="wendu"*10+0.5;
return temp;
}
得到以下结论:
一、主控机发出读命令后,要紧接着连续读取两次数据,先读取低位再读取高位,每次读取8bit数据;
二、读到的低位和高位数据要整合成一个16bit的温度量化值,通过左移和位运算实现;
三、得到量化值后,还要根据需要的精度将其换算为摄氏度温度值,12位精度就是0.0625的精度,9、10、11位精度处理方法类似,即用量化值乘以精度就是温度值;
四、此时得到的温度值是四个字节的浮点数,有四位小数,要通过移动小数点再加0.5来四舍五入,舍去不需要的小数(保留的小数位数视自己的精度要求而定),处理后得到的是一个整数,但是保留的小数位却藏在整数里面,比如上例中保留一个小数,则这个小数就是temp的个位。
五、整数直接显示是没有小数点的,所以要在十位上加小数点才可以正确显示温度,即人为分离出小数位。
搞懂这些后,实验板已经可以显示温度了。但是没有正负温度符号显示,我在再次读了datasheet后,发现负温度的最高位为1,正温度的最高位为0,于是将8bit高位数据的最高位截取,转化成bit型数据sign作为符号标志,然后根据符号标志显示正负符号,正温度加“0”,负温度加“—”。
另外一个细节问题,好多网友显示小数点是通过查表实现的,即把数码管位扫描数组设置两个,一个没有加小数点,一个加了小数点,十位显示用加了小数点的数组,其他的位就用没有家小数点的数组。我想了一个办法,在显示十位之后不是直接显示个位,而是插入显示小数点,结果出来是一样的,但是却简化了数码管显示函数。
以下是我的实验板上显示温度的情形。
图片1
图片2
图片3
用户235074 2010-8-5 09:43