DS18B20单线数字温度采集
一、DS18B20核心特性与硬件基础
1. 关键参数(必记!)
| 参数 | 规格细节 |
|---|---|
| 测量量程 | -55℃ ~ +125℃(工业级场景全覆盖) |
| 测量精度 | -10℃~+85℃范围内±0.5℃,全量程误差≤±2℃ |
| 分辨率 | 9~12位可调(默认12位):9位=0.5℃、10位=0.25℃、11位=0.125℃、12位=0.0625℃ |
| 工作电压 | 3V~5.5V(兼容51单片机3.3V/5V供电,无需额外稳压) |
| 通信接口 | GPIO单线总线(仅需1根I/O引脚+GND,硬件成本极低) |
| 核心优势 | 无需外部元件、抗干扰强、支持多传感器组网、掉电保留配置 |
2. 引脚定义与接线方式
DS18B20采用TO-92封装,共3个引脚,51单片机接线如下:
| DS18B20引脚 | 功能 | 51单片机连接方式 |
|---|---|---|
| VDD | 电源引脚 | 接3.3V/5V(外部电源模式),或悬空(寄生电源模式) |
| DQ | 数据I/O | 接任意GPIO引脚(本文代码用P3.7)+ 4.7KΩ上拉电阻 |
| GND | 地 | 接单片机GND(必须共地,否则信号干扰) |
关键提醒:单线总线必须串联4.7KΩ上拉电阻,确保总线空闲时为高电平,通信稳定。
二、DS18B20核心时序原理(通信关键!)
DS18B20的通信依赖严格的时序协议,所有操作(复位、写数据、读数据)都需遵循单线总线的时序规则,这是采集成功的核心。
1. 复位时序(初始化)
所有通信必须从复位开始,流程如下:
- 主机(51单片机)拉低总线 ≥480μs(复位脉冲);
- 主机释放总线,拉高后切换为输入模式;
- DS18B20检测到上升沿后,延迟15~60μs,拉低总线 60~240μs(存在脉冲),告知主机"已就绪";
- DS18B20释放总线,恢复高电平,进入空闲状态。
代码对应:
ds18b20_reset()函数中,通过Delay10us(70)实现700μs复位拉低,Delay10us(6)等待存在脉冲。
2. 写时序(主机→DS18B20)
主机通过不同的低电平时长传递"0"或"1",每次仅发送1位,8位为1字节(LSB优先):
- 写0 :拉低总线 ≥60μs → 释放总线(拉高);DS18B20在60μs内采样,低电平视为"0";
- 写1 :拉低总线 1~15μs → 释放总线(拉高);DS18B20采样到高电平视为"1";
- 两次写操作间隔 ≥1μs(恢复时间)。
代码对应:
write_ds18b20()函数中,dat&1判断当前位,短延时对应写1,长延时对应写0。
3. 读时序(DS18B20→主机)
主机先拉低总线触发读操作,再释放总线由DS18B20控制总线电平,流程如下:
- 主机拉低总线 ≥1μs → 立即释放总线(拉高);
- 主机在拉低后15μs内采样总线电平(高=1,低=0);
- 单次读操作时长 ≥60μs,两次读间隔 ≥1μs。
代码对应:
read_ds18b20()函数中,拉低后快速释放,通过DQ_CHECK检测电平,存入dat对应位。
三、核心命令解析(DS18B20操作灵魂)
DS18B20通过主机发送的8位命令执行对应操作,本文代码用到3个核心命令:
| 命令字节 | 命令名称 | 功能说明 |
|---|---|---|
| 0xCC | Skip ROM(跳过ROM) | 无需读取DS18B20的唯一64位ROM编码,直接进入功能操作(单传感器场景首选,节省时间) |
| 0x44 | Convert T(温度转换) | 启动一次温度测量,转换时间与分辨率相关(12位约750ms),转换期间总线需保持高电平 |
| 0xBE | Read Scratchpad(读暂存器) | 读取DS18B20内部暂存器数据(共9字节,前2字节为温度数据) |
扩展:多传感器组网时,需用
0x55(Match ROM)命令+64位ROM编码,定位目标传感器。
四、51单片机代码完整解析
代码基于P3.7引脚实现,分"复位→测温→读数→数据解析"四大步骤,可直接编译下载使用。
1. 头文件与宏定义(ds18b20.h)
c
#ifndef __DS18B20_H__
#define __DS18B20_H__
#include <reg51.h>
// 函数声明
int ds18b20_reset(void); // 复位DS18B20
void write_ds18b20(unsigned char dat); // 写1字节到DS18B20
unsigned char read_ds18b20(void); // 从DS18B20读1字节
float get_temp(void); // 获取温度值(返回浮点型)
#endif
2. 核心功能实现(ds18b20.c)
c
#include <reg51.h>
#include <intrins.h>
#include "ds18b20.h"
#include "delay.h"
// 宏定义:P3.7作为DQ引脚
#define DQ_DOWN (P3 &= ~(1 << 7)) // 拉低DQ
#define DQ_HIGH (P3 |= (1 << 7)) // 拉高DQ
#define DQ_CHECK ((P3 & (1 << 7)) != 0) // 检测DQ电平
/**
* @brief DS18B20复位初始化
* @retval 1-复位成功,0-复位失败
*/
int ds18b20_reset(void)
{
int t = 0;
// 1. 发送复位脉冲(拉低≥480μs)
DQ_DOWN;
Delay10us(70); // 70×10μs=700μs,满足≥480μs要求
DQ_HIGH; // 释放总线
Delay10us(6); // 等待60μs,准备接收存在脉冲
// 2. 检测存在脉冲(DS18B20拉低总线)
while (DQ_CHECK && t < 30) // 超时300μs未检测到低电平→失败
{
Delay10us(1);
t++;
}
if (t >= 30) return 0; // 复位失败
// 3. 等待存在脉冲结束(DS18B20拉高总线)
t = 0;
while (!DQ_CHECK && t < 30) // 超时300μs未拉高→失败
{
Delay10us(1);
t++;
}
if (t >= 30) return 0; // 复位失败
return 1; // 复位成功
}
/**
* @brief 向DS18B20写1字节数据(LSB优先)
* @param dat:要发送的字节
*/
void write_ds18b20(unsigned char dat)
{
int i = 0;
for (i = 0; i < 8; i++) // 循环8次,每次写1位
{
if (dat & 1) // 写1:拉低1~15μs
{
DQ_DOWN;
_nop_(); // 短延时(约1μs)
_nop_();
DQ_HIGH; // 释放总线
Delay10us(5); // 等待45μs,确保DS18B20采样
}
else // 写0:拉低≥60μs
{
DQ_DOWN;
Delay10us(6); // 60μs
DQ_HIGH; // 释放总线
}
dat >>= 1; // 右移1位,准备写下一位(LSB优先)
}
}
/**
* @brief 从DS18B20读1字节数据(LSB优先)
* @retval 读取到的字节
*/
unsigned char read_ds18b20(void)
{
unsigned char dat = 0;
int i = 0;
for (i = 0; i < 8; i++) // 循环8次,每次读1位
{
DQ_DOWN; // 拉低≥1μs,触发读操作
_nop_();
_nop_();
DQ_HIGH; // 释放总线,由DS18B20控制电平
_nop_();
_nop_();
_nop_(); // 延时约3μs,准备采样
if (DQ_CHECK) // 采样电平:高=1,低=0
{
dat |= (1 << i); // 存入对应位(LSB优先)
}
Delay10us(6); // 单次读操作≥60μs
}
return dat;
}
/**
* @brief 获取温度值
* @retval 浮点型温度(精度0.0625℃)
*/
float get_temp(void)
{
unsigned char tl = 0; // 温度低字节(LSB)
unsigned char th = 0; // 温度高字节(MSB,含符号位)
short t = 0; // 组合后的16位温度数据
// 1. 复位→跳过ROM→启动温度转换
if (ds18b20_reset() == 0) return -99.9; // 复位失败返回错误值
write_ds18b20(0xCC); // 跳过ROM(单传感器)
write_ds18b20(0x44); // 启动温度转换
Delay1ms(1000); // 等待转换完成(12位分辨率需750ms以上)
// 2. 复位→跳过ROM→读暂存器
ds18b20_reset();
write_ds18b20(0xCC); // 跳过ROM
write_ds18b20(0xBE); // 读暂存器
// 3. 读取温度数据(前2字节为温度值,LSB先读)
tl = read_ds18b20(); // 低字节
th = read_ds18b20(); // 高字节
// 4. 组合温度数据(16位带符号补码)
t = th << 8; // 高字节左移8位
t |= tl; // 拼接低字节
// 5. 温度换算:12位分辨率→1LSB=0.0625℃
return t * 0.0625;
}
3. 延时函数支持(delay.c/h)
DS18B20时序对延时精度要求高,需实现10μs、1ms级延时(11.0592MHz晶振):
c
// delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay10us(unsigned int n);
void Delay1ms(unsigned int n);
#endif
// delay.c
#include <reg51.h>
void Delay10us(unsigned int n)
{
unsigned int i, j;
for (i = n; i > 0; i--)
for (j = 2; j > 0; j--); // 11.0592MHz下≈10μs
}
void Delay1ms(unsigned int n)
{
unsigned int i, j;
for (i = n; i > 0; i--)
for (j = 110; j > 0; j--); // 11.0592MHz下≈1ms
}
4. 主函数调用示例(main.c)
c
#include <reg51.h>
#include "ds18b20.h"
#include "uart.h" // 假设已实现串口发送函数
void main(void)
{
float temp;
uart_init(); // 初始化串口(用于打印温度)
while (1)
{
temp = get_temp(); // 获取温度
if (temp != -99.9) // 采集成功
{
// 串口打印温度(需实现浮点型转字符串函数,此处省略)
uart_sendstr("当前温度:");
// 示例:打印整数部分+小数部分
}
Delay1ms(2000); // 每2秒采集一次
}
}
五、实战关键注意事项
- 上拉电阻不可少:4.7KΩ上拉电阻是单线总线稳定通信的核心,缺少会导致复位失败、数据传输错误;
- 延时精度要达标:时序中的时间参数(如复位480μs、写0 60μs)需严格匹配,延时误差过大会导致采集失败;
- 温度转换需等待:启动转换(0x44命令)后,必须等待足够时间(12位分辨率≥750ms),否则读取到的是旧数据;
- 寄生电源模式注意:若DS18B20采用寄生电源(VDD悬空),转换期间总线需保持高电平,不能进行其他操作;
- 多传感器组网 :需使用
0x55(Match ROM)命令+传感器唯一64位ROM编码,避免数据冲突。
六、温度数据解析原理
DS18B20的温度数据以16位带符号补码形式存储,格式如下:
| 位15(MSB) | 位14-11 | 位10-4 | 位3-0(LSB) |
|---|---|---|---|
| 符号位(0=正,1=负) | 整数部分 | 小数部分 | 小数部分(12位分辨率) |
- 正数:直接按"整数部分×1 + 小数部分×0.0625"换算;
- 负数:按补码规则转换(取反+1)后再换算,符号为负;
- 示例:温度25.5℃→二进制
00000000 00011001.1000→十六进制0x00198→换算为25 + 8×0.0625=25.5℃。
总结
DS18B20的核心优势在于"单线通信+极简硬件",学习重点集中在时序协议 和命令解析:复位是通信前提,写/读时序是数据传输基础,温度转换和读暂存器命令是核心操作。掌握本文代码和原理后,可轻松扩展多传感器组网、温度报警(利用TH/TL寄存器)、串口上传温度等功能,适用于环境监测、设备温控等嵌入式场景。