DS18B20 是一款常用的数字温度传感器,由 DALLAS 公司(后被 Maxim 收购)开发,广泛应用于温度测量、控制系统、家电、工业监测等领域。以下是其核心特点与技术信息的详细介绍:
一、核心特性
-
单总线通信(1-Wire® 协议)
- 仅需一根数据线(DQ)和地线(GND)即可与微控制器通信,节省 IO 端口资源,适合多传感器组网。
- 支持在同一条总线上挂载多个 DS18B20 传感器(通过 ROM 地址唯一标识)。
-
宽温度测量范围
- 标准范围:-55°C 至 +125°C(-67°F 至 +257°F)。
- 精度:在 -10°C 至 +85°C 范围内,精度为 ±0.5°C;其他范围精度略有下降。
-
可编程分辨率
- 温度转换分辨率可通过配置寄存器设置为 9 位、10 位、11 位或 12 位(默认 12 位),对应不同的转换时间和精度:
- 12 位精度:0.0625°C/LSB,转换时间约 750ms;
- 9 位精度:0.5°C/LSB,转换时间约 93.75ms。
- 温度转换分辨率可通过配置寄存器设置为 9 位、10 位、11 位或 12 位(默认 12 位),对应不同的转换时间和精度:
-
内置温度报警功能
- 支持设置 高温阈值(TH) 和 低温阈值(TL),可通过命令触发报警搜索,快速定位超温传感器。
-
供电方式灵活
- 外部供电:通过 VCC 引脚接入 3.0V~5.5V 电源。
- 寄生电源(单总线供电):无需 VCC 引脚,直接从数据线获取能量(需确保总线驱动能力足够,适合便携式场景)。
二、硬件结构与引脚功能
1. 封装形式
常见封装包括:
- TO-92 直插式(适合面包板或 PCB 焊接);
- SOIC 贴片式(适合小型化设计);
- 防水探头式(用于恶劣环境或液体温度测量)。
2. 引脚定义(以 TO-92 为例)
引脚名称 | 功能描述 |
---|---|
GND | 接地端 |
DQ | 单总线数据引脚(开漏输出,需外接 4.7kΩ 上拉电阻) |
VCC | 电源正极(寄生供电时可悬空) |
三、工作原理与通信协议
1. 温度转换流程
- 微控制器通过单总线发送 启动温度转换命令(0x44);
- DS18B20 内部 ADC 开始转换温度,完成后将结果存储在 温度寄存器 中;
- 微控制器发送 读取暂存器命令(0xBE) 获取温度数据(16 位补码格式)。
2. 数据格式(12 位精度示例)
- 温度值以 16 位二进制补码 表示,高字节在前,低字节在后。
- 正数示例:+25°C 对应二进制
0000 0001 1001 0100
(十六进制0x0194
),换算为十进制:25.0°C
。 - 负数示例:-5°C 对应二进制
1111 1110 1111 0100
(十六进制0xFEFC
),换算为十进制:-5.0°C
。
3. 单总线通信时序
- 通信基于严格的时序协议,包括:
- 初始化脉冲(主机拉低总线 ≥480μs,释放后等待从机应答脉冲);
- 写时隙(主机向从机写数据,分为 “写 0” 和 “写 1” 时隙);
- 读时隙(主机从从机读数据,需在拉低总线后 15μs 内采样)。
四、典型应用场景
- 工业自动化:电机、管道温度监测;
- 智能家居:空调、地暖温度控制;
- 环境监测:温室、冷库温度记录;
- 嵌入式系统:Arduino、STM32 等开发板的温度采集模块;
- 汽车电子:发动机舱、电池温度检测。
五、注意事项
- 上拉电阻:单总线必须外接 4.7kΩ 上拉电阻,确保信号稳定。
- 寄生电源限制:使用寄生供电时,需在温度转换期间保持总线高电平(可通过强上拉或外部电容储能)。
- 多传感器组网:需先通过 搜索 ROM 命令(0xF0) 或 匹配 ROM 命令(0x55) 寻址特定传感器。
- 抗干扰:长距离通信时建议使用屏蔽线,并降低总线速度(如延长时隙宽度)。
六、驱动代码
ds18b20.h
#ifndef DS18B20_H
#define DS18B20_H
#include "stm32f1xx_hal.h"
/* DS18B20时钟端口、引脚定义 */
#define DS18B20_Pin GPIO_PIN_11
#define DS18B20_GPIO_Port GPIOA
#define DS18B20_GPIO_Port_RCC __HAL_RCC_GPIOA_CLK_ENABLE()
#define DS18B20_DQ(x) HAL_GPIO_WritePin(DS18B20_GPIO_Port, DS18B20_Pin, (GPIO_PinState)(x))
#define DS18B20_DQ_IN ((HAL_GPIO_ReadPin(DS18B20_GPIO_Port, DS18B20_Pin) == GPIO_PIN_SET) ? 1 : 0)
/**
* @brief 初始化DS18B20传感器及通信引脚
* @param 无
* @retval 0:传感器存在且初始化成功,1:传感器不存在或初始化失败
*/
uint8_t DS18B20_Init(void); //初始化DS18B20
/**
* @brief 获取DS18B20温度值
* @param 无
* @retval 温度数据(单位:℃,精度0.0625℃)
*/
float DS18B20_GetTemperture(void); //获取温度
/**
* @brief 启动DS18B20温度转换过程
* @param 无
* @retval 无
*/
void DS18B20_Start(void); //开始温度转换
/**
* @brief 向DS18B20写入一个字节数据
* @param dat:待写入的8位无符号字节数据
* @retval 无
*/
void DS18B20_Write_Byte(uint8_t dat);//写入一个字节
/**
* @brief 从DS18B20读取一个字节数据
* @param 无
* @retval 读取到的8位无符号字节数据
*/
uint8_t DS18B20_Read_Byte(void); //读出一个字节
/**
* @brief 从DS18B20读取一个位数据
* @param 无
* @retval 读取的位值(0或1)
*/
uint8_t DS18B20_Read_Bit(void); //读出一个位
/**
* @brief 检测DS18B20传感器是否存在
* @param 无
* @retval 1:未检测到传感器,0:传感器存在
*/
uint8_t DS18B20_Check(void); //检测是否存在DS18B20
/**
* @brief 复位DS18B20传感器
* @param 无
* @retval 无
*/
void DS18B20_Reset(void); //复位DS18B20
/**
* @brief 设置DS18B20温度分辨率
* @param resolution:分辨率(可选值:9、10、11、12,对应精度0.5℃~0.0625℃)
* @retval 0:设置失败(传感器无响应或分辨率无效),1:设置成功
*/
uint8_t DS18B20_SetResolution(uint8_t resolution);
#endif
dsl8b20.c
#include "ds18b20.h"
#include "Delay.h"
/**
* @brief 复位DS18B20传感器
* @param 无
* @retval 无
*/
void DS18B20_Reset(void)
{
//DS18B20_IO_OUT(); //SET PG11 OUTPUT
DS18B20_DQ(0); // 拉低DQ
delay_us(750); // 拉低750us
DS18B20_DQ(1);; // DQ=1
delay_us(15); // 15US
}
/**
* @brief 检测DS18B20是否存在
* @param 无
* @retval 1:未检测到DS18B20的存在,0:存在
*/
uint8_t DS18B20_Check(void)
{
uint8_t retry = 0;
//DS18B20_IO_IN();//SET PG11 INPUT
while (DS18B20_DQ_IN && retry < 200)
{
retry++;
delay_us(1);
};
if (retry >= 200) return 1;
else retry = 0;
while (!DS18B20_DQ_IN && retry < 240)
{
retry++;
delay_us(1);
};
if (retry >= 240) return 1;
return 0;
}
/**
* @brief 从DS18B20读取一个位
* @param 无
* @retval 1/0(读取的位值)
*/
uint8_t DS18B20_Read_Bit(void) // read one bit
{
uint8_t data;
DS18B20_DQ(0);
delay_us(2);
DS18B20_DQ(1);
delay_us(12);
if (DS18B20_DQ_IN) data = 1;
else data = 0;
delay_us(50);
return data;
}
/**
* @brief 从DS18B20读取一个字节
* @param 无
* @retval 8位无符号字节数据
*/
uint8_t DS18B20_Read_Byte(void) // read one byte
{
uint8_t i, j, dat;
dat = 0;
for (i = 1; i <= 8; i++)
{
j = DS18B20_Read_Bit();
dat = (j << 7) | (dat >> 1);
}
return dat;
}
/**
* @brief 写一个字节到DS18B20
* @param dat:要写入的8位无符号字节
* @retval 无
*/
void DS18B20_Write_Byte(uint8_t dat)
{
uint8_t j;
uint8_t testb;
for (j = 1; j <= 8; j++)
{
testb = dat & 0x01;
dat = dat >> 1;
if (testb)
{
DS18B20_DQ(0);// Write 1
delay_us(2);
DS18B20_DQ(1);
delay_us(60);
}
else
{
DS18B20_DQ(0);// Write 0
delay_us(60);
DS18B20_DQ(1);
delay_us(2);
}
}
}
/**
* @brief 启动DS18B20温度转换
* @param 无
* @retval 无
*/
void DS18B20_Start(void)
{
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
/**
* @brief 初始化DS18B20的IO口及检测传感器存在
* @param 无
* @retval 1:传感器不存在,0:传感器存在
*/
uint8_t DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
DS18B20_GPIO_Port_RCC;
DS18B20_DQ(1);
GPIO_InitStruct.Pin = DS18B20_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
DS18B20_Reset();
return DS18B20_Check();
}
/**
* @brief 设置DS18B20温度分辨率
* @param resolution:分辨率(可选值:9、10、11、12)
* @retval 0:设置失败(传感器无响应),1:设置成功
*/
uint8_t DS18B20_SetResolution(uint8_t resolution)
{
uint8_t config_byte = 0x7F; // 默认12位分辨率配置(R1=1, R0=1)
// 根据分辨率设置配置寄存器的R1/R0位
switch(resolution)
{
case 9: config_byte = 0x1F; break; // 9位:R1=0, R0=0(0001 1111)
case 10: config_byte = 0x3F; break; // 10位:R1=0, R0=1(0011 1111)
case 11: config_byte = 0x5F; break; // 11位:R1=1, R0=0(0101 1111)
case 12: config_byte = 0x7F; break; // 12位:R1=1, R0=1(0111 1111,默认值)
default: return 0; // 无效分辨率
}
// 1. 复位传感器并检查响应
DS18B20_Reset();
if(DS18B20_Check()) // 返回1表示传感器不存在
return 0;
// 2. 发送写入暂存器命令(0x4E):TH/TL/配置寄存器
DS18B20_Write_Byte(0xCC); // 跳过ROM(单传感器场景)
DS18B20_Write_Byte(0x4E); // 写入暂存器命令
// 3. 写入TH和TL寄存器(温度报警阈值,此处设为默认0xFF)
DS18B20_Write_Byte(0xFF); // TH寄存器(高温报警,通常不使用)
DS18B20_Write_Byte(0xFF); // TL寄存器(低温报警,通常不使用)
DS18B20_Write_Byte(config_byte); // 写入配置寄存器
// 4. 复位传感器并再次检查响应(确保通信正常)
DS18B20_Reset();
if(DS18B20_Check())
return 0;
// 5. 发送复制暂存器命令(0x48):将配置保存到EEPROM
DS18B20_Write_Byte(0xCC); // 跳过ROM
DS18B20_Write_Byte(0x48); // 复制暂存器到EEPROM(掉电保存配置)
return 1; // 分辨率设置成功
}
/**
* @brief 从DS18B20获取温度值
* @param 无
* @retval 温度数据(单位:℃,精度0.0625℃)
*/
float DS18B20_GetTemperture(void)
{
uint16_t temp;
uint8_t a, b;
float value;
DS18B20_Start(); // ds1820 start convert
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
a = DS18B20_Read_Byte(); // LSB
b = DS18B20_Read_Byte(); // MSB
temp = b;
temp = (temp << 8) + a;
if ((temp & 0xf800) == 0xf800)
{
temp = (~temp) + 1;
value = temp * (-0.0625);
}
else
{
value = temp * 0.0625;
}
return value;
}
mian.c
while(DS18B20_Init())
{
OLED_ShowString(2,1,"DS18B20 Error..." ,strlen("DS18B20 Error..."));
delay_ms(500);
OLED_Clear();
}
DS18B20_SetResolution(12); //设置ds18b20分辨率
float temp = 0;
char str_data[16];
while (1)
{
temp = DS18B20_GetTemperture();
uint8_t len = (uint8_t)sprintf(str_data , "temp:%.3f" , temp);
OLED_ShowString(1,1,str_data , len);
}
我这里使用的是F1系列的单片机,效果图如下。(单位为摄氏度)
OLED的驱动代码本文章的代码资源绑定文件里