2026/7/9 23:27:30

STM32 DS18B20 多点测温系统:1条总线挂载8个传感器与ROM搜索算法实现

STM32 DS18B20 多点测温系统:1条总线挂载8个传感器与ROM搜索算法实现 STM32 DS18B20 多点测温系统1条总线挂载8个传感器与ROM搜索算法实现在工业自动化、农业温室监测、机房环境监控等场景中分布式温度采集系统往往需要同时监测多个位置的温度数据。传统方案需要为每个传感器单独布线不仅增加了硬件成本也使得系统复杂度大幅提升。DS18B20作为一款支持单总线通信的数字温度传感器通过独特的ROM寻址机制允许在一条总线上挂载多个设备极大简化了硬件设计。本文将深入解析基于STM32的多点测温系统实现方案涵盖硬件设计、ROM搜索算法、温度轮询采集等关键技术。1. 系统架构与硬件设计1.1 单总线网络拓扑结构DS18B20采用单总线1-Wire通信协议仅需一根数据线即可完成双向数据传输。在多点测温系统中所有传感器并联连接到主控器的同一GPIO引脚典型连接方式如下[STM32 GPIO]---[4.7KΩ上拉电阻]---[VCC 3.3V] | ---[DS18B20 #1]---[DS18B20 #2]--- ... ---[DS18B20 #8] | GND关键参数计算上拉电阻选择4.7KΩ3.3V供电或5.1KΩ5V供电总线电容限制总线上所有DS18B20的寄生电容之和应小于800pF传输距离理论上可达100米实际应用中建议不超过30米提示寄生供电模式下需在温度转换期间提供强上拉通过MOSFET将总线直接拉至VCC1.2 硬件接口电路设计STM32与DS18B20的典型连接电路如下表所示元件参数/型号作用说明R14.7KΩ ±5%总线默认上拉电阻Q12N7002寄生供电强上拉开关可选C1100nF电源去耦电容DS18B20TO-92封装温度传感器最多可挂载8个寄生供电模式注意事项每个传感器工作电流约1mA总线需提供足够驱动能力温度转换期间最长750ms需保持强上拉建议在传感器就近放置0.1μF退耦电容1.3 总线负载能力验证为确保通信可靠性需验证总线上所有传感器的并联负载不会导致信号畸变。总线总电容计算公式C_total N × C_DS18B20 C_stray其中N传感器数量C_DS18B20单个传感器寄生电容典型值50pFC_stray布线杂散电容约50pF/m对于8个DS18B20的系统C_total 8×50pF 1m×50pF 450pF 800pF安全范围2. ROM搜索算法实现2.1 64位ROM编码结构每个DS18B20内置全球唯一的64位ROM编码结构如下字节位置内容说明Byte 00x28产品家族码DS18B20固定值Byte 1-648位序列号设备唯一标识Byte 78位CRC校验码前7字节的CRC校验2.2 递归式搜索算法实现ROM搜索采用二叉树遍历思想通过位冲突检测识别总线上所有设备。以下是递归实现的核心代码// 递归搜索函数 void DS18B20_SearchROM(uint8_t *rom_list, uint8_t *dev_count, uint8_t depth, uint64_t current_rom) { if (depth 64) { rom_list[(*dev_count) * 8] (current_rom 56) 0xFF; rom_list[(*dev_count) * 8 1] (current_rom 48) 0xFF; // ... 存储完整64位ROM (*dev_count); return; } uint8_t bit_pos depth % 8; uint8_t byte_pos depth / 8; // 尝试该位为0 if (DS18B20_TryBit(rom_list, *dev_count, depth, 0)) { current_rom ~(1ULL (63 - depth)); DS18B20_SearchROM(rom_list, dev_count, depth 1, current_rom); } // 尝试该位为1 if (DS18B20_TryBit(rom_list, *dev_count, depth, 1)) { current_rom | (1ULL (63 - depth)); DS18B20_SearchROM(rom_list, dev_count, depth 1, current_rom); } } // 位测试函数 uint8_t DS18B20_TryBit(uint8_t *rom_list, uint8_t dev_count, uint8_t depth, uint8_t bit_value) { DS18B20_Reset(); DS18B20_WriteByte(0xF0); // Search ROM命令 // 发送已知ROM位 for (uint8_t i 0; i depth; i) { uint8_t bit (rom_list[(dev_count * 8) (i / 8)] (i % 8)) 0x01; DS18B20_WriteBit(bit); } // 发送当前测试位 DS18B20_WriteBit(bit_value); // 读取响应 uint8_t id_bit DS18B20_ReadBit(); uint8_t cmp_bit DS18B20_ReadBit(); if (id_bit 1 cmp_bit 1) return 0; // 无设备响应 if (id_bit ! cmp_bit) return 1; // 唯一路径 return (id_bit bit_value); // 冲突检测 }2.3 迭代优化版本对于资源受限的嵌入式系统可采用迭代方式避免递归栈消耗void DS18B20_FindAllROM(uint8_t *rom_list, uint8_t *dev_count) { uint8_t last_discrepancy 0; uint8_t rom_buffer[8] {0}; *dev_count 0; while (*dev_count MAX_DEVICES) { uint8_t discrepancy_marker 0; uint8_t is_search_done 1; DS18B20_Reset(); DS18B20_WriteByte(0xF0); // Search ROM for (uint8_t bit_pos 0; bit_pos 64; bit_pos) { uint8_t bit DS18B20_ReadBit(); uint8_t cmp_bit DS18B20_ReadBit(); uint8_t byte_pos bit_pos / 8; uint8_t mask 1 (bit_pos % 8); if (bit cmp_bit) break; // 无设备 if (!bit !cmp_bit) { // 冲突位 if (bit_pos last_discrepancy) { bit (rom_buffer[byte_pos] mask) ? 1 : 0; } else { bit (bit_pos last_discrepancy) ? 1 : 0; } if (!bit) discrepancy_marker bit_pos; } if (bit) rom_buffer[byte_pos] | mask; else rom_buffer[byte_pos] ~mask; DS18B20_WriteBit(bit); } if (bit_pos 64) { // 完整ROM找到 memcpy(rom_list[(*dev_count) * 8], rom_buffer, 8); (*dev_count); last_discrepancy discrepancy_marker; is_search_done (last_discrepancy 0); } if (is_search_done) break; } }3. 多点温度采集框架3.1 轮询采集策略针对8个传感器的温度采集可采用以下两种策略策略一顺序采集发送Skip ROM Convert T命令所有传感器同时开始转换等待750ms12位分辨率依次匹配每个ROM并读取温度策略二并行启动分时读取// 启动所有传感器转换 DS18B20_Reset(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0x44); // Convert T // 等待转换完成 Delay_ms(750); // 逐个读取温度 for (uint8_t i 0; i dev_count; i) { DS18B20_Reset(); DS18B20_WriteByte(0x55); // Match ROM for (uint8_t j 0; j 8; j) { DS18B20_WriteByte(rom_list[i*8 j]); } DS18B20_WriteByte(0xBE); // Read Scratchpad uint8_t temp_l DS18B20_ReadByte(); uint8_t temp_h DS18B20_ReadByte(); // ... 数据处理 }3.2 温度数据管理建议采用结构体数组管理多个传感器数据typedef struct { uint8_t rom[8]; float temperature; uint32_t last_update; uint8_t crc_valid; } DS18B20_Device; DS18B20_Device sensor_pool[MAX_DEVICES]; void UpdateTemperatures(void) { for (uint8_t i 0; i MAX_DEVICES; i) { if (ReadSensorTemperature(i, sensor_pool[i].temperature)) { sensor_pool[i].last_update HAL_GetTick(); sensor_pool[i].crc_valid 1; } } }3.3 异常处理机制常见问题及解决方案问题现象可能原因解决方案读取温度固定为85℃电源上电初始值检查总线连接确保转换完成CRC校验失败总线干扰或时序问题降低通信速率增加重试机制部分传感器无法检测ROM搜索不完整优化搜索算法增加搜索深度温度值跳变过大电源噪声干扰增加去耦电容改用外部供电4. 寄生供电优化方案4.1 强上拉电路设计当使用寄生供电时需在温度转换期间提供额外电流。典型电路设计VCC | / \ / \ R2 MOSFET (Q1) \ / \ / | ---[1-Wire Bus]元件选型R2100Ω限流电阻Q1SI2302SOT-23封装低导通电阻触发时机发送Convert T命令后立即激活持续至少750ms4.2 软件控制流程void DS18B20_StartConversion_Parasitic(void) { DS18B20_Reset(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0x44); // Convert T // 激活强上拉 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin DS18B20_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DS18B20_PORT, GPIO_InitStruct); HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET); // 启动定时器750ms后恢复 HAL_TIM_Base_Start_IT(htim, 750); } // 定时器中断回调 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim htim) { // 恢复开漏模式 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin DS18B20_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull GPIO_PULLUP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DS18B20_PORT, GPIO_InitStruct); } }4.3 电源噪声抑制PCB布局建议总线走线尽量短避免形成天线效应在传感器VDD与GND之间放置100nF陶瓷电容强上拉路径使用至少20mil线宽避免总线与高频信号线平行走线实测表明良好的电源设计可将温度采集误差控制在±0.2℃以内。在电磁环境复杂的工业场景中建议采用屏蔽双绞线传输单总线信号。