在嵌入式开发领域,温度监测是最基础却又最常遇到的需求之一。DS18B20这款单总线数字温度传感器,以其独特的1-Wire协议和高达±0.5℃的精度,成为了51单片机项目中的常客。我第一次接触这个传感器是在一个农业大棚监控项目中,当时需要低成本实现多点温度监测,DS18B20+STC89C52的组合完美解决了问题。
相比传统的模拟温度传感器,DS18B20最大的优势在于它将ADC转换器集成在传感器内部,直接输出数字信号,省去了单片机额外的ADC模块需求。而且单总线协议意味着只需要一根数据线就能实现通信,这对IO资源紧张的51单片机来说简直是雪中送炭。不过在实际使用中,时序控制是最大的难点,这也是很多初学者容易栽跟头的地方。
DS18B20支持寄生供电和外部供电两种模式。在51单片机项目中,我强烈推荐使用外部供电方式(VCC接5V),虽然要多占用一条电源线,但稳定性远胜寄生供电。典型连接方式如下:
code复制DS18B20引脚说明:
1-GND → 单片机GND
2-DQ → 单片机P2.0(需接4.7K上拉电阻)
3-VDD → 单片机5V
关键细节:上拉电阻绝对不能省略!我曾遇到过因为忘记加上拉电阻导致通信时好时坏的诡异问题,排查了整整两天。
当需要多个DS18B20组网时,可以采用总线型拓扑。所有传感器的DQ线并联在一起,通过各自的64位ROM地址进行区分。这里有个实用技巧:在硬件设计时,建议给每个DS18B20预留单独的测试点,这样在调试时可以单独检测每个传感器。
51单片机驱动DS18B20的核心在于精确的时序控制。由于没有硬件1-Wire控制器,所有时序都需要用软件模拟。以下是复位脉冲的典型代码:
c复制// DS18B20复位函数
bit DS18B20_Reset() {
bit presence;
DQ = 0; // 拉低总线
delay_us(480); // 保持480us以上
DQ = 1; // 释放总线
delay_us(60); // 等待15-60us
presence = DQ;// 采样存在脉冲
delay_us(420); // 等待存在脉冲结束
return presence;
}
血泪教训:不同型号的51单片机指令周期不同,delay_us()必须根据实际主频调整。我曾因疏忽这点,在STC12C5A60S2上直接移植STC89C52的延时函数,导致通信完全失败。
标准的温度读取流程包括:初始化→跳过ROM→启动转换→延时→初始化→匹配ROM→读取暂存器。在实际项目中,我发现两个优化点:
以下是优化后的温度读取代码片段:
c复制float DS18B20_ReadTemp() {
unsigned char tempL, tempH;
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 启动转换
while(!DQ); // 等待转换完成
DS18B20_Reset();
DS18B20_WriteByte(0xCC);
DS18B20_WriteByte(0xBE); // 读暂存器
tempL = DS18B20_ReadByte();
tempH = DS18B20_ReadByte();
return (tempH<<8|tempL) * 0.0625;
}
工业环境中温度读数常会出现毛刺。我常用的三重滤波方案:
c复制#define FILTER_SIZE 5
float temp_history[FILTER_SIZE];
float filter_temp(float new_temp) {
// 中值滤波实现
for(int i=FILTER_SIZE-1; i>0; i--) {
temp_history[i] = temp_history[i-1];
}
temp_history[0] = new_temp;
// 排序找中值
float sorted[FILTER_SIZE];
memcpy(sorted, temp_history, sizeof(sorted));
bubble_sort(sorted, FILTER_SIZE);
return sorted[FILTER_SIZE/2];
}
在电机控制等干扰强的场合,这些措施很有效:
根据我的维修记录,DS18B20故障TOP3:
当出现85℃/-127℃等特殊值时:
在冷链监控项目中,我实现了最多挂接12个DS18B20的系统。关键点在于:
c复制// 简化的多点测温流程
void multi_point_measure() {
for(int i=0; i<dev_count; i++) {
DS18B20_Reset();
DS18B20_WriteByte(0x55); // 匹配ROM
for(int j=0; j<8; j++) {
DS18B20_WriteByte(rom_codes[i][j]);
}
DS18B20_WriteByte(0x44); // 启动转换
delay_ms(10); // 简单延时,实际应用应优化
}
// 后续读取各传感器数据...
}
对于电池供电的设备,这些方法可延长续航:
经过实测,在12位精度、每分钟采样一次的情况下,整个系统平均电流可控制在0.5mA以下。