从 底层硬件原理、时序细节、代码优化、通信协议 四个维度进行更深入的解析,并补充实际开发中的调试经验和注意事项:
一、DS18B20 硬件连接与电气特性
1. 引脚定义
DS18B20 通常有三个引脚:
- VDD:电源(3.0V~5.5V,可选外部供电或寄生供电)
- GND:地
- DQ:数据输入 / 输出,需外接 4.7kΩ 上拉电阻 到 VDD
2. 上拉电阻的作用
- 释放总线:当单片机将 DQ 引脚配置为输入模式或输出高电平时,上拉电阻将总线拉高。
- 信号完整性:确保高电平信号的稳定性,抵抗噪声干扰。
3. 寄生供电模式
DS18B20 支持 寄生供电(VDD 和 GND 短接),此时:
- 电源通过 DQ 引脚获取(DQ 高电平时储能,低电平时消耗能量)。
- 温度转换等操作需更长时间(约 750ms)。
- 需在温度转换期间保持 DQ 高电平(通过
DS18B20_WriteByte(0x44)
后持续拉高 DQ)。
二、单总线协议的时序细节(纳秒级精度)
1. 写时序的精确参数(基于 DS18B20 数据手册)
时序参数 | 最小值 (μs) | 典型值 (μs) | 最大值 (μs) | 说明 |
---|---|---|---|---|
tLOW0(写 0 低电平时间) | 60 | - | 120 | 写 0 时,主设备拉低总线的时间 |
tLOW1(写 1 低电平时间) | 1 | - | 15 | 写 1 时,主设备拉低总线的时间 |
tREC(恢复时间) | 1 | - | - | 位传输后总线的恢复时间 |
tSAMPLE(采样时间) | 15 | - | - | DS18B20 采样总线电平的时间窗口 |
tSLOT(位时间) | 60 | - | 120 | 每个位传输的最小持续时间 |
2. 时序图详解(写 1 和写 0 对比)
三、代码性能优化与临界区保护
1. 禁用中断确保时序精确性
在时序关键代码段禁用中断,避免中断处理函数干扰延时精度:
static void DS18B20_WriteByte(uint8_t dat)
{
uint8_t i, testb;
__disable_irq(); // 禁用中断(根据单片机平台不同,函数名可能不同)
DS18B20_Mode_Out_PP();
for(i = 0; i < 8; i++) {
testb = dat & 0x01;
dat = dat >> 1;
if(testb) {
DS18B20_Dout_LOW();
DS18B20_Delay(96); // 约15μs
DS18B20_Dout_HIGH();
DS18B20_Delay(696); // 约60μs
}
else {
DS18B20_Dout_LOW();
DS18B20_Delay(696); // 约60μs
DS18B20_Dout_HIGH();
DS18B20_Delay(96); // 约15μs
}
}
__enable_irq(); // 恢复中断
}
2. 延时函数的高精度实现
基于定时器的微秒级延时(以 STM32 为例):
// 初始化 SysTick 定时器(通常在系统初始化时调用)
void SysTick_Init(void) {
// 设置 SysTick 为 1μs 中断一次
SysTick_Config(SystemCoreClock / 1000000); // 假设系统时钟为 72MHz
}
// 微秒级延时(阻塞式)
static volatile uint32_t micros = 0;
void delay_us(uint32_t us) {
uint32_t start = micros;
while((micros - start) < us);
}
// SysTick 中断处理函数
void SysTick_Handler(void) {
micros++;
}
四、DS18B20 通信协议完整解析
1. 完整通信流程
- 初始化:发送复位脉冲 → 检测 DS18B20 的存在脉冲。
- ROM 操作:
- 跳过 ROM(单设备):发送
0xCC
- 匹配 ROM(多设备):发送
0x55
+ 64 位设备 ID
- 跳过 ROM(单设备):发送
- 功能命令:
- 启动温度转换:
0x44
- 读取暂存器:
0xBE
- 写入配置:
0x4E
+ 配置数据
- 启动温度转换:
2. 温度转换与读取流程
// 读取 DS18B20 温度值(返回值单位:0.01℃)
int16_t DS18B20_ReadTemperature(void) {
uint8_t LSB, MSB;
int16_t temp;
DS18B20_Reset(); // 初始化
DS18B20_WriteByte(0xCC); // 跳过 ROM
DS18B20_WriteByte(0x44); // 启动温度转换
// 等待转换完成(寄生供电模式需主动拉高总线)
HAL_Delay(750); // 等待 750ms(最大转换时间)
DS18B20_Reset(); // 再次初始化
DS18B20_WriteByte(0xCC); // 跳过 ROM
DS18B20_WriteByte(0xBE); // 发送读取暂存器命令
LSB = DS18B20_ReadByte(); // 读取温度低字节
MSB = DS18B20_ReadByte(); // 读取温度高字节
temp = (MSB << 8) | LSB; // 组合为 16 位温度值
return temp * 0.0625 * 100; // 转换为 0.01℃ 单位
}
详细讲解如何使用IO口读取一个字节数据
int8_t DS18B20_ReadByte(void) {
uint8_t i, dat = 0;
// 配置引脚为推挽输出模式(主动控制电平)
DS18B20_Mode_Out_PP();
// 循环读取 8 位数据(低位在前,高位在后)
for(i = 0; i < 8; i++) {
// 1. 拉低总线 1~15μs,发起读时隙
DS18B20_Dout_LOW();
DS18B20_Delay(12); // 延时约 2μs(实际延时需根据 MCU 时钟调整)
// 2. 释放总线,准备接收数据
DS18B20_Dout_HIGH();
// 3. 配置为输入模式,读取总线电平
DS18B20_Mode_IPU();
// 4. 等待 15μs 窗口,确保 DS18B20 已驱动数据到总线
DS18B20_Delay(12); // 延时约 2μs(进入采样窗口)
// 5. 读取当前位数据(0 或 1)
if(DS18B20_ReadInput()) { // 读取引脚电平
dat |= (1 << i); // 若为高电平,将当前位设为 1
}
// 6. 等待读时隙结束(确保总时隙时间 ≥60μs)
DS18B20_Delay(60); // 延时约 10μs(补足 60μs 总时间)
}
return dat;
}
五、实际开发中的调试技巧
1. 硬件调试
-
示波器观察时序:
- 使用示波器监测 DQ 引脚,验证拉低 / 拉高时间是否符合规范。
- 典型问题:延时函数不准确导致时序偏移。
-
上拉电阻检查:
- 无 / 过小的上拉电阻会导致总线无法可靠拉高。
- 过大的上拉电阻会增加信号上升时间,导致通信失败。
2. 软件调试
-
添加调试日志:
#define DEBUG 1 #if DEBUG #define DBG_PRINT(...) printf(__VA_ARGS__) #else #define DBG_PRINT(...) #endif // 在关键位置添加日志 void DS18B20_WriteByte(uint8_t dat) { DBG_PRINT("Writing byte: 0x%02X\n", dat); // ... 原有代码 ... }
-
单步执行测试:
- 使用调试器单步执行代码,观察总线状态变化。
- 断点验证每个位的发送时序。
六、常见问题与解决方案
问题现象 | 可能原因 | 解决方案 |
---|---|---|
无法检测到 DS18B20 | 1. 硬件连接错误 2. 上拉电阻缺失 3. 初始化时序错误 | 1. 检查引脚连接 2. 确认上拉电阻(4.7kΩ) 3. 用示波器检查复位脉冲 |
温度值始终为 85℃ | 1. 通信未建立 2. 温度转换未完成 | 1. 验证初始化和写时序 2. 确保转换时间足够(≥750ms) |
温度值跳动大 | 1. 电源不稳定 2. 干扰过大 3. 上拉电阻不合适 | 1. 添加去耦电容(0.1μF 并联到 VDD/GND) 2. 缩短信号线长度 3. 尝试 2.2kΩ~10kΩ 上拉电阻 |
多设备环境无法区分 | 1. 未发送正确的 ROM 命令 2. 设备 ID 读取错误 | 1. 使用 0xF0 命令扫描总线上的所有设备 ID2. 逐个匹配设备 ID |
七、代码扩展:支持寄生供电模式
// 在寄生供电模式下启动温度转换
void DS18B20_StartConvert_PowerOn(void) {
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过 ROM
DS18B20_WriteByte(0x44); // 启动温度转换
// 保持总线高电平(强上拉)为 DS18B20 供电
DS18B20_Mode_Out_PP();
DS18B20_Dout_HIGH();
// 等待转换完成(至少 750ms)
HAL_Delay(750);
// 释放总线
DS18B20_Dout_LOW();
}
总结
DS18B20 的通信核心在于精确控制时序,需注意:
- 写时序:通过控制拉低总线的时间区分逻辑 0/1。
- 硬件要求:必须外接上拉电阻,确保总线能可靠拉高。
- 软件优化:禁用中断、使用高精度延时函数,保证时序稳定。
- 协议流程:初始化 → ROM 操作 → 功能命令,缺一不可。
掌握这些细节后,你可以进一步扩展功能,如:
- 实现多设备支持(扫描并存储设备 ID)
- 优化温度分辨率(配置寄存器)
- 添加 CRC 校验(验证数据传输正确性)
分享
如何计算从主机到 DS18B20 的写 1 高电平时间?
写时序的时间参数会受到哪些因素的影响?
如何使用示波器准确测量 DS18B20 单总线通信的时序参数?