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,有一篇很棒的文章,可以作为参考~~~

  • 相关阅读:
    【Azure 应用服务】在Azure App Service多实例的情况下,如何在应用中通过代码获取到实例名(Instance ID)呢?
    【Azure 应用服务】App Service For Windows 中如何设置代理实现前端静态文件和后端Java Spring Boot Jar包
    【Azure Developer】使用Azure Key Vault 的Key签名后,离线验证的一些参考资料
    【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
    【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(Xms512m Xmx1204m)?
    【Azure API 管理】APIM添加Logtoeventhub的策略后,一些相关APIM与Event Hub的问题
    【Azure API 管理】为调用APIM的请求启用Trace 调试APIM Policy的利器
    【Azure 事件中心】China Azure上是否有Kafka服务简答
    【Azure 应用服务】探索在Azure上设置禁止任何人访问App Service的默认域名(Default URL)
    【Azure 微服务】记一次错误的更新Service Fabric 证书而引发的集群崩溃而只能重建
  • 原文地址:https://www.cnblogs.com/xmfbit/p/3872196.html
Copyright © 2011-2022 走看看