zoukankan      html  css  js  c++  java
  • 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,有一篇很棒的文章,可以作为参考~~~

  • 相关阅读:
    PyTorch学习笔记7--案例3:基于CNN的CIFAR10数据集的图像分类
    [转载]使用 Pandoc 与 Markdown 生成 PDF 文件
    [转载]论文笔记:目标检测算法(R-CNN,Fast R-CNN,Faster R-CNN,FPN,YOLOv1-v3)
    [转载]论文笔记:CNN经典结构2(WideResNet,FractalNet,DenseNet,ResNeXt,DPN,SENet)
    [转载]论文笔记:CNN经典结构1(AlexNet,ZFNet,OverFeat,VGG,GoogleNet,ResNet)
    [转载]ImageNet历年冠军和相关CNN模型
    神经网络模型Tricks归纳
    Python生成windows可执行的exe文件
    如何让chrome浏览器自动打开Adobe Flash Player?
    PyTorch学习笔记6--案例2:PyTorch神经网络(MNIST CNN)
  • 原文地址:https://www.cnblogs.com/xmfbit/p/3872196.html
Copyright © 2011-2022 走看看