DS18B20 温度传感器驱动代码用法总结

一、DS18B20硬件介绍

1、DS18B20:

        在无干扰时,DS18B20 指示值近似室温;有自身发热或外部热源时,指示值偏向器件温度

2、通信方式:半双工

        因此,读、写和完成温度变换所需的电源可以由数据线本身提供,而不需要外部电源

        能够完成:温度转换→数据存储→与主机通信

<主从关系图>

3、优点:

        DS1820 靠 “唯一序列号” 实现了 “一根线连多个传感器且能区分彼此”,让 “多位置同时测温度” 变得更简单,因此能用于各种需要多点温度管理的场景

4、特点:

        独特的单线接口,只需1个接口引脚即可通信

        多点(multidrop)能力使分布式温度检测应用得以简化

        不需要外部元件

        可用数据线供电

        不需备份电源

        以9 位数字值方式读出温度

        在1秒(典型值)内把温度变换为数字

        用户可定义的,非易失性的温度告警设置

        告警搜索命令识别和寻址温度在编定的极限之外的器件 (温度告警情况)

        应用范围包括恒温控制,工业系统,消费类产品,温度计或任何热敏系统

5、测量范围:

          -55℃-125℃

6、测量精度:

        ±0.5℃

7、引脚排列

引 脚(8 脚 SOIC) 引脚 PR35 符号 说明
5 1 GND
4 2 DQ

单线运用的数据输入 / 输出引脚:漏极开路见 “寄生电源” 一节

(51单片机连接P37引脚)

3 3 V₍DD₎ 可选 V₍DD₎引脚。有关连接的细节见 “寄生电源” 一节

▲ 51单片机的P37引脚:外接上拉电阻->保证空闲状态是高电平

     满足DS18B20单总线 “空闲高电平” 的通信要求

二、代码实现

1、main.c

#include <reg51.h>
#include <stdio.h>
#include <intrins.h>
#include "ds18b20.h"
#include "uart.h"


int main(void)
{
	float ret = 0;
	xdata char s[20];

	Uart_Init();

	while (1)
	{
		ret = get_tmp();
		sprintf(s,"%f",ret);
		Uart_SendStr(s);
	
	}

	return 0;
}

2、ds18b20.c

#include <reg51.h>
#include <stdio.h>
#include <intrins.h>
#include "delay.h"
#include "uart.h"

#define DQ_HIGH ((P3 |= (1<<7))) 		//将与DQ相连接的P37号引脚制1
#define DQ_DOWN ((P3 &= ~(1<<7)))		//将与DQ相连接的P37号引脚制0
#define DQ_CHECK ((P3 & (1<<7)) != 0)		//检测DQ引脚电平 p37为1时 为 1
											// DQ_CHECK为1是高电平

//ds18b20 复位函数
//过程满足:主机发送复位脉冲 → 传感器回应存在脉冲(有两个阶段) → 主机确认存在脉冲
int ds18b20_Reset(void)
{
	int t = 0;

	//*初始化 —> 复位和存在脉冲
	//ds18b20 的p3 连接着一个上拉电阻 所以空闲时是高电平

	DQ_DOWN;	 		//将DQ引脚拉低
	Delay10us(70);		// 延时700us
	DQ_HIGH;			//将DQ引脚拉高
	Delay10us(5);		// 延时50us
	
	//*检测传感器是否存在脉冲的 第一阶段 (现高电平)
	//在300us内检测DQ引脚是否被ds18b20拉低,被拉低代表ds18b20回复了一个存在脉冲信号
	while (DQ_CHECK && t < 30)	//高电平进入循环等待,低电平跳出循环(说明回复了一个存在脉冲信号)
	{
		Delay10us(1);
		t++;		
	}
	if (t >= 30) //如果300us内没恢复低电平,返回失败
	{
		return 0;
	}
	t = 0;
	// *检测传感器是否存在脉冲的 第二阶段 (现低电平)
	// 在300us内检测DQ引脚是否被ds18b20拉高
	while (!DQ_CHECK && t < 30)
	{
		Delay10us(1);
		t++;	
	}
	if (t > 30)	//如果300us内没恢复高电平,返回失败
	{
		return 0;
	}

	//两个阶段都检测成功,返回 1 表示传感器存在且正常
	return 1;

}


// 向ds18b20发送一个字节数据
void write_ds18b20(unsigned char dat)
{
	int i = 0;

    //* 循环判断要发送的数据中的8bit是1还是0
	// 写 1 时:只需极短拉低(≥1μs)
	//写 0 时:需要长拉低(≥60μs)
	for (i = 0; i < 8; i++)
	{
		if (dat & 1)  //bit -> 1
		{
			DQ_DOWN;
			_nop_();
			_nop_();
			DQ_HIGH;
			Delay10us(5);
		}
		else  			//bit -> 0
		{
			DQ_DOWN;
			Delay10us(5);
			DQ_HIGH;
		}
		dat >>= 1;
	
	}
}

// 从ds18b20读取一个字节数据
unsigned char read_ds18b20(void)
{
	int i = 0;
	unsigned char ret = 0;

	for (i = 0; i < 8 ; i++)
	{
		DQ_DOWN;
		_nop_();
		_nop_();
		DQ_HIGH;
		_nop_();
		_nop_();
		_nop_();

		if (DQ_CHECK)   // 如果DQ是高位,ds18b20发送一个bit1
		{
			ret |= (1 << i);
		}
		Delay10us(5);
	
	}
	 return ret;
}

// 获取ds18b20采集到的温度
float get_tmp(void)
{
	short ret = 0;
	unsigned char tl = 0;
	unsigned char th = 0;

	ds18b20_Reset();
	write_ds18b20(0xCC);
	write_ds18b20(0x44);
	Delay1ms(1000);
	ds18b20_Reset();
	write_ds18b20(0xCC);
	write_ds18b20(0xBE);

	tl = read_ds18b20();
	th = read_ds18b20();


	ret = th << 8;
	ret |= tl;

	return ret * 0.0625;		
}

3、ds18b20.h

#ifndef DS18B20_H__
#define DS18B20_H__

extern int ds18b20_Reset(void);
extern void write_ds18b20(unsigned char dat);
extern unsigned char read_ds18b20(void);
extern float get_tmp(void);

#endif

4、uart.c

#include <reg51.h>

xdata char recv_buffer[32];
unsigned int pos = 0;

// 串口接收服务
void uart_RecvHandler(void) interrupt 4
{
	if ((SCON & (1 << 0)) == 1)
	{
		if (pos < 32)
		{
			recv_buffer[pos++] = SBUF;
			recv_buffer[pos] = 0;
		}
		SCON &= ~(1 << 0);
	}
}

//串口初始化
void Uart_Init(void)
{
	//将scon寄存器中的bit6和bit7清0
	SCON &= ~(3 << 6);

	//串口工作模式选择:SMO:0 SM1:1 代表串口工作在8位UART模式
	SCON |= (1 << 6);

	// 允许串口接收数据
	SCON |= (1 << 4); 


	// 串口波特率加倍
	PCON &= ~(1 << 6);
	PCON |= (1 << 7);
            

	// TMOD寄存器高四位清0
	// 定时器1工作在8位自动重装模式
	TMOD &= ~(0x0F << 4);        
	TMOD |= (1 << 5);            

	// 2 ^ 8 - 2 ^ smod * focs/32/bps/12	bps:2400
	TL1 = 230;			        
	TH1 = 230;

	// 允许定时器1开始计数
	TCON |= (1 << 6);             

	// 允许CPU响应中断 + 允许串口产生中断
	IE |= (1 << 7) | (1 << 4);    
}

void Uart_SendChar(unsigned char ch)
{
	SBUF = ch;
	while ((SCON & (1 << 1)) == 0);

	SCON &= ~(1 << 1);

}

void Uart_SendStr(const char *p)
{
	while (*p)
	{
	 	Uart_SendChar(*p++);
	} 
}

void Uart_SendBuffer(const char *p,int len)
{
	while(len--)
	{
		Uart_SendChar(*p++);
	}
}

5、uart.h

#ifndef UART_H__
#define UART_H__

extern void Uart_Init(void);
extern void Uart_SendChar(unsigned char ch);
extern void Uart_SendStr(const char *p);
extern void Uart_SendBuffer(const char *p,int len);
extern xdata char recv_buffer[32];
extern unsigned int pos;

#endif

6、delay.c

#include <intrins.h>

//粗略进行延时
void delay(unsigned int n)
{
	while(n--);
}

 //12MHz晶振版本 更加精准控制时间
void Delay10us(unsigned int n)	//@12.000MHz
{
	unsigned char data i;

	_nop_();
 	_nop_();
 	_nop_();
 	i = 2 * n;
 	while (--i)
 	{			
 		_nop_();		
 	}
}

void Delay1ms(unsigned int n)
{
	while(n--)
	{
		Delay10us(100);
	}
}

7、delay.h

#ifndef DELAY_H__
#define DELAY_H__

extern void delay(unsigned int n);
extern void Delay10us(unsigned int n);
extern void Delay1ms(unsigned int n);

#endif

三、核心函数功能说明

文件 功能 核心作用
main.c 主程序逻辑 循环获取温度并通过串口发送
ds18b20.c DS18B20 驱动(复位 / 读写 / 测温) 实现单总线通信协议,获取温度值
uart.c 串口初始化与数据发送 将温度数据转换为字符串输出
delay.c 延时函数 提供单总线通信所需的精确时序(μs 级)
.h文件 函数 / 变量声明 实现跨文件调用,模块解耦

四、核心流程详解(main)

1、初始化阶段:

        Uart_Init(); // 初始化串口,设置波特率、工作模式

2、2. 循环测温与发送:

        main()内的while(1)

ret = get_tmp(); // 获取温度值(float类型)

sprintf(s,"%f",ret); // 转换为字符串

Uart_SendStr(s); // 串口发送字符串

        核心是get_tmp()函数,它封装了 DS18B20 的完整测温流程

五、单总线通信协议的软件实现(DS18B20

1、复位函数:ds18b20_Reset(void)

线型图例
复位时序图

        实现的原理:DS18B20 的通信依赖严格的时序,根据时序图电平的起伏以及所需的时间进行的结合精确的延时函数,模拟时序图中 “电平起伏的时间规律”,从而实现让传感器能识别命令、传输数据(复位、写指令、读温度等操作)

        功能:向 DS18B20 发送复位信号,并检测传感器是否响应

        流程:拉低 DQ 引脚 700us(复位信号)→ 释放引脚 50us → 检测 300us 内是否收到传感器的应答信号(低电平)→ 检测 300us 内应答信号是否结束(恢复高电平)

        返回值1表示传感器响应正常;0表示无响应(通信失败)

2、写数据函数:write_ds18b20(unsigned char dat)

写时序图

        功能:向 DS18B20 写入 1 字节数据(8 位)

        原理:按位发送数据,每位时序如下:

        发送1:拉低 DQ 引脚 2 个时钟周期 → 释放引脚 → 延时 50us

        发送0:拉低 DQ 引脚 50us → 释放引脚

3、读数据函数:read_ds18b20(void)

读时序

        功能:从 DS18B20 读取 1 字节数据(8 位)

        原理:按位读取数据,每位时序如下:

        拉低 DQ 引脚 2 个时钟周期 → 释放引脚 → 延迟 3 个时钟周期后检测 DQ 引脚电平 → 高电平表示读入1,低电平表示读入0 → 延时 50us

        返回值:读取到的 1 字节数据

4、温度读取函数:get_temp(void)

        功能:触发温度转换并读取转换后的温度值

        流程

        复位传感器 → 发送跳过 ROM 指令(0xCC)→ 发送温度转换指令(0x44)→ 延时 1000ms 等待转换完成

        再次复位 → 发送跳过 ROM 指令(0xCC)→ 发送读取暂存器指令(0xBE

        读取温度低 8 位(tl)和高 8 位(th)→ 组合为 16 位数据(ret = th << 8 | tl)。

        转换为温度值:ret * 0.0625(DS18B20 的温度分辨率为 0.0625℃)

        返回值:float 类型的温度值(单位:℃)

六、使用方法

  1. 确保硬件连接正确(DQ 引脚接 P3.7,电源和地正常连接)
  2. 初始化延时函数(Delay10us()Delay1ms()
  3. 直接调用get_temp()函数即可获取当前温度,例如:
    float temp;
    temp = get_temp(); // 读取温度值
    

七、注意事项

  1. 通信时序严格依赖延时函数,若延时不准确会导致通信失败
  2. get_temp()函数中包含 1000ms 的转换等待时间,若需优化响应速度,可根据 DS18B20 的转换速率调整延时(最高精度下转换时间约 750ms)
  3. 若总线上有多个 DS18B20,需修改代码(替换0xCC指令)以支持 ROM 匹配,当前代码默认单传感器场景(跳过 ROM)
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐