参加蓝桥杯单片机竞赛的同学应该对DS18B20温度传感器不陌生,这个小小的传感器在比赛中经常出现。它采用单总线(onewire)通信协议,只需要一根数据线就能完成数据传输,非常适合在资源有限的单片机系统中使用。我在实际项目中多次使用过这个传感器,发现它的精度和稳定性都相当不错,最高能达到±0.5℃的精度,完全能满足比赛需求。
DS18B20最大的特点就是单总线设计。这意味着你只需要连接三根线(VCC、GND和DQ)就能让它工作。在蓝桥杯的板子上,DS18B20通常连接在P1.4引脚。记得我第一次使用时,因为没仔细看原理图,把线接错了位置,结果怎么调试都没反应,浪费了不少时间。所以建议大家在开始编码前,一定要确认硬件连接正确。
单总线协议听起来简单,但实现起来有不少细节需要注意。它通过精确的时序来控制数据传输,每个bit的传输都需要严格的时间控制。比如初始化时,主机要先拉低总线至少480μs,然后释放总线等待DS18B20回应。
我在调试时发现,时序控制是单总线最关键的环节。如果延时时间不准确,传感器可能无法正确响应。官方提供的底层驱动代码中已经包含了这些时序控制函数,比如Delay_OneWire(),但你需要根据自己单片机的时钟频率做适当调整。记得有一次比赛,我直接用了往年的代码,结果因为时钟频率不同导致通信失败,这个教训让我记忆深刻。
在蓝桥杯比赛中,我们的单总线上通常只连接了一个DS18B20,这种情况下可以跳过耗时的ROM检测过程。具体做法是在初始化后直接发送0xCC命令。这个优化虽然看起来很小,但在需要频繁读取温度的场景下,能节省不少时间。
我做过测试,跳过ROM检测后,单次温度读取可以节省约5ms的时间。别小看这5ms,在实时性要求高的应用中,这点时间可能很关键。当然,如果你以后在工作中遇到总线上挂载多个传感器的情况,就必须进行完整的ROM检测流程了。
读取温度分为两个步骤:首先发送0x44命令启动温度转换,然后等待转换完成。这里有个容易踩的坑:温度转换需要一定时间,DS18B20在转换期间不会响应其他命令。官方文档指出,12位精度下转换需要最多750ms。
我在代码中使用了简单的延时等待方式,虽然不够优雅但很实用。更专业的做法是启动转换后不断查询总线状态,但这会增加代码复杂度。对于比赛来说,200ms左右的延时通常就足够了,毕竟我们不需要那么高的实时性。
转换完成后,发送0xBE命令读取暂存器中的数据。DS18B20会返回两个字节的温度数据,我们需要将它们组合成一个16位的值。这里的数据格式有点特别:
我建议先把这两个字节打印出来看看,确保通信正常。有时候因为时序问题,读到的数据可能是0xFF或0x00,这通常表示通信失败。
对于比赛应用,我们通常只需要整数部分温度。我的做法是用位操作提取中间8位(高字节低4位+低字节高4位),这样就得到了温度值的整数部分。如果要显示小数部分,可以这样计算:
c复制float temperature = (temp_integer) + (temp_fraction * 0.0625);
但考虑到数码管显示的限制,比赛中一般只显示整数部分就够了。如果遇到负温度,记得要先对数据取反再加1,才能得到正确的温度值。
官方提供的底层驱动代码需要做一些调整才能使用。首先要在代码开头添加引脚定义:
c复制#include "onewire.h"
#include <stc15.h>
sbit DQ = P1^4;
然后创建一个onewire.h头文件,内容很简单:
c复制#ifndef _ONWIRE_H_
#define _ONWIRE_H_
unsigned int read_18b20();
#endif
这些准备工作完成后,就可以编写温度读取函数了。我的经验是把这个函数分成几个清晰的步骤:初始化、跳过ROM、启动转换、再次初始化、跳过ROM、读取数据。每个步骤都加上简短注释,这样调试时更容易定位问题。
温度读取完成后,我们需要把它显示在数码管上。蓝桥杯板子通常使用共阳数码管,比赛时会提供段码表。显示逻辑很简单:把温度值分解为十位和个位,然后查表显示。
这里有个实用技巧:使用定时器中断来实现数码管动态扫描。这样既能保证显示稳定,又不会阻塞主程序。我在代码中设置了一个1ms的定时器中断,在中断服务程序里依次刷新每个数码管。
实际测试时可能会遇到温度值偶尔跳动的情况。我通常会在代码中加入简单的防抖处理:连续读取三次,取中间值作为最终结果。另外,建议对读取到的温度值做范围检查,比如设定0-50℃的合理范围,超出这个范围的数据视为无效。
还有一个常见问题是DS18B20偶尔会返回85℃这个默认值。这通常表示通信出现问题,可能是时序不对或者硬件连接不良。遇到这种情况,最好的办法是重新初始化传感器。
调试DS18B20时,我总结了一些实用技巧。首先,准备一个示波器或者逻辑分析仪非常有用,可以直观地观察单总线上的信号波形。如果没有这些设备,也可以用软件方式把关键数据通过串口打印出来。
其次,建议在代码中加入调试输出。比如在每次读取温度后,把原始数据通过串口发送到电脑上。这样当出现问题时,你可以清楚地看到是哪个环节出了错。
最后,记得给DS18B20足够的响应时间。我有次为了追求速度,把延时时间设得太短,结果传感器经常无响应。后来按照数据手册的建议调整后,问题就解决了。这也提醒我,在嵌入式开发中,有时候慢一点反而更可靠。