51单片机(五) --- DS18B20 单总线温度传感器
·
一、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 单总线协议,核心特性:
- 线与特性:任何设备拉低总线,总线电平就为低,这是复位、应答的基础。
- 主机控制时序:所有通信都由主机发起,传感器被动响应。
- 严格时序要求:复位、读写操作都必须满足手册规定的时间窗口,否则通信失败。
- 半双工通信:同一时间只能单向传输数据。
二、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 指令,单总线只有一个设备时使用,无需匹配 ID0x44:启动温度转换指令,传感器开始采集温度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即可得到实际温度(正 / 负温度自动处理)
五、问题总结(直接背)
-
DS18B20 是什么通信方式?单总线(1-Wire)异步半双工通信,仅需 1 根数据线。
-
通信的第一步必须做什么?复位时序,发送复位脉冲并等待存在脉冲,确认传感器在线。
-
单点测温时为什么要发送 0xCC?跳过 ROM 指令,单总线只有一个设备时无需匹配 ID,简化通信流程。
-
启动温度转换和读取数据分别用什么指令?
- 启动转换:
0x44 - 读取数据:
0xBE
- 启动转换:
-
写 0 和写 1 时序的区别?
- 写 0:拉低总线≥60μs,DS18B20 采样为 0
- 写 1:拉低总线 > 1μs 后立即释放,DS18B20 采样为 1
-
读时序的关键是什么?主机拉低总线后必须在 15μs 内采样电平,否则数据会丢失。
-
温度数据怎么计算?拼接高低字节后乘以 0.0625(12 位分辨率)。
- 时序延时不准:复位脉冲不足 480μs 或读写时序超时,会导致通信失败。
- 忘记延时等待转换:发送
0x44后必须延时,否则读取的是旧数据。- 读操作采样过晚:主机拉低后超过 15μs 采样,无法正确读取传感器输出。
- 高低字节拼接错误:温度数据必须高字节左移 8 位再和低字节按位或,不能直接相加。
更多推荐


所有评论(0)