多数通用单片机无原生1-Wire硬件模块,GPIO软件模拟最可控,但需精确控制时序;DS18B20复位与读写窗口容差仅±1μs,必须严格遵循拉低/释放时间及采样点(释放后15μs);GPIO须开漏+外接4.7kΩ上拉,禁用浮空;单器件可用Skip ROM(0xCC)提速,但首次通信或复位后可能需先执行Read ROM(0x33)。

为什么不能直接用硬件1-Wire外设
多数通用单片机(如STM32F1/F4、GD32、ESP32-C3)没有原生1-Wire硬件模块;即使有(如某些AVR或DS2480B配套芯片),也常因驱动复杂、时序难调、库不开放而放弃。实际项目里,GPIO软件模拟是最可控、最易移植的方案——前提是能精确控制高低电平持续时间。
关键时序必须死守:DS18B20复位与采样窗口
DS18B20对时序极其敏感,尤其复位脉冲(Reset Pulse)和读/写时间片(Time Slot)。实测中,超±1μs偏差就可能漏读或误判。核心三段:
-
复位请求:主控拉低
480–960μs→ 释放总线 → 等待15–60μs→ 读取从机应答脉冲(60–240μs低电平) -
写“1”:拉低 ≤
15μs后释放,维持高电平 ≥60μs -
读采样:拉低 ≤
15μs后释放,**在释放后 15μs 处采样电平**(不是立刻读!)
注意:__NOP() 或 __delay_us() 在不同编译优化等级下行为不一致;建议用定时器(如SysTick)做微秒级延时,或手写汇编循环(仅限裸机且主频已知场景)。
GPIO配置必须开漏+上拉,且禁止浮空
1-Wire是开漏总线,必须外接 4.7kΩ 上拉电阻(VDD到数据线),且MCU引脚必须设为开漏输出(GPIO_MODE_OUTPUT_OD)或推挽输出+手动控制电平(需确保释放时呈高阻态)。常见错误:
- 设成推挽输出但未在“释放总线”时切为输入模式 → 总线被强拉低,从机无法响应
- 没接上拉电阻,或上拉接到3.3V却给DS18B20供电5V → 通信电压不匹配,读数全为
0xFF或0x00 - 使用内部上拉(如STM32的
PULL_UP)→ 驱动能力弱,上升沿过缓,导致采样时刻误判为低电平
实操建议:初始化时先置GPIO为推挽输出并拉高,再切为开漏;每次“释放总线”前,务必切换回输入模式(GPIO_MODE_INPUT)并启用上拉(若硬件允许),否则靠外部电阻上拉需要时间,会拖慢时序。
读ROM和跳过ROM指令的选择直接影响多器件支持
单总线上挂多个DS18B20时,必须用0x33(Read ROM)获取64位ROM码,再用0x55(Match ROM)寻址指定器件。但若只接一个传感器,用0xCC(Skip ROM)可省掉ROM交互,加快流程——不过要注意:部分DS18B20在刚上电或复位后首次通信必须执行Read ROM,否则后续命令(如0x44启动转换)无响应。
温度读取典型流程:
// 1. 复位 ow_reset(); // 2. 跳过ROM(单器件) ow_write_byte(0xCC); // 3. 启动温度转换 ow_write_byte(0x44); // 4. 延时750ms(寄存器默认12位分辨率) delay_ms(750); // 5. 再次复位 ow_reset(); // 6. 跳过ROM ow_write_byte(0xCC); // 7. 读取温度寄存器(2字节) uint8_t buf[2]; ow_read_bytes(buf, 2);
真正容易被忽略的是:DS18B20在0x44之后进入忙状态,此时若立即发ow_reset(),可能遭遇总线冲突;必须等它完成转换(查0xB8寄存器或硬延时),且第二次复位前确保总线已稳定高电平至少2μs。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











