51单片机-18B20温度传感器:从单总线协议到多路测温系统设计 📅 2026/7/15 13:52:31 1. 认识DS18B20温度传感器第一次接触DS18B20是在大学电子设计课上当时老师要求用51单片机做个温控风扇。这个只有三个引脚的小芯片让我印象深刻——它居然能直接输出数字温度信号相比需要复杂ADC电路的热敏电阻DS18B20简直是新手福音。DS18B20的核心优势在于其单总线通信协议。传统温度传感器需要模拟信号线电源线地线而它只需要一根数据线就能完成供电和通信寄生供电模式下甚至只需两根线。实测中发现在3.0V-5.5V宽电压范围内都能稳定工作测量范围-55℃到125℃精度可达±0.5℃12位分辨率时。这个传感器的内部结构很有意思64位ROM相当于身份证号前8位是家族码28h代表DS18B20中间48位是唯一序列号最后8位是CRC校验码。正是这个设计让多传感器并联成为可能温度灵敏元件直接输出9-12位的二进制温度值非易失性存储器可以保存温度报警阈值TH/TL断电不丢失实际项目中踩过的坑寄生供电模式下当进行温度转换时电流需求骤增最高1.5mA如果总线电容不足会导致电压跌落。解决方法是在数据线加4.7kΩ上拉电阻的同时并联一个100nF电容储能。2. 单总线协议深度解析刚开始调DS18B20时最头疼的就是那个严苛的时序要求。有次调试整整一天都没反应最后发现是延时函数少了个nop指令。这里把关键时序拆解给大家2.1 初始化时序复位脉冲// 51单片机示例代码 bit DS18B20_Init() { DQ 0; // 拉低总线 delay_us(480); // 保持480-960us DQ 1; // 释放总线 delay_us(60); // 等待15-60us return DQ; // 0表示存在1表示不存在 }这个复位脉冲就像敲门传感器收到后会回个应答脉冲。实测中发现拉低时间少于480us可能导致无应答应答信号出现在释放总线后15-60us窗口期总线恢复时间至少480us后才能进行下一步操作2.2 读写时序对比通过示波器抓取的波形显示如下图写0需要保持60us低电平而写1在拉低2us后就要释放总线写时序技巧void DS18B20_WriteByte(uchar dat) { for(int i0; i8; i) { DQ 0; // 拉低开始写周期 _nop_(); _nop_(); // 保持至少1us DQ dat 0x01; // 发送最低位 delay_us(60); // 保持写周期 DQ 1; // 释放总线 dat 1; // 准备下一位 } }读时序要点主机拉低总线至少1us后释放必须在15us内采样数据线状态整个读时隙不少于60us实测发现温度转换期间读取会返回0xFF3. 多路测温系统设计去年给温室大棚做环境监控时需要在20米范围内布置8个测温点。DS18B20的多点组网能力派上了大用场具体实现方案如下3.1 硬件连接优化----------------- | 51单片机 | | P3.7 - DQ | ---------------- | ------------------------------ 4.7kΩ | | 上拉电阻 | | --- | | | | | 100nF 100nF 100nF | | | ---- ---- ---- | DS1 | | DS2 | ... | DS8 | ----- ----- -----布线经验总线长度超过10米时改用屏蔽双绞线每增加5个传感器上拉电阻减小1kΩ分支线长度控制在1米内避免信号反射3.2 传感器寻址策略通过ROM匹配实现精准寻址流程如下发送搜索ROM命令0xF0读取所有传感器的位数据构建二进制搜索树逐个记录64位ROM码// 示例ROM搜索代码 void DS18B20_SearchROM(uint8_t *ROM_LIST) { uint8_t last_diff 0; uint8_t search_dir 0; Reset_DS18B20(); Write_DS18B20(0xF0); // 搜索ROM命令 for(int bit_idx0; bit_idx64; bit_idx) { int byte_pos bit_idx/8; int bit_mask 1(bit_idx%8); int bit1 Read_DS18B20(); int bit2 Read_DS18B20(); if(bit1 bit2) { // 无设备响应 break; } else if(bit1 ! bit2) { // 所有设备该位相同 ROM_LIST[byte_pos] | (bit1 ? bit_mask : 0); } else { // 存在分歧位 if(bit_idx last_diff) { search_dir 1; } else if(bit_idx last_diff) { search_dir 0; last_diff bit_idx; } ROM_LIST[byte_pos] | (search_dir ? bit_mask : 0); } Write_DS18B20(search_dir); } }4. 完整工程实现结合LCD显示和串口上传功能分享一个经过实际验证的代码框架4.1 驱动层封装// ds18b20.h #ifndef __DS18B20_H__ #define __DS18B20_H__ #include reg52.h sbit DQ P3^7; // 单总线接口 float DS18B20_GetTemp(void); void DS18B20_SetResolution(uint8_t res); uint8_t DS18B20_ScanDevices(uint8_t *rom_codes); #endif4.2 应用层实现// main.c #include ds18b20.h #include lcd1602.h #include uart.h uint8_t rom_codes[8][8]; // 存储最多8个传感器ROM码 void main() { UART_Init(9600); LCD_Init(); uint8_t dev_count DS18B20_ScanDevices(rom_codes); printf(Found %d devices\r\n, dev_count); while(1) { for(int i0; idev_count; i) { DS18B20_MatchROM(rom_codes[i]); float temp DS18B20_GetTemp(); LCD_SetCursor(0, i); LCD_Printf(T%d:%4.1fC, i1, temp); printf(Sensor%d: %.1fC\r\n, i, temp); } delay_ms(1000); } }4.3 抗干扰设计在工业现场应用中还需要增加以下保护措施总线加TVS二极管防静电采用磁珠隔离数字噪声每30米增加总线中继器软件上增加CRC校验和数据重传机制温度转换期间实测发现电源会出现约1ms的50mV纹波。通过以下电源滤波电路可有效抑制--- --- 5V -----| L |----| C |--- VDD --- | --- 100μF | GND5. 性能优化技巧经过多个项目验证总结出这些实用经验转换速度优化9位分辨率时转换时间94ms12位时750ms对于实时性要求高的场景可以DS18B20_WriteByte(0x44); // 启动转换 while(!DQ); // 等待转换完成总线变高功耗控制休眠模式下电流仅750nA采用间歇工作模式每5分钟唤醒测量一次温度报警应用// 设置报警阈值 void DS18B20_SetAlarm(int8_t TH, int8_t TL) { DS18B20_WriteByte(0x4E); // 写暂存器 DS18B20_WriteByte(TH); DS18B20_WriteByte(TL); DS18B20_WriteByte(0x7F); // 配置寄存器 DS18B20_WriteByte(0x48); // 复制到EEPROM }异常处理总线冲突时复位所有设备增加温度变化率检测2℃/秒视为异常对连续3次读取失败