STM32深入解析DS18B20:硬件、时序与优化全攻略

从 底层硬件原理时序细节代码优化通信协议 四个维度进行更深入的解析,并补充实际开发中的调试经验和注意事项:

一、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. 完整通信流程
  1. 初始化:发送复位脉冲 → 检测 DS18B20 的存在脉冲。
  2. ROM 操作
    • 跳过 ROM(单设备):发送 0xCC
    • 匹配 ROM(多设备):发送 0x55 + 64 位设备 ID
  3. 功能命令
    • 启动温度转换: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);
        // ... 原有代码 ...
    }
    
  • 单步执行测试

    • 使用调试器单步执行代码,观察总线状态变化。
    • 断点验证每个位的发送时序。

六、常见问题与解决方案

问题现象可能原因解决方案
无法检测到 DS18B201. 硬件连接错误
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 命令扫描总线上的所有设备 ID
2. 逐个匹配设备 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 的通信核心在于精确控制时序,需注意:

  1. 写时序:通过控制拉低总线的时间区分逻辑 0/1。
  2. 硬件要求:必须外接上拉电阻,确保总线能可靠拉高。
  3. 软件优化:禁用中断、使用高精度延时函数,保证时序稳定。
  4. 协议流程:初始化 → ROM 操作 → 功能命令,缺一不可。

掌握这些细节后,你可以进一步扩展功能,如:

  • 实现多设备支持(扫描并存储设备 ID)
  • 优化温度分辨率(配置寄存器)
  • 添加 CRC 校验(验证数据传输正确性)

分享

如何计算从主机到 DS18B20 的写 1 高电平时间?

写时序的时间参数会受到哪些因素的影响?

如何使用示波器准确测量 DS18B20 单总线通信的时序参数?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值