1. 系统设计概述
想要用51单片机做个多路温度监测系统?这事儿听起来高大上,但实际操作起来并没有想象中那么难。我去年给一个温室大棚项目做过类似的方案,用4路DS18B20传感器+LCD1602显示屏,整套成本不到50块钱。单总线协议是这里的关键技术,一根线就能串联多个传感器,布线特别方便。
先说说这个系统的核心部件:STC89C52单片机(老牌51核)、DS18B20温度传感器(防水不锈钢头版本)、LCD1602液晶屏,再加上几个按键和蜂鸣器。Proteus仿真时我推荐用7.8以上版本,实测发现新版对单总线协议的支持更稳定。整个系统的工作流程是这样的:单片机轮流读取各传感器数据→处理温度值→显示在LCD上→超限就声光报警。这里有个实用技巧:DS18B20的供电建议用寄生供电模式,能省掉一堆电源线,但要注意总线负载不能超过3个传感器。
2. 硬件电路设计要点
2.1 单片机最小系统
51单片机最小系统就是经典的"三件套":11.0592MHz晶振(做串口通信时这个频率最准)、22pF负载电容、10kΩ上拉电阻的复位电路。Proteus里直接搜"AT89C51"就能找到模型,注意仿真时要把EA引脚接高电平。I/O口分配建议:
- P1.0~P1.3:接DS18B20数据线(多路时需要加4.7kΩ上拉)
- P2口:接LCD1602数据线
- P3.2/P3.3:接报警设置按键
- P3.7:接蜂鸣器
2.2 多路DS18B20连接
单总线挂多个传感器有两种接法:一种是每个传感器单独接上拉电阻(稳定但费IO口),另一种是用模拟开关切换(省IO但程序复杂)。我推荐第一种,虽然要占用多个IO口,但程序写起来简单。具体接线要注意:
- 每个DS18B20的DQ线串联4.7kΩ电阻到VCC
- 传感器金属外壳要接地,防止静电损坏
- 传输距离超过3米时要在数据线加屏蔽层
Proteus里搜索"DS18B20"调出模型,右键属性可以设置初始温度值,调试时特别有用。遇到过最坑的问题是仿真时传感器不响应,后来发现是没勾选"Use Advanced Model"选项。
3. 单总线协议实现细节
3.1 初始化时序
单总线通信的第一步永远是复位脉冲。用C51写的话,关键代码就几行:
void DS18B20_Reset(uint8_t pin) { DQ = 0; // 拉低480us delay_us(480); DQ = 1; // 释放总线 delay_us(60); while(DQ); // 等待传感器回应 delay_us(420); }实测发现延时误差不能超过±15%,否则传感器会无响应。有个取巧的方法:用_nop_()指令做微秒级延时,比定时器更准。
3.2 ROM匹配算法
多路测温时必须先匹配64位ROM编码。每个DS18B20出厂时都有唯一ID,可以通过搜索算法获取:
- 发F0h搜索指令
- 逐位读取所有传感器的位状态
- 根据冲突情况选择分支 这个算法稍复杂,建议直接套用官方示例代码。我优化过的版本能在200ms内完成4路传感器搜索。
4. 温度采集与处理
4.1 启动温度转换
发完匹配ROM命令后,发送44h启动转换。这里有个坑:12位精度转换需要750ms,期间如果读总线会返回0。建议这样处理:
DS18B20_WriteByte(0x44); delay_ms(800); // 预留余量 while(!DQ); // 等待转换完成4.2 读取温度数据
温度值以16位补码形式存储,读取后要处理符号位。分享个经过实测的转换函数:
float GetTemperature(uint8_t pin) { int16_t temp = DS18B20_ReadByte(); temp |= DS18B20_ReadByte() << 8; if(temp & 0x8000) temp = -(temp & 0x7FFF); // 处理负温 return temp * 0.0625; // 12位精度系数 }特别注意:DS18B20的0.5℃精度是硬件保证的,但软件处理时浮点运算会引入额外误差,建议将所有温度值放大100倍后用整型运算。
5. LCD1602显示驱动
5.1 初始化序列
LCD1602的4位模式能节省IO口,初始化时要先发三次0x28。我遇到的典型问题是第一行字符乱码,后来发现是忙检测函数没写好。改进后的代码:
void LCD_BusyCheck() { do { RS = 0; RW = 1; P2 = 0xFF; // 端口置输入 EN = 1; delay_us(1); } while(P2 & 0x80); // 检测BF位 EN = 0; }5.2 温度显示优化
显示格式建议:"T1:25.5C T2:26.0C",交替显示各路温度。实测发现LCD刷新率超过2Hz会闪烁,可以用定时器做分时刷新。报警值显示用反白效果更醒目:
void LCD_Invert(uint8_t pos) { LCD_WriteCmd(0x80 + pos); LCD_WriteData(LCD_ReadData() | 0x80); // 设置反白 }6. 报警功能实现
6.1 按键设置阈值
用三个按键实现设置功能:SET键进入设置模式,UP/DOWN调整数值。防抖处理很关键,我的方案是:
if(!KEY_SET) { delay_ms(20); // 延时去抖 if(!KEY_SET) { while(!KEY_SET); // 等待释放 setting_mode = !setting_mode; } }6.2 声光报警逻辑
超限报警建议用非阻塞式设计,避免影响温度采集:
if(temp > threshold) { static uint8_t cnt; BUZZER = cnt < 50; // 产生断续音 LED = ~LED; if(++cnt >= 100) cnt = 0; }7. Proteus仿真技巧
7.1 调试单总线通信
打开Proteus的"Digital Oscilloscope",监测DQ线波形。正常时序应该能看到:
- 480us低电平复位脉冲
- 60us传感器回应脉冲
- 写时序的15us低电平窗口
7.2 多传感器仿真
在DS18B20属性里设置不同的ROM编码,模拟实际设备。遇到过两个传感器冲突的情况,后来发现是ROM码设置重复了。
8. 实际项目经验
去年做的农业大棚项目里,发现DS18B20在高温高湿环境容易结露导致误报。改进方案:
- 给传感器套热缩管防水
- 软件上增加连续3次超限才触发报警
- 每月自动校准一次零点(冰水混合物测试)
电源干扰也是常见问题,建议在单片机电源脚加100μF+0.1μF电容组合。曾有个客户现场因为继电器动作导致温度跳变,后来在传感器电源端加磁珠解决了。