《电子DIY》之基于STM32驱动温度传感器DS18B20

一,DS18B20温度传感器简介

DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点,应用广泛。
技术特性:
①、 独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
② 、测温范围 -55℃~+125℃,固有测温误差1℃。
③、支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只能并联8个,实现多点测温,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。
④、工作电源: 3.0~5.5V/DC (可以数据线寄生电源)
⑤ 、在使用中不需要任何外围元件
⑥、 测量结果以9~12位数字量方式串行传送
⑦ 、不锈钢保护管直径 Φ6
⑧ 、适用于DN15~25, DN40~DN250各种介质工业管道和狭小空间设备测温
⑨、 标准安装螺纹 M10X1, M12X1.5, G1/2”任选
⑩ 、PVC电缆直接出线或德式球型接线盒出线,便于与其它电器设备连接。

DS18B20的读写时序和测温原理: DS18B20测温原理如图1所示。图中低温度系数晶振的振荡频率受温度影响很小,用于产生固定频率的脉冲信号发送给计数器1。高温度系数晶振随温度变化其振荡频率明显改变,所产生的信号作为计数器2的脉冲输入。计数器1和温度寄存器被预置在-55℃所对应的一个基数值。计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当计数器1的预置值减到0时,温度寄存器的值将加1,计数器1的预置将重新被装入,计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温度。斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正计数器1的预置值。
(以上摘自百度)

图1如下图:
在这里插入图片描述
DS18B20模块实物图
在这里插入图片描述

二,DS18B20与MCU连接图

在这里插入图片描述

三,DS18B20引脚定义:

在这里插入图片描述

DQ: 数据输入/输出。开漏1线接口。也可以在寄生电源模式中使用时为设备提供电源
VDD:电源正极
GND:电源地

四,DS18B20内部分析介绍:

在这里插入图片描述
上图显示DS18B20的框图,64位ROM存储设备的唯一串行代码。缓冲存储器包含2字节存储温度传感器数字输出的温度寄存器。另外,缓冲存储器提供对1字节上下报警触发寄存器(TH和TL)和1字节的访问配置寄存器。配置寄存器允许用户将温度到数字转换的分辨率设置为9、10、11或12位TH、TL和配置寄存器是非易失性的(EEPROM),因此当设备断电时,它们将保留数据。DS18B20使用Maxim独有的1线总线协议,该协议使用一个控制信号。控制线需要一个弱的上拉电阻,因为所有设备都连接到总线上通过3状态或开放式漏极端口(DS18B20的情况下为DQ引脚)。在此总线系统中微处理器(主设备)使用每个设备的 唯一64位代码。因为每个设备都有一个唯一的代码,所以可以在一条总线上寻址的设备数量实际上是无限的。

温度寄存器格式
在这里插入图片描述
温度/数据关系
在这里插入图片描述
操作报警信号

DS18B20执行温度转换后,将温度值与存储在1字节TH和TL寄存器中的用户定义的两个补码报警触发值进行比较。符号位表示值是正是负:正数S=0,负数S=1,TH和TL寄存器是非易失性的(EEPROM),因此当设备已关机。TH和TL可以通过存储器的字节2和3进行访问。

TH和TL寄存器格式:
在这里插入图片描述
使用外部电源为DS18B20供电原理图
在这里插入图片描述
64位激光只读存储器代码:
在这里插入图片描述
每个DS18B20包含一个唯一的64位代码,存储在ROM中。最低有效8位ROM代码中包含DS18B20的单线族代码:28h。接下来的48位包含唯一的序列号。最重要的8位包含一个循环冗余校验(CRC)字节,即从ROM码的前56位开始计算。

DS18B20内存映射
在这里插入图片描述
配置寄存器:
图2:
在这里插入图片描述存储器的字节4包含配置寄存器,其组织方式如所示图2。用户可以使用这里的R0和R1位设置DS18B20的转换分辨率寄存器如表2所示。这些位的通电默认值为R0=1和R1=1(12位分辨率)。请注意,分辨率和转换时间之间存在直接的关系。中的位7和位0到4配置寄存器是为设备内部使用而保留的,不能被覆盖。
表2温度计分辨率配置
在这里插入图片描述
CRC生成
CRC字节是DS18B20 64位ROM代码的一部分,并在暂存器的第9个字节中提供。 ROM代码CRC由ROM代码的前56位计算得出,并包含在ROM的最高有效字节。暂存器CRC是根据存储在暂存器,因此当暂存器中的数据更改时,它也会更改。 CRC提供总线从DS18B20读取数据时,主机具有数据验证方法。验证数据是否具有正确读取后,总线主机必须从接收到的数据中重新计算CRC,然后进行比较将该值写入ROM代码CRC(用于ROM读取)或暂存器CRC(用于暂存器读取)。如果计算出的CRC与读取的CRC相匹配,则表明已正确接收数据。比较CRC值和继续进行操作的决定完全由总线主机决定。如果出现以下情况,DS18B20内部没有电路可以阻止执行命令序列:
DS18B20 CRC(ROM或暂存器)与总线主机生成的值不匹配。
CRC的等效多项式函数为:
CRC = X8 + X5 + X4 + 1

总线主机可以重新计算CRC并将其与DS18B20的CRC值进行比较,方法是:
多项式发生器,如图3所示。该电路包括一个移位寄存器和yihuo门,以及移位寄存器的位初始化为0。以ROM代码的最低有效位或最低暂存器中字节0的有效位,一次一次应移入移位寄存器。 后从ROM移入第56位或暂存器移入字节7的最高有效位,多项式生成器将包含重新计算的CRC。 接下来,使用8位ROM代码或暂存器CRCDS18B20中的信号必须移入电路。 此时,如果重新计算的CRC正确,则移位寄存器将全为0。
图3:CRC产生器
在这里插入图片描述

五,访问DS18B20:

访问DS18B20的顺序如下:
步骤1.初始化
步骤2. ROM命令(随后进行任何必需的数据交换)
步骤3. DS18B20功能命令(随后进行任何必需的数据交换)

:每次访问DS18B20时都遵循此顺序,因为如果序列中的任何步骤丢失或顺序混乱,DS18B20不会做出响应。此规则的例外是搜索ROM [F0h]和警报搜索[ECh]命令。 发出这两个ROM命令后,主机必须按顺序返回步骤1。
(以上介绍从官方手册翻译过来)

ROM命令
1,读ROM [33h]
2,匹配ROM [55h]
3,跳过ROM [CCh]
4,警报搜索[ECh]

DS18B20功能命令
1,转换温度 [44h]
2,写暂存器(存储器)[4Eh]
3,读暂存器(存储器)[BEh]
4,复制暂存器(存储器[48h]
5,重新唤醒 E2[B8h]
6,读取电源[B4h]
(以上命令详细介绍见官方手册)

六,访问DS18B20时序

在初始化过程中,总线主机通过拉动1-Wire总线发送(TX)复位脉冲低电平持续至少480µs。 然后,总线主控器释放总线并进入接收模(RX)。释放总线后,5kΩ上拉电阻将1-Wire总线拉高。 当DS18B20检测到在这个上升沿,它等待15µs至60µs,然后通过将1-Wire总线拉低来发送存在脉冲持续60µs至240µs。
初始化时序:
在这里插入图片描述
写时隙有两种类型:“写入1”时隙和“写入0”时隙。 总线使用Write 1时隙将逻辑1写入DS18B20,使用Write 0时隙将逻辑0写入DS18B20。DS18B20。 所有写入时隙的持续时间必须至少为60µs,恢复时间至少为1µs,各个写时隙之间的时间。 两种类型的写时隙均由主机拉动1-Wire总线为低电平(见图14)。为了产生写1时隙,将1-Wire总线拉低后,总线主机必须释放1-Wire
总线在15µs之内。 释放总线后,5kΩ上拉电阻会将总线拉高。 产生一个
写入0时隙,将1-Wire总线拉低后,总线主机必须继续将总线保持低电平以保持时隙的持续时间(至少60µs)。DS18B20在主机之后的15µs至60µs的窗口内对1-Wire总线进行采样启动写时隙。 如果在采样窗口中总线为高电平,则将1写入DS18B20。如果该线为低电平,则向DS18B20写入0。
备注:Timeslot(时隙)专用于某一个单个通道的时隙信息的串行自复用的一个部分。

图14如下:
在这里插入图片描述
读时隙:
DS18B20仅在主机发出读取时隙时才能将数据发送到主机。因此,主机必须在发出Read 存储器命令[BEh]或Read Power Supply [B4h]命令后立即生成读取时隙,以便DS18B20提供所需的数据。另外,主机可以在发出Convert T [44h]或Recall E2 [B8h]命令以找出状态后生成读取时隙。所有读取时隙的持续时间必须至少为60µs,时隙之间的恢复时间最少为1µs。 读时隙由主器件启动,将1-Wire总线拉低以保持低电平。至少1µs,然后释放总线(见图14)。 主机启动读取时隙后,DS18B20将开始在总线上发送1或0,DS18B20通过将总线保持高电平来发送1并通过拉低总线发送0。 当发送0时,DS18B20将通过总线释放总线。时隙结束,总线将被上拉电阻器拉回到高空闲状态。

详细主机读1时隙:
在这里插入图片描述
推荐主机读1时隙:
在这里插入图片描述
(更详细介绍见官方手册)

七,读取DS18B20数据源程序:

DS18B20 头文件

#ifndef __DS18B20_H
#define __DS18B20_H 
#include "sys.h"   
#define  DS18B20_CLOCK  RCC_APB2Periph_GPIOA
#define  DS18B20_PIN_DQ GPIO_Pin_11
#define  DS18B20_PORT   GPIOA
typedef struct __DS18B20
{
	int temperature;
	float handleDAT;
	u16 retry;
	u8 flag;
}DS18B20;
extern DS18B20 ds18b20;
#define DS18B20_IO_IN()  {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=8<<12;}
#define DS18B20_IO_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=3<<12;}										   
#define	DS18B20_DQ_OUT PAout(11) 
#define	DS18B20_DQ_IN  PAin(11)    	
void  DS18B20_Init(void);
void DS18B20_Get_Temperature(void);
void DS18B20_Start(void);
void DS18B20_Write_Byte(u8 dat);
u8 DS18B20_Read_Byte(void);
u8 DS18B20_Read_Bit(void);
u8 DS18B20_Check(void);
void DS18B20_Rst(void);   
#endif

DS18B20 C文件

#include "ds18b20.h"
#include "delay.h"	

DS18B20  ds18b20={0,0.0,0,0};
/*
*	函数名称:复位DS18B20
*   参数:    无
*   返回值: 无
*/
void DS18B20_Rst(void)	   
{                 
	DS18B20_IO_OUT(); 	
    DS18B20_DQ_OUT=0; 
    delay_us(666);    // >=480 us 	
    DS18B20_DQ_OUT=1; 
	delay_us(32);     // 15-60 us 	
}

/*
*	函数名称:检测DS18B20
*   参数:    无
*   返回值:  一位
*           //返回1:未检测到DS18B20的存在
*           //返回0:存在
*/
u8 DS18B20_Check(void) 	   
{   
	DS18B20_IO_IN();	
	ds18b20.retry=0;
    while (DS18B20_DQ_IN&&ds18b20.retry<250)
	{
		ds18b20.retry++;
		delay_us(1);
	};	 
	if(ds18b20.retry>=250)
		return 1;
	else 
		ds18b20.retry=0;
    while (!DS18B20_DQ_IN&&ds18b20.retry<240)// 60-240 us
	{
		ds18b20.retry++;
		delay_us(1);
	};
	if(ds18b20.retry>=240)
		return 1;	    
	return 0;
}

/*
*	函数名称:从DS18B20读取一个位
*   参数:    无
*   返回值:  一位
*/
u8 DS18B20_Read_Bit(void) 	 
{
    u8 dat;
	DS18B20_IO_OUT();	
    DS18B20_DQ_OUT=0; 
	delay_us(3);
    DS18B20_DQ_OUT=1; 
	DS18B20_IO_IN();	
	delay_us(12);
	if(DS18B20_DQ_IN)
		dat=1;
    else 
		dat=0;	 
    delay_us(50);           
    return dat;
}

/*
*	函数名称:从DS18B20读取一个字节
*   参数:    无
*   返回值:  读取得温度数据
*/
u8 DS18B20_Read_Byte(void)     
{        
    u8 k,bit,dat;
    dat=0;
	for (k=1;k<=8;k++) 
	{
        bit=DS18B20_Read_Bit();
        dat=(bit<<7)|(dat>>1);
    }						    
    return dat;
}

/*
*	函数名称:写一个字节到DS18B20
*   参数:    待写入的字节
*   返回值:  无
*/
void DS18B20_Write_Byte(u8 data)     
 {             
    u8 i;
    u8 temp;
	DS18B20_IO_OUT();	
    for (i=1;i<=8;i++) 
	{
        temp=data&0x01;
        data=data>>1;
        if (temp) 
        {
            DS18B20_DQ_OUT=0;	// Write 1
            delay_us(2);                            
            DS18B20_DQ_OUT=1;
            delay_us(60);             
        }
        else 
        {
            DS18B20_DQ_OUT=0;	// Write 0
            delay_us(60);             
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}

/*
*	函数名称:启动温度转换
*   参数:    无
*   返回值:  无
*/
void DS18B20_Start(void) 
{   						               
    DS18B20_Rst();	   
	DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0x44);	// convert
} 

/*
*	函数名称:初始化DS18B20的IO口
*   参数:    无
*   返回值:  无
*/
void DS18B20_Init(void)
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	RCC_APB2PeriphClockCmd(DS18B20_CLOCK, ENABLE);	
 	GPIO_InitStructure.GPIO_Pin = DS18B20_PIN_DQ;				
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(DS18B20_PORT, &GPIO_InitStructure);
 	GPIO_SetBits(DS18B20_PORT,DS18B20_PIN_DQ);    
	DS18B20_Rst();
} 

/*
*	函数名称:获取ds18b20的温度值
*   参数:    无
*   返回值:  温度值
*/
void DS18B20_Get_Temperature(void)
{
    u8 temp;
    u8 TL,TH;
	int tem;
    DS18B20_Start ();  			// ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	
    DS18B20_Write_Byte(0xbe);	    
    TL=DS18B20_Read_Byte(); 	// LSB   
    TH=DS18B20_Read_Byte(); 	// MSB  	  
    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
        temp=0;			//温度为负  
    }
	else 
		temp=1;			//温度为正	  	  
    tem=TH;
    tem<<=8;    
    tem+=TL;					
    ds18b20.handleDAT=(float)tem*0.625/10.0;		    
	if(temp)
		ds18b20.temperature=tem; 		
	else 
		ds18b20.temperature=(-1)*tem;    
}

八,效果图

(使用串口打印数据)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/liuxianfei0810/article/details/105903327