DS18B20

发布时间 2023-11-14 21:56:59作者: Laplace蒜子

DS18B20 介绍

DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线)”接口的温度传感器。

 

特点

  1. 适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电。
  2. 一条口线实现处理器和DS18B20双向通讯。
  3. 可以组网多点测温,DS18B20 支持多点组网功能,多个DS18B20 可以并联在唯一的三线上,实现组网多点测温。
  4. DS18B20 在使用中不需要任何外围元件,全部传感元件及转换电路集成,在形如一只三极管的集成电路内。
  5. 温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃
  6. 可编程的分辨率为 9~12 位,对应的可分辨温度分别为 0.5℃、0.25℃、0.125℃ 和 0.0625℃,可实现高精度测温。
  7. 在 9 位分辨率时最多在 93.75ms 内把温度转换为数字,12 位分辨率时最多在 750ms 内把温度值转换为数字,速度更快。
  8. 测量结果直接输出数字温度信号,以"一根总线"串行传送给 CPU,同时可传送 CRC 校验码,具有极强的抗干扰纠错能力。
  9. 负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。

元器件结构

外部结构

共三根线,地线,信号线,电源线。

内部结构

ROM 中的 64 位序列号是出厂前被光刻好的,作为该 DS18B20 的地址序列号,用于在多个DS18B20中做区分。

高速缓存

用于存储温度转换后的二进制数。

配置寄存器

用于配置采样的精度。

TM为1表示测试模式,为0表示工作模式,出厂时默认为0。

R1和R0两位用于设置分辨率,可以分别设置为9位,10位,11位,12位。

假设精度为10位就是0-1023。

温度寄存器

温度寄存器处于高速缓存存储器内,用于记录采集的温度。

由低字节和高字节组成。高字节前5位为S,若S为0,则表明温度≥0,若S为1,则表明温度<0;

大于等于零,正数的源码和补码都一样,直接使用即可。

小于零,则需要将其他数值位取反再加1,再使用。

设精度为12位,也就是范围为0-4095,会将传感器测量范围归一化到0-4095区间。对应的精度为0.0625℃。

若采集得到的温度为0000 0101 0101 0000,转换后面11位为十进制就是1360,转换成实际的温度就是1360x0.0625=85,也就是85℃

若采集得到的温度为1111 1100 1001 0000,由于前5位位1,对后11位取反,得到011 0110 1111,转换为十进制就是879,879 x 0.0625=54.93度,也就是-54.93℃。

 

从存储寄存器读取到的数据就是以上数据。

 

工作模式

主机控制信号线,向DS18B20写入命令(字节表示),然后DS18B20完成指定动作,数值放在高速缓存寄存器中,然后主机控制信号线,从高速缓存读取数据。

初始化时序

主机设置信号线为低电平0,保持至少480us,产生复位脉冲。(此期间DS18B20使用while等待,检测主机将信号线设置为0,继续下一步准备回复,等待主机释放总线即可。)

主机设置信号线为高电平1,释放总线,等到DS18B20应答。

DS18B20在回复存在脉冲,设置信号线位低电平0,保持60us-240us。(此期间主机使用while等待,检测DS18B20将信号线设置为0。)

DS18B20将信号线设置为高电平1,延时200us,表示回复完毕。(此期间主机收到存在脉冲,使用while等待DS18B20释放信号线。)

保持信号一定时间的目的是为了另一端使用while循环等待期间信号时能检测到。

写时序

写的目的是主机将命令写入DS18B20,让其完成指定动作,写必须一位一位的写完一个字节。

写0步骤:设置信号线为低电平0,并保持60us,设置信号线为高电平1,延时2us。

写1步骤:设置信号线为高电平0,并保持2us,设置信号线为高电平1,延时60us。

写0和写1都要设置为低电平,只不过写0低电平保持时间长,写1高电平保持时间长。

代码如下

void ds18b20_write_byte(u8 dat)	  //往ds18b20写一个字节,用于写指令,如写启动转换指令或者跳过查询指令
{
	u8 i=0;
	u8 temp=0;

	for(i=0;i<8;i++)//循环8次,每次写一位,且先写低位再写高位
	{
		temp=dat&0x01;//选择低位准备写入,与00000001做与运算,只得到最低位置结果。
		dat>>=1;//将次高位移到低位
		if(temp)	//写1,如果当前低位为1
		{
			DS18B20_PORT=0;		 //拉低电平0,
			_nop_();_nop_();	 //延迟2us,
			DS18B20_PORT=1;		 //拉高电平
			delay_10us(6);	     //延迟60us
		}
		else				  //写0,如果当前低位为0
		{									    
			DS18B20_PORT=0;	 	 //拉低电平0,
			delay_10us(6);		   //延迟60us
			DS18B20_PORT=1;		 //拉高电平
			_nop_();_nop_();	//延迟2us,
		}	
	}	
}

读时序

读也只能一位一位的读取。目的是从温度寄存器中读取二进制位的数值。

读一个数步骤

  1. 主机将信号线设置为低电平0。
  2. 等待两个指令周期,约2us。
  3. 主机将信号线设置为高电平1。
  4. 等待两个指令周期,约2us。
  5. 读取信号线的电平。
  6. 延时50us。

主机将信号线发送一个上升沿,则表明从机可以将数值设置到信号线上了。

代码

u8 ds18b20_read_bit(void)//读一位
{
	u8 dat=0;
	DS18B20_PORT=0;	  //主机拉低总线电平
	_nop_();_nop_(); //延迟2us,主机转变为输入模式,nop表示延时一个指令周期,也就是12个时钟周期,等于1us
	DS18B20_PORT=1;	  //拉高总线电平
	_nop_();_nop_(); //等待从机设置总线电平 该段时间不能过长,必须在15us内读取数据
	if(DS18B20_PORT)dat=1;//读取当前总线电平
	else dat=0;
	delay_10us(5); //延时50us
	return dat;
} 
u8 ds18b20_read_byte(void)
{
	u8 i=0;
	u8 dat=0;
	u8 temp=0;
	for(i=0;i<8;i++)//循环8次,每次读取一位,且先读低位再读高位
	{
		temp=ds18b20_read_bit();
		dat=(temp<<7)|(dat>>1);//temp只有0和1,将最低位移动到最高位。
	}
	//读取方法,将temp放到最高位,dat左移一位后,最高位为0,与temp或运算,最高位由temp决定。
	//temp 10000000   dat 00000000->0000000   ->  1000 0000
	//temp 10000000   dat 10000000->0100000   ->  1100 0000
	//temo 00000000   dat 11000000->0110000   ->  0110 0000
	return dat;	
}

整个工作流程

复位→发 SKIP ROM 命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送 SKIP ROM 命令(0XCC)→发读存储器命令(0XBE)→连续读出两个字节数据(即温度)→结束

 0xcc是跳过ROM查询,因为只有单个ds18b20传感器,不需要区分ds18b20,所以使用0xcc跳过查询命令,直接下一步转换。

0x44是转换命令,命令DS18B20将温度转换到高速缓存中。

0xBE是读暂存器的命令,读取9个字节的暂存器。

 

数码管实时显示温度代码

ds18b20.h文件

#ifndef _ds18b20_H
#define _ds18b20_H
#include "public.h"
sbit DS18B20_PORT=P3^7;
u8 ds18b20_init(void);
float ds18b20_read_temperture(void);
#endif

ds18b20.c文件

#include"ds18b20.h"
#include"intrins.h"

void ds18b20_reset(void){	//主机产生复位脉冲,进入接收模式。
	DS18B20_PORT=0;	  //拉低DQ
	delay_us(55);			   //保持750us 产生复位脉冲(480us~960us)
	DS18B20_PORT=1;	   //释放      上拉
	delay_10us(2);	   //延时20us	 要求时延范围(15us~60us)
}					   

u8 ds18b20_check(void)//主机等待从机回复,返回0表示成功,返回1表示失败
	//主机进入接收模式后检查。 从机必须在200us内回复低电平。
{
	u8 time_temp=0;

	while(DS18B20_PORT&&time_temp<20)	//主机等待从机回复0,   从机感受到复位脉冲后,需要回复存在脉冲,低电平持续时间60us-240us。
	{
		time_temp++;
		delay_10us(1);	
	}
	if(time_temp>=20)return 1;	//如果超时则强制返回1
	else time_temp=0;
	while((!DS18B20_PORT)&&time_temp<20)	//主机从机的存在脉冲,等待从机拉高电平,从机也必须在200us内拉高电平。
	{
		time_temp++;
		delay_10us(1);
	}
	if(time_temp>=20)return 1;	//如果超时则强制返回1
	return 0;						   
}

u8 ds18b20_read_bit(void)//读一位
{
	u8 dat=0;
	DS18B20_PORT=0;	  //主机拉低总线电平
	_nop_();_nop_(); //延迟2us,主机转变为输入模式,nop表示延时一个指令周期,也就是12个时钟周期,等于1us
	DS18B20_PORT=1;	  //拉高总线电平
	_nop_();_nop_(); //等待从机设置总线电平 该段时间不能过长,必须在15us内读取数据
	if(DS18B20_PORT)dat=1;//读取当前总线电平
	else dat=0;
	delay_10us(5); //延时50us
	return dat;
} 

u8 ds18b20_read_byte(void)
{
	u8 i=0;
	u8 dat=0;
	u8 temp=0;

	for(i=0;i<8;i++)//循环8次,每次读取一位,且先读低位再读高位
	{
		temp=ds18b20_read_bit();
		dat=(temp<<7)|(dat>>1);//temp只有0和1,将最低位移动到最高位。
	}
	//读取方法,将temp放到最高位,dat左移一位后,最高位为0,与temp或运算,最高位由temp决定。
	//temp 10000000   dat 00000000->0000000   ->  1000 0000
	//temp 10000000   dat 10000000->0100000   ->  1100 0000
	//temo 00000000   dat 11000000->0110000   ->  0110 0000
	return dat;	
}


void ds18b20_write_byte(u8 dat)	  //往ds18b20写一个字节,用于写指令,如写启动转换指令或者跳过查询指令
{
	u8 i=0;
	u8 temp=0;

	for(i=0;i<8;i++)//循环8次,每次写一位,且先写低位再写高位
	{
		temp=dat&0x01;//选择低位准备写入,与00000001做与运算,只得到最低位置结果。
		dat>>=1;//将次高位移到低位
		if(temp)	//写1,如果当前低位为1
		{
			DS18B20_PORT=0;		 //拉低电平,
			_nop_();_nop_();	 //延迟2us,
			DS18B20_PORT=1;		 //拉高电平
			delay_10us(6);	     //延迟60us
		}
		else				  //写0,如果当前低位为0
		{									    
			DS18B20_PORT=0;	 	 //拉低电平,
			delay_10us(6);		   //延迟60us
			DS18B20_PORT=1;		 //拉高电平
			_nop_();_nop_();	//延迟2us,
		}	
	}	
}

void ds18b20_start(void)
{
	ds18b20_reset();//主机发送复位脉冲
	ds18b20_check();//主机等待DS18B20的存在脉冲。
	ds18b20_write_byte(0xcc);//SKIP ROM
    ds18b20_write_byte(0x44);//温度转换命令0x44,之后温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。	
}

u8 ds18b20_init(void)
{
	ds18b20_reset();
	return ds18b20_check();	
}

float ds18b20_read_temperture(void)
{
	float temp;
	u8 dath=0;
	u8 datl=0;
	u16 value=0;

	ds18b20_start();//开始转换
	ds18b20_reset();//复位
	ds18b20_check();
	ds18b20_write_byte(0xcc);//SKIP ROM	 ,因为只有单个ds18b20传感器,不需要区分ds18b20,所以使用0xcc跳过查询命令,直接下一步转换。
    ds18b20_write_byte(0xbe);//读存储器

	datl=ds18b20_read_byte();//低字节
	dath=ds18b20_read_byte();//高字节
	value=(dath<<8)+datl;//合并为16位数据

	if((value&0xf800)==0xf800)//判断符号位,负温度
	{
		value=(~value)+1; //数据取反再加1
		temp=value*(-0.0625);//乘以精度	
	}
	else //正温度
	{
		temp=value*0.0625;	
	}
	return temp;
}

 smg.h文件

#ifndef _smg_H
#define _smg_H

#include "public.h"


#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口

//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

extern u8 gsmg_code[17];

void smg_display(u8 dat[],u8 pos);

#endif

smg.c文件

#include "smg.h"

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能		 : 动态数码管显示
* 输    入       : dat:要显示的数据
				   pos:从左开始第几个位置开始显示,范围1-8
* 输    出    	 : 无
*******************************************************************************/
void smg_display(u8 dat[],u8 pos)
{
	u8 i=0;
	u8 pos_temp=pos-1;

	for(i=pos_temp;i<8;i++)
	{
	   	switch(i)//位选
		{
			case 0: LSC=1;LSB=1;LSA=1;break;
			case 1: LSC=1;LSB=1;LSA=0;break;
			case 2: LSC=1;LSB=0;LSA=1;break;
			case 3: LSC=1;LSB=0;LSA=0;break;
			case 4: LSC=0;LSB=1;LSA=1;break;
			case 5: LSC=0;LSB=1;LSA=0;break;
			case 6: LSC=0;LSB=0;LSA=1;break;
			case 7: LSC=0;LSB=0;LSA=0;break;
		}
		SMG_A_DP_PORT=dat[i-pos_temp];//传送段选数据
		delay_10us(100);//延时一段时间,等待显示稳定
		SMG_A_DP_PORT=0x00;//消音
	}
}

public.h文件

#include"public.h"
void delay_10us(u16 ten_us){
	while(ten_us--);
}
void delay_ms(u16 ms){
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);
}

main.c文件

															   /**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
PRECHIN
 普中

实验名称:DS18B20温度传感器实验
接线说明:	
实验现象:下载程序后,插上DS18B20温度传感器,数码管显示检测的温度值
注意事项:注意温度传感器的方向,在接口处我们已经用丝印画了一个凸起,
		  所以只需要将温度传感器对应插入即可																				  
***************************************************************************************/
#include "public.h"
#include "smg.h"
#include "ds18b20.h"


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 i=0;
   	int temp_value;
	u8 temp_buf[5];

	ds18b20_init();//初始化DS18B20

	while(1)
	{				
		i++;
		if(i%50==0)//间隔一段时间读取温度值,间隔时间要大于温度传感器转换温度时间
			temp_value=ds18b20_read_temperture()*10;//保留温度值小数后一位
		if(temp_value<0)//负温度
		{
			temp_value=-temp_value;
			temp_buf[0]=0x40;//显示负号	
		}
		else
			temp_buf[0]=0x00;//不显示
		temp_buf[1]=gsmg_code[temp_value/1000];//百位
		temp_buf[2]=gsmg_code[temp_value%1000/100];//十位
		temp_buf[3]=gsmg_code[temp_value%1000%100/10]|0x80;//个位+小数点
		temp_buf[4]=gsmg_code[temp_value%1000%100%10];//小数点后一位
		smg_display(temp_buf,4);
	}		
}