51+DS18B20测量温度

一.简述

DS18B20是DALLAS公司出品的一种数字式单总线温度传感器,测温范围为-55°C到125°C(-67°F到257°F),被广泛应用在温度测量领域中。显著优点就是接线简单。因为它只有三个引脚:VCC,GND和DQ数据线,可以实现单总线数据传输,简化了硬件设计。

而且,它可以使用数据线供电,可以再省去一个电源线,只要接地和数据线即可。

下面是一个TSOC封装的引脚图:

在实际使用中,要注意不能把它的正负极引脚接反,否则很容易造成芯片损坏。在实际使用时还常常用到下面这种形态的封装。这时可以如图所示,面朝芯片的平面一侧,从左到右依次是GND,DQ,VDD引脚。供电电源可取3V到5.5V。

此外,每一个DS18B20的内部都有一个唯一的64位长的编号作为标识,所以可以将多个DS18B20串在一根总线上实现温度查询测量。这个64位长的序列存储在其ROM中,开始8位为产品编号,同系列的DS18B20是相同的;接下来的48位为每个器件的唯一编号,最后8位为前面56位的循环校验码CRC码。

二.将存储器数据转换为实际温度的方法

DS18B20用两个存储器存储温度测量之。其中高8位为符号存储。若温度小于0,则此8位全为1;若温度大于0,则此8位均为0。为什么要采用这样的存储方式呢??在这种存储方式下,数据实际上是以补码的方式在存储。所以当我们用C语言编程的时候,可以直接把高8位和低8位组合到一起,然后直接赋给一个int型的变量。考虑到它的1LSB为0.0625°,所以我们还要再乘以0.0625才能得到真实的温度。

三.硬件连接

下面是我的单片机开发板的硬件连接图:

首先是DS18B20模块:

可以看到,在芯片的DQ引脚上又加了一个上拉电阻,这是是选择了10K。这是因为DS18B20输出高电平的能力不强,一般采用接上拉电阻的方式增强其输出能力,上拉电阻一般取4到5K即可。这是一种比较简单的上拉方法,其中DALLAS公司的数据手册中还提出了他们建议的上拉方法,可以参考其手册来设计。

微控制器部分采用STC的89C52,如下:

在这里,我们把DQ接到了单片机的P2.2引脚。

四.工作时序和操作方法

1.总体设计

我们首先编写DS18B20的头文件,完成对DS18B20硬件操作的封装。

#ifndef _DS18B20_H_
#define _DS18B20_H_

#include <reg52.h>

//ROM操作指令
#define start_ZH         0x44
#define read_ROM    	 0x33
#define match_ROM   	 0x55
#define skip_ROM    	 0xcc
#define search_ROM  	 0xf0
#define alarm_SEARCH 	 0xec  
#define write_RAM 		 0x4e
#define read_RAM 		 0xbe
#define copy_RAM 		 0x48
#define recall_EPROM 	 0xb8
#define read_POWER 	     0xb4

sbit ds=P2^2;

/*********************************
功能:初始化设备函数
参数:无
返回值:无
*********************************/
void Init_ds18b20();

/*********************************
功能:等待设备应答
参数:无
返回值:无
*********************************/
void Wait_ds18b20();

/*********************************
功能:读DS18B20的一位
参数:无
返回值:读取的一位数据
*********************************/
bit read_ds18b20_bit();

/*********************************
功能:读DS18B20的一字节
参数:无
返回值:读取的一个字节
*********************************/
uchar read_ds18b20_byte();

/*********************************
功能:写DS18B20的一位
参数:要写入的一位
返回值:无
*********************************/
void write_ds18b20_bit(bit dat);

/*********************************
功能:写DS18B20的一字节
参数:要写入的一个字节
返回值:无
*********************************/
void write_ds18b20_byte(uchar dat);

/*********************************
功能:发布指令
参数:无
返回值:无
*********************************/
void write_ds18b20_command(uchar com);

/*********************************
功能:得到当前温度值
参数:无
返回值:当前温度值
*********************************/
int getTemp();

#endif

在这个头文件里,我们编写了一般对一个可编程元件进行操作可能用到的函数声明。一个可编程的器件,一般要涉及到对它进行写指令操作,写/读数据操作。读/写 数据/指令 又是以字节为单位,而我们的总线上每次只能传递一个比特,所以要从bit的读写中扩展出字节的读写操作。

同样注意到我们在头文件中声明了大量的ROM操作指令。通过查阅数据手册可以知道,在单总线通信方式下,我们如果想对器件的内部存储器和向其写指令,都必须先进行对ROM的操作,主机必须先向DS18B20发出下面五种ROM指令之一:

(1)Read_ROM 

(2)Match_ROM

(3)Search_ROM

(4)Skip_ROM

(5)Alarm_Search

下面我们将逐一实现头文件里的函数定义。.

2.初始化和等待设备应答

这里要注意的是DS18B20单总线的所有操作都要以初始化为开始。就好比和DS18B20通信时,单片机必须首先发出握手信号,等到18B20发回应答后,才能进行通信。

下面是数据手册给出的时序关系图:

单片机首先发出一个持续时间为480us到960us的低电平,随后总线复位为高电平,DS18B20在接收到高点平后,等待15到60us后,发出一持续时间为60到240us的低电平,表明自己的存在,双方可以通信。根据这一时序特点,我们可以编写初始化和等待应答函数:

/*********************************
功能:初始化设备函数
参数:无
返回值:无
备注:调用Wait_ds18b20()来接收DS18B20的回应
*********************************/
void Init_ds18b20()
{	
	uint i=100;
	//总线拉低
	ds=0;
	//延时480us以上
	while(i)
	{
		i--;
	}
	//总线拉高,等待DS18B20应答
	ds=1;
}

/*********************************
功能:等待设备应答
参数:无
返回值:无
*********************************/
void Wait_ds18b20()
{
        //等待应答
	while(ds)    ;
	while(~ds)   ;
}

3.读写bit操作


先来看数据手册中的内容,数据手册当中给出了完整的读写一个bit的时序:
写时序:


在写bit的时候,总线首先需要拉低15us,然后置高或置低并持续45us,即写1或0,然后把总线拉高,实现一个写操作。同时注意在写下一个bit的时候,要与上一个至少相隔1us。

读时序:

在读bit的时候,总线首先由高变低并最少持续1us,DS18B20在总线拉低后15us后将数据放到总线上,所以控制器的必须停止拉低总线,并在其读周期刚开始拉低总线15us后完成采样,并在结束后将总线复位到高电平。整个读周期应该持续60us,两次读之间间隔至少1us。

下面是根据时序图写出的读写bit操作的函数write_bit和read_bit。

/*********************************
功能:写DS18B20的一位
参数:要写入的一位
返回值:无
*********************************/
void write_ds18b20_bit(bit dat)
{
	uint j=0;
	//总线拉低
	ds=0;
	j++;j++;
	//延时后把数据放到总线
	ds=dat;
	j=8;
	while(j>0)
	{
		j--;
	}
	//待18B20读取数据后把总线拉高
	ds=1;
	j++;
}

/*********************************
功能:读DS18B20的一位
参数:无
返回值:读取的一位数据
*********************************/
bit read_ds18b20_bit()
{
 uint i=1;
 bit res;
 ds=0;
    i++;
 //停止拉低总线,读取DQ引脚的值
 ds=1;
 //15us后读数据
 i++;
 i++;
 res=ds;
 //延时
 i=10;
 while(i)
 {
  i--;
 }
 return res;
}

4.读写btye

读写bit是读写byte的前提,而实现读写byte我们就能够向DS18B20内写入指令,读取存储器内容等。

这两个函数主要是设置了一个循环,做8个读写bit的操作就可以了,比较简单,直接把代码贴出来:

/*********************************
功能:写DS18B20的一字节
参数:要写入的一个字节
返回值:无
*********************************/
void write_ds18b20_byte(uchar dat)
{
	uint i=0;
	for(;i<8;i++)
	{
		//前面的宏定义有define BIT(n) (0x01<<n)
		//BIT(0)=0x01
		//即取dat的最后一位,来决定写1或者写0 
		if((dat>>i)&BIT(0))
			write_ds18b20_bit(1);
		else
			write_ds18b20_bit(0);
	}
}

/*********************************
功能:读DS18B20的一字节
参数:无
返回值:读取的一个字节
*********************************/
uchar read_ds18b20_byte()
{
	uchar res=0;
	uchar tem=0;
	uint i=0;
	for(;i<8;i++)
	{
		tem=read_ds18b20_bit();
		//第i次读进来的是第i位
		res |= (tem<<i);
	}
	return res;
}

下面这个函数实际也是写字节操作,只是我们上面提到过,对DS18B20的写指令都要以初始化和对它的ROM操作为先,所以我们单独把写指令这个功能拿出来封装成为一个独立的函数,方便调用。

/*********************************
功能:发布指令
参数:指令字节
返回值:无
*********************************/
void write_ds18b20_command(uchar com)
{
	bit flag=0;
	if(EA==1)
	{
		flag=1;
	}
	//先关中断,防止中断影响时序
	//宏定义define DisableInterrupt (EA=0)
	DisableInterrupt;
	//初始化DS18B20
	Init_ds18b20();
	//等待回应
	Wait_ds18b20();
	//跳过ROM
	write_ds18b20_byte(skip_ROM);
	//写指令字节
	write_ds18b20_byte(com);
	//开中断
	//宏定义define EnableInterrupt (EA=1)
	if(flag==1)
	{
	 	EnableInterrupt;
	}
}

5.获取温度值

/*********************************
功能:得到当前温度值
参数:无
返回值:当前温度值
*********************************/
int getTemp()
{
	uchar low,high;
	int value=0;
	float tmp=0.0;
	bit flag=0;
	//发布命令,启动转换
	write_ds18b20_command(start_ZH);
	if(EA==1)
	{
		flag=1;
	}
	DisableInterrupt;
	//读RAM获取温度
	write_ds18b20_command(read_RAM);
	low=read_ds18b20_byte();
	high=read_ds18b20_byte();
	//得到int
	value = (high<<8|low);
	//得到真实温度
	tmp=value*0.0625;
	//将真实的温度扩大100倍返回整形,即是取小数点后两位
	value=(int)(tmp*100);
	if(flag==1)
	{
		EnableInterrupt;	
	}
	return value;	
}


 

这样我们就得到了扩大100倍后的温度值。

于是只要在我们的其他程序里面调用getTemp就可以获得当前的温度值的100倍了,从而实现了对硬件设备的封装。

在以后的文章中我会把它放到一个具体的工程里面。实现特定的功能,通过调用getTemp函数来实现对DS18B20的访问,并把数据传回调用程序中。

在这里:http://bbs.21ic.com/icview-46868-1-1.html,有一篇很棒的文章,可以作为参考~~~

原文地址:https://www.cnblogs.com/xmfbit/p/3872196.html