第2章 温度传感器(DS18B20):单总线协议详解

DS18B20 这玩意儿,我在温室项目里用了不下上百个。说实话,它是我见过最「省引脚」的数字温度传感器——就一根数据线,既能供电又能传数据。嗯,今天咱们就把它彻底聊透。

2.1 单总线协议到底是什么?

单总线(1-Wire),说白了就是 Dallas 公司搞的一套「一根线走天下」的通信协议。你想想看,传统的 I2C 要两根线,SPI 要三四根,而单总线只需要一根数据线加一根地线。

我刚开始接触时也觉得不可思议:一根线怎么同时传时钟和数据?后来才明白,它靠的是严格的时序——主机通过拉低总线的时间长短来发送「0」和「1」。从机则通过拉低总线来响应。

核心要点:单总线是半双工通信,主机控制所有时序。从机只能被动响应。

2.2 DS18B20 工作原理

DS18B20 内部其实有三个主要部分:

  • 64位 ROM 编码:每个芯片独一无二,支持多设备挂在一根总线上
  • 温度传感器:核心部件,把温度转换成数字量
  • 暂存器(Scratchpad):9字节的临时存储区,存放温度值、配置、CRC 等

我记得第一次用的时候,死活读不到温度。查了半天才发现是 ROM 匹配指令没发对。这里提醒一下:如果你总线上只挂一个 DS18B20,可以用「跳过 ROM」指令(0xCC),省去匹配步骤。

2.3 寄生供电模式

这个模式很有意思。正常供电需要 VDD 接 3.3V 或 5V,但寄生供电模式下,VDD 引脚直接接地,芯片从数据线上「偷电」。

怎么偷的?当总线为高电平时,芯片内部电容充电;当总线为低电平时,电容放电维持工作。但有个坑——温度转换时电流需求大(约 1.5mA),如果总线拉低太久,电容会掉电。

避坑指南:我曾经在温室项目里用了寄生供电,结果冬天温度转换总失败。后来发现是总线拉低时间太长,电容撑不住。解决方案:在数据线上加一个 4.7kΩ 上拉电阻到 VCC,同时确保转换期间总线保持高电平。

我个人习惯:除非引脚特别紧张,否则还是用正常供电模式。寄生供电省的那根线,往往换来一堆调试时间。

2.4 分辨率配置

DS18B20 支持 9 到 12 位分辨率,默认是 12 位。分辨率越高,转换时间越长:

分辨率 转换时间(典型值) 温度精度
9 位 93.75 ms 0.5°C
10 位 187.5 ms 0.25°C
11 位 375 ms 0.125°C
12 位 750 ms 0.0625°C

你想想看,温室环境温度变化很慢,0.5°C 的精度完全够用。我一般设成 9 位,转换一次不到 100ms,省电又快速。

配置分辨率的方法:向暂存器的第 4 字节写入配置值。比如 12 位写 0x7F,9 位写 0x1F。

// 设置 DS18B20 为 9 位分辨率
void setResolution_9bit() {
    reset_pulse();          // 复位脉冲
    send_byte(0xCC);        // 跳过 ROM
    send_byte(0x4E);        // 写暂存器指令
    send_byte(0x00);        // TH 用户字节1
    send_byte(0x00);        // TL 用户字节2
    send_byte(0x1F);        // 配置寄存器:9位
}

2.5 CRC 校验

单总线通信容易受干扰,尤其是温室里电机启停时。DS18B20 内置了 8 位 CRC 校验,确保数据完整性。

CRC 校验覆盖 8 字节数据(温度 + TH + TL + 配置 + 保留字节),最后一个字节就是 CRC 值。主机收到数据后,用多项式 x⁸ + x⁵ + x⁴ + 1 计算校验。

小技巧:我一般直接用 Dallas 官方提供的 CRC 查表法,速度比计算快得多。代码就几行,网上随便搜都有。

// CRC 校验示例(查表法)
uint8_t crc8(uint8_t *data, uint8_t len) {
    uint8_t crc = 0;
    uint8_t lookup[] = {
        0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
        // ... 省略中间 248 个值
    };
    for (uint8_t i = 0; i < len; i++) {
        crc = lookup[crc ^ data[i]];
    }
    return crc;
}

如果计算出的 CRC 和收到的 CRC 不匹配,直接丢弃这帧数据。别犹豫,温室里数据错一位,温度可能差好几度。

2.6 典型电路设计

一个标准的 DS18B20 电路其实很简单:

  • 数据线:接 MCU 的 GPIO,加上拉电阻 4.7kΩ 到 VCC
  • VDD:接 3.3V 或 5V(正常供电模式)
  • GND:共地

但实际项目中,我踩过不少坑:

注意:如果数据线超过 10 米,上拉电阻要减小到 2.2kΩ 甚至 1kΩ。我有个项目线长 30 米,用 4.7kΩ 死活通信不上,换成 1kΩ 就好了。

另外,建议在数据线上加一个 100nF 的电容到地,滤除高频干扰。温室里的变频器、水泵都是干扰源。

// 典型电路连接(正常供电模式)
// MCU GPIO  ----[4.7kΩ]---- VCC (3.3V)
//              |
//              +---- DS18B20 DQ
// DS18B20 VDD ---- VCC (3.3V)
// DS18B20 GND ---- GND

如果你非要用寄生供电,电路改成这样:

// 寄生供电模式
// MCU GPIO  ----[4.7kΩ]---- VCC (3.3V)
//              |
//              +---- DS18B20 DQ
// DS18B20 VDD ---- GND
// DS18B20 GND ---- GND

嗯,寄生供电模式下,转换期间必须保证总线为高电平。我一般用 MOS 管强拉高,或者干脆在转换前把 GPIO 设成输出高。

小结

DS18B20 是个好芯片,便宜、稳定、易用。但单总线的时序要求很严格,稍微偏差一点就通信失败。我的建议是:

  1. 先用逻辑分析仪抓波形,确认时序正确
  2. 量产时用正常供电模式,别省那根线
  3. CRC 校验一定要做,温室环境干扰多

下一章咱们聊聊湿度传感器 SHT30 的 I2C 接口,那个又是另一番天地了。