一、DS18B20 概念

1.1 核心参数

DS18B20 是 单总线(1-Wire)数字温度传感器,只需要 1 根 GPIO + GND 即可完成通信。

参数项 规格 关键考点
测量范围 -55℃ ~ +125℃ 工业级宽温,适合环境监测
精度 ±0.5℃(-10℃~+85℃) 全量程精度会略低,±0.5℃是典型值
分辨率 9~12 位可配置(默认 12 位) 9 位 = 0.5℃,10 位 = 0.25℃,11 位 = 0.125℃,12 位 = 0.0625℃
接口 单总线(1-Wire) 仅需 1 根数据线,外加电源和地,线与特性
工作电压 3.0V~5.5V 兼容 3.3V/5V 单片机系统
通信方式 异步半双工 主机严格控制时序,传感器被动响应
唯一 ID 64 位光刻 ROM 编码 支持单总线挂载多个 DS18B20,通过 ID 区分设备
转换时间 最大 750ms(12 位分辨率) 分辨率越低,转换速度越快

1.2 单总线通信基础

DS18B20 基于 1-Wire 单总线协议,核心特性:

  1. 线与特性:任何设备拉低总线,总线电平就为低,这是复位、应答的基础。
  2. 主机控制时序:所有通信都由主机发起,传感器被动响应。
  3. 严格时序要求:复位、读写操作都必须满足手册规定的时间窗口,否则通信失败。
  4. 半双工通信:同一时间只能单向传输数据。

二、DS18B20 配置与通信流程

复位 → 发送命令(启动转换) → 延时 → 复位 → 读取数据

1. 第一步:复位与存在脉冲(通信初始化)

这是所有通信的前提,目的是检测传感器是否在线、唤醒设备。

时序规则
  • 主机拉低总线 480~960μs(你的代码用了 700μs,满足要求)
  • 主机释放总线(拉高),等待 15~60μs
  • DS18B20 主动拉低总线 60~240μs,作为「存在脉冲」,告诉主机 “我已准备好”
  • 传感器释放总线,复位完成
int ds18b20_reset(void)
{
    int time = 0;
    // 1. 主机拉低700μs,发送复位脉冲
    DQ_DOWN;
    Delay10us(70);

    // 2. 释放总线,等待传感器响应
    DQ_HIGH;
    Delay10us(6);

    // 3. 等待存在脉冲(传感器拉低总线),超时返回-1
    while(DQ_CHECK && time < 30) { Delay10us(1); time++; }
    if(time >= 30) return -1;

    // 4. 等待传感器释放总线,超时返回-2
    while(!DQ_CHECK && time < 30) { Delay10us(1); time++; }
    if(time >= 30) return -2;

    return 1; // 复位成功
}

关键:两个超时循环分别检测「存在脉冲开始 / 结束」,防止传感器异常导致程序卡死。

2. 第二步:发送命令(写时序详解)

复位成功后,主机发送命令控制传感器,核心是写 0 / 写 1 时序

写 0 时序(对应位为 0)
  • 主机拉低总线 至少 60μs,不超过 120μs
  • DS18B20 在拉低后的 60μs 内采样,识别为 bit0
DQ_DOWN;
Delay10us(6); // 拉低60μs
DQ_HIGH;
写 1 时序(对应位为 1)
  • 主机拉低总线 >1μs 后立即释放
  • DS18B20 在 45μs 内采样,识别为 bit1
DQ_DOWN;
_nop_(); _nop_(); // 拉低>1μs
DQ_HIGH;
Delay10us(5);
核心指令(单点测温)
  • 0xCC:跳过 ROM 指令,单总线只有一个设备时使用,无需匹配 ID
  • 0x44:启动温度转换指令,传感器开始采集温度
  • 0xBE:读取暂存器指令,读取转换好的温度数据

写字节函数逻辑

void write_ds18b20(unsigned char dat)
{
    int i;
    for(i=0; i<8; i++)
    {
        if(dat & 1) // 写1
        {
            DQ_DOWN; _nop_(); _nop_(); DQ_HIGH;
            Delay10us(5);
        }
        else // 写0
        {
            DQ_DOWN; Delay10us(6); DQ_HIGH;
        }
        dat >>= 1; // LSB低位先行
    }
}

关键:单总线通信必须低位先行,代码中通过dat >>= 1从 bit0 开始发送。

3. 第三步:读取温度数据(读时序详解)

温度转换完成后,主机通过读时序获取数据,核心是读一位时序

读时序规则
  • 主机拉低总线 >1μs 后立即释放,作为读操作的开始
  • DS18B20 输出数据到总线,主机必须在15μs 内采样电平
  • 低电平 = 0,高电平 = 1

读字节函数逻辑

unsigned char read_ds18b20(void)
{
    int i;
    unsigned char dat = 0;
    for(i=0; i<8; i++)
    {
        // 1. 主机拉低>1μs,启动读操作
        DQ_DOWN; _nop_(); _nop_();
        // 2. 释放总线,等待传感器输出数据
        DQ_HIGH; _nop_(); _nop_();

        // 3. 采样电平,拼接数据
        if(DQ_CHECK) dat |= (1 << i);

        Delay10us(6); // 等待本次读周期结束
    }
    return dat;
}

关键:主机拉低后必须快速采样,否则传感器会释放总线导致数据丢失。

三、完整温度读取函数

float get_temp(void)
{
    unsigned char temp_low, temp_high;
    short temp;

    // 1. 复位传感器,准备发送命令
    ds18b20_reset();
    // 2. 跳过ROM,启动温度转换
    write_ds18b20(0xCC);
    write_ds18b20(0x44);
    // 3. 等待转换完成(12位分辨率最大750ms,这里延时1s确保完成)
    Delay1ms(1000);

    // 4. 再次复位,准备读取数据
    ds18b20_reset();
    write_ds18b20(0xCC);
    write_ds18b20(0xBE);

    // 5. 读取温度低字节和高字节
    temp_low = read_ds18b20();
    temp_high = read_ds18b20();

    // 6. 拼接数据,计算实际温度
    temp = (temp_high << 8) | temp_low;
    return temp * 0.0625; // 12位分辨率,每1LSB=0.0625℃
}

温度数据格式解析

DS18B20 返回的 16 位数据格式:

  • 低字节(temp_low):温度的低 8 位,包含小数部分
  • 高字节(temp_high):温度的高 8 位,包含符号位和整数部分
  • 12 位分辨率下,temp * 0.0625 即可得到实际温度(正 / 负温度自动处理)

五、问题总结(直接背)

  1. DS18B20 是什么通信方式?单总线(1-Wire)异步半双工通信,仅需 1 根数据线。

  2. 通信的第一步必须做什么?复位时序,发送复位脉冲并等待存在脉冲,确认传感器在线。

  3. 单点测温时为什么要发送 0xCC?跳过 ROM 指令,单总线只有一个设备时无需匹配 ID,简化通信流程。

  4. 启动温度转换和读取数据分别用什么指令?

    • 启动转换:0x44
    • 读取数据:0xBE
  5. 写 0 和写 1 时序的区别?

    • 写 0:拉低总线≥60μs,DS18B20 采样为 0
    • 写 1:拉低总线 > 1μs 后立即释放,DS18B20 采样为 1
  6. 读时序的关键是什么?主机拉低总线后必须在 15μs 内采样电平,否则数据会丢失。

  7. 温度数据怎么计算?拼接高低字节后乘以 0.0625(12 位分辨率)。

  • 时序延时不准:复位脉冲不足 480μs 或读写时序超时,会导致通信失败。
  • 忘记延时等待转换:发送0x44后必须延时,否则读取的是旧数据。
  • 读操作采样过晚:主机拉低后超过 15μs 采样,无法正确读取传感器输出。
  • 高低字节拼接错误:温度数据必须高字节左移 8 位再和低字节按位或,不能直接相加。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐