DS18B20,HAL库STM32单片机驱动(超详细),改编自普中开发板赠送程序

DS18B20 是一款常用的数字温度传感器,由 DALLAS 公司(后被 Maxim 收购)开发,广泛应用于温度测量、控制系统、家电、工业监测等领域。以下是其核心特点与技术信息的详细介绍:

一、核心特性

  1. 单总线通信(1-Wire® 协议)

    • 仅需一根数据线(DQ)和地线(GND)即可与微控制器通信,节省 IO 端口资源,适合多传感器组网。
    • 支持在同一条总线上挂载多个 DS18B20 传感器(通过 ROM 地址唯一标识)。
  2. 宽温度测量范围

    • 标准范围:-55°C 至 +125°C(-67°F 至 +257°F)。
    • 精度:在 -10°C 至 +85°C 范围内,精度为 ±0.5°C;其他范围精度略有下降。
  3. 可编程分辨率

    • 温度转换分辨率可通过配置寄存器设置为 9 位、10 位、11 位或 12 位(默认 12 位),对应不同的转换时间和精度:
      • 12 位精度:0.0625°C/LSB,转换时间约 750ms;
      • 9 位精度:0.5°C/LSB,转换时间约 93.75ms。
  4. 内置温度报警功能

    • 支持设置 高温阈值(TH) 和 低温阈值(TL),可通过命令触发报警搜索,快速定位超温传感器。
  5. 供电方式灵活

    • 外部供电:通过 VCC 引脚接入 3.0V~5.5V 电源。
    • 寄生电源(单总线供电):无需 VCC 引脚,直接从数据线获取能量(需确保总线驱动能力足够,适合便携式场景)。

二、硬件结构与引脚功能

1. 封装形式

常见封装包括:

  • TO-92 直插式(适合面包板或 PCB 焊接);
  • SOIC 贴片式(适合小型化设计);
  • 防水探头式(用于恶劣环境或液体温度测量)。
2. 引脚定义(以 TO-92 为例)
引脚名称功能描述
GND接地端
DQ单总线数据引脚(开漏输出,需外接 4.7kΩ 上拉电阻)
VCC电源正极(寄生供电时可悬空)

三、工作原理与通信协议

1. 温度转换流程
  1. 微控制器通过单总线发送 启动温度转换命令(0x44)
  2. DS18B20 内部 ADC 开始转换温度,完成后将结果存储在 温度寄存器 中;
  3. 微控制器发送 读取暂存器命令(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 内采样)。

四、典型应用场景

  1. 工业自动化:电机、管道温度监测;
  2. 智能家居:空调、地暖温度控制;
  3. 环境监测:温室、冷库温度记录;
  4. 嵌入式系统:Arduino、STM32 等开发板的温度采集模块;
  5. 汽车电子:发动机舱、电池温度检测。

五、注意事项

  1. 上拉电阻:单总线必须外接 4.7kΩ 上拉电阻,确保信号稳定。
  2. 寄生电源限制:使用寄生供电时,需在温度转换期间保持总线高电平(可通过强上拉或外部电容储能)。
  3. 多传感器组网:需先通过 搜索 ROM 命令(0xF0) 或 匹配 ROM 命令(0x55) 寻址特定传感器。
  4. 抗干扰:长距离通信时建议使用屏蔽线,并降低总线速度(如延长时隙宽度)。


 六、驱动代码
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的驱动代码本文章的代码资源绑定文件里
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值