STC51入门笔记(郭天祥C语言)---第十节:(一)使用 DS18B20 温度传感器设计温控系统

项目实现功能: 使用51开发板上的DS18B20温度传感器设计温控系统,要求如下:


       用串口将采集到的温度数据实时发送至上位机,在上位机软件上显示当前温度值(关于上位机软件的编写请参考下篇VB 内容)。
       关于温度变化的实现,大家可参考以下方法: 室温通常在 28°C左右,用手捏住温度传感器可使其温度上升,用温度低的物体接触温度传感器可使其温度降低,或在温度传感器上淋点水,然后对着温度传感器吹气可以使温度迅速下降,大家也可想其他办法使温度传感器周围温度在 25°C~32°C 变化。
 

一、温度传感器概述:

       温度传感器是各种传感器中最常用的一种,早期使用的是模拟温度传感器,如热敏电阻,随着环境温度的变化,它的阻值也发生线性变化,用处理器采集电阻两端的电压,然后根据某个公式就可计算出当前环境温度。随着科技的进步,现代的温度传感器已经走向数字化, 外形小,接口简单,广泛应用在生产实践的各个领域,为我们的生活提供便利。随着现代仪器的发展,微型化、集成化、数字化正成为传感器发展的一个重要方向。美国DALLAS半导体公司推出的数字化温度传感器DS18B20采用单总线协议,即与单片机接口仅需占用一个I/O端口,无须任何外部元件,直接将环境温度转化成数字信号,以数字码方式串行输出,从而 大大简化了传感器与微处理器的接口。

二、DS18B20 温度传感器介绍:

      DS18B20是美国DALLAS半导体公司推出的第一片支持“一线总线”接口的温度传感器,它具有微型化、低功耗、高性能、抗干扰能力强、易配微处理器等优点,可直接将温度转化成串行数字信号供处理器处理。

1、D818B20温度传感器特性:
① 适应电压范围宽,电压范围在3.0~5.5V,在寄生电源方式下可由数据线供电。
② 独特的单线接口方式,它与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通信。
③ 支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现组网多点测温。
④ 在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内。
⑤ 测温范围-55°C~+I25°C,在-10°C~+85°C时精度为的0.5°C。
⑥ 可编程分辨率为9~12位,对应的可分辨温度分别为0.5°C,0.25°C,0.125°C和0.0625°C,    可实现高精度测温。
⑦ 在9位分辨率时,最多在93.75ms内把温度转换为数字;12位分辨率时,最多在750ms内把温度值转换为数字,显然速度更快。
⑧ 测量结果直接输出数字温度信号,以“一线总线”串行传送给CPU,同时可传送CRC校验码,具有极强的抗干扰纠错能力。
⑨ 负压特性。电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。
2、应用范围:
① 冷冻库、粮仓、储罐、电信机房、电力机房、电缆线槽等测温和控制领域。
② 轴瓦、缸体、纺机、空调等狭小空间工业设备测温和控制。
③ 汽车空调、冰箱、冷柜以及中低温干燥箱等。
④ 供热、制冷管道热量计量、中央空调分户热能计量等。
3、引脚介绍:

DS18B20有两种封装:三脚T0-92直插式(用的最多、最普遍的封装)和八脚SOIC贴片式。

4、硬件连接:
       我们首先来了解“单总线”的概念。目前常用的单片机与外设之间进行数据传输的串行总线主要有I2C,SPI和SCI总线。其中l2C总线以同步串行二线方式进行通信(一条时钟线,—条数据线),SPI总线则以同步串行三线方式进行通信(一条时钟线,一条数据输入线,一条数据输出线),而SCI总线是以异步方式进行通信(一条数据输入线,一条数据输出线)。这些总线至少需要两条或两条以上的信号线,而DS18B20使用的单总线技术与上述总线不同,它采用单条信号线,既可传输时钟,又可传输数据,而且数据传输是双向的,因而这种单总线技术具有线路简单,硬件开销少,成本低廉,便于总线扩展和维护等优点。单总线适用于单主机系统,能够控制一个或多个从机设备。
       主机可以是微控制器,从机可以是单总线器件,它们之间的数据交换只通过一条信号线。当只有一个从机设备时,系统可按单节点系统操作;当有多个从机设备时,系统则按多节点系统操作。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其他设备使用总线。单总线通常要求外接一个约为5kQ的上拉电阻。芯片手册上的典型连接如下图所示。

       DS18B20和单片机的连接非常简单,单片机只需要一个I/O口就可以控制DS18B20。这个图的接法是单片机与一个DS18B20通信,如果要控制多个DS18B20进行温度采集,只要将所有DS18B20的I/O口全部连接到一起就可以了。在具体操作时,通过读取每个DS18B20内部芯片的序列号来识别。本章我们仅操作一个DS18B20进行温度采集。掌握了本章的知识,就能很容易扩展,设计出多点温度采集系统。
5、工作原理:
      硬件电路连接好以后,单片机需要怎样工作才能将DS18B20中的温度数据读取出来呢?下面将给出详细分析。
首先我们来看控制DS18B20的指令:
① 33H—读ROM。读DS18B20温度传感器ROM中的编码(即64位地址)。
② 55H—匹配ROM。发出此命令之后,接着发出64位ROM编码,访问单总线上与该编码相对应的DS18B20并使之做出响应,为下一步对该DS18B20的读/写做准备。
③ FOH—搜索ROM。用于确定挂接在同一总线上DS18B20的个数,识别64位ROM地址,为操作各器件做好准备。
④ CCH—跳过ROM。忽略64位ROM地址,直接向18B20发温度变换命令,适用于一个从机工作。
⑤ ECH—告警搜索命令。执行后只有温度超过设定值上限或下限的芯片才做出响应。以上这些指令涉及的存储器是64位光刻ROM,    下表列出了它的各位定义。

       64位光刻ROM中的序列号是出厂前被光刻好的,它可以看做该DS18B20的地址序列码。其各位排列顺序是:开始8位为产品类型标号,接下来48位是该DS18B20自身的序列号,最后8位是前面56位的CRC循环冗余校验码(CRC=X8+X5+X4+1)。光刻ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一条总线上挂接多个DS18B20的目的。
       下面介绍以上儿条指令的用法。当主机需要对众多在线DS18B20中的某一个进行操作时,首先应将主机逐个与DS18B20挂接,读出其序列号;然后再将所有的DS18B20挂接到总线上,单片机发出匹配ROM命令(55H),紧接着主机提供的64位序列(包括该DS18B20的48位序列号)之后的操作就是针对该DS18B20的。
       如果主机只对一个DS18B20进行操作,就不需要读取ROM编码以及匹配ROM编码了,只要用跳过ROM (CCH)命令,就可进行如下温度转换和读取操作。
① 44H—温度转换。启动DS18B20进行温度转换,12位转换时最长为750ms(9位为93.75ms)。结果存入内部9字节的RAM中。
② BEH—读暂存器。读内部RAM中9字节的温度数据。
③ 4EH—写暂存器。发出向内部RAM的第2,    3字节写上、下限温度数据命令,紧跟该命令之后,是传送两字节的数据。
④ 48H—复制暂存器。将RAM中第2,    3字节的内容复制到E2PROM中。
⑤88H—重调E2PROM。将E2PROM中内容恢复到RAM中的第3、4字节。
⑥84H—读供电方式。读DS18B20的供电模式。寄生供电时,DS18B20发送0;外接电源供电时,DS18B20发送1。
以上这些指令涉及的存储器为高速暂存器RAM和可电擦除E2PROM,    见下表。

        高速暂存器RAM由9个字节的存储器组成。第0~1个字节是温度的显示位;第2和第3个字节是复制的TH和TL,同时第2和第3个字节的数字可以更新;第4个字节是配置寄存器,同时第4个字节的数字可以更新;第5,6,7三个字节是保留的。可电擦除E2PROM又包括温度触发器TH和TL,以及一个配置寄存器。这些大家了解就可以了。
       下表列出了温度数据在高速暂存器RAM的第0和第1个字节中的存储格式。

       DS18B20 在出厂时默认配置为12位,其中最高位为符号位,即温度值共11位,单片机在读取数据时,一次会读2字节共16位,读完后将低11位的二进制数转化为十进制数后再乘以0.0625便为所测的实际温度值。另外,还需要判断温度的正负。前5个数字为符号位,这5位同时变化,我们只需要判断11位就可以了。前5位为1时,读取的温度为负值,且测到的数值需要取反加1再乘以0.0625才可得到实际温度值。前5位为0时,读取的温度为正值,且温度为正值时,只要将测得的数值乘以0.0625即可得到实际温度值。
6、工作时序图:
下图为时序图中各总线状态。

(1)初始化时序图见下图)

① 先将数据线置高电平1。
② 延时(该时间要求不是很严格,但是要尽可能短一点)。
③ 数据线拉到低电平0。
④ 延时750µs(该时间范围可以在480~960µs)。
⑤ 数据线拉到高电平1。
⑥ 延时等待。如果初始化成功则在15~60ms内产生一个由DS18B20返回的低电平0,据该状态可以确定它的存在。但是应注意,不能无限地等待,不然会使程序进入死循环,所以要进行超时判断。
⑦ 若CPU读到数据线上的低电平0后,还要进行延时,其延时的时间从发出高电平算起(第@步的时间算起)最少要480µs。
雹)将数据线再次拉到高电平1后结束。


(2) DS18B20写数据(时序图见下图)

① 数据线先置低电平 0。
② 延时确定的时间为 15µs。
③ 按从低位到高位的顺序发送数据(一次只发送一位)。
④ 延时时间为 45µs。
⑤ 将数据线拉到高电平 1 。
⑥ 重复①~⑤步骤,直到发送完整个字节。
⑦ 最后将数据线拉高到 1。

(3) DS18B20 读数据(时序图见下图)

① 将数据线拉高到1。
② 延时2µs。
③ 将数据线拉低到0。
④ 延时6µs。
⑤ 将数据线拉高到1。
⑥ 延时4µs。
⑦ 读数据线的状态得到一个状态位,并进行数据处理。
⑧ 延时30µs。
⑨ 重复①~⑦步骤,直到读取完一个字节。

 

#include <reg52.h>		//编译器自带的库用 < >	 编译器包含C52的定义
#include "DS18B20_Sum.h"
#include "delay_Sum.h"


#define uchar unsigned char
#define uint  unsigned int

sbit DS18B20=P2^2;   //温度传感器信号线

uint temp;
float f_temp;
long int temperature=0;
DS18B20初始化
/*
① 先将数据线置高电平 1。
② 延时(该时间要求不是很严格,但是要尽可能短一点)。
③ 数据线拉到低电平 0。
④ 延时750μs(该时间范围可以在480~960μs) 。
⑤ 数据线拉到高电平 l 。
⑥ 延时等待。如果初始化成功则在15~60ms内产生一个由DS18B20返回的低电平0, 据该状态可以确定它的存在。
   但是应注意,不能无限地等待,不然会使程序进入死循环,所以要进行超时判断。
⑦ 若 CPU 读到数据线上的低电平 0 后,还要进行延时, 其延时的时间从发出高电平算起(第⑤步的时间算起)最少要 480μs。
⑧ 将数据线再次拉到高电平 l 后结束。
*/
uchar reset_ds18b20()
{
   uchar presence;
   DS18B20=0;
   delay_ds18b20(29);     //延时480 - 960  us
   DS18B20=1;						  
   delay_ds18b20(3);      //延时 15 - 60   us
   presence=DS18B20;
   delay_ds18b20(25);	  //延时 60 - 240  us
   return(presence);
}
DS18B20读取一字节数据
/*
① 将数据线拉高到 1。
② 延时2μs。
③ 将数据线拉低到 0。
④ 延时6μs。
⑤ 将数据线拉高到 1。
⑥ 延时4μs。
⑦ 读数据线的状态得到一个状态位,并进行数据处理。
⑧ 延时30μs。 
⑨ 重复①~⑦步骤,直到读取完一个字节。
*/
 uchar read_bit_ds18b20()
{
	uchar i;
	DS18B20=1;
	delay_ds18b20(1);
	DS18B20=0;
	//delay(1);    //延时 15us  也可以不延时
	DS18B20=1;
	//delay(3);	 //延时 1 - 45  us
	for(i=0;i<3;i++);
	return(DS18B20);
}
DS18B20写一字节数据
/*
① 数据线先置低电平 0。
② 延时确定的时间为 15μs。
③ 按从低位到高位的顺序发送数据(一次只发送一位)。
④ 延时时间为 45μs。
⑤ 将数据线拉到高电平 l 。
⑥ 重复①~⑤步骤,直到发送完整个字节。
⑦ 最后将数据线拉高到 1。
*/ 
void write_bit_ds18b20(uchar dat)
{
	DS18B20=0;        //置0 无需延时
	if(dat==1)
	  DS18B20=1;
	delay_ds18b20(1);	 //延时 60 - 120  us
	DS18B20=1;
	delay_ds18b20(1);	 //延时 1 - ∞  us
}

DS18B20写数据
void write_byte_ds18b20(uchar dat)
{
     uchar i,j;
	 for(i=0;i<8;i++)
	 {
	     j=((dat>>i)&0x01);
		 write_bit_ds18b20(j);
		 //delay(1);      //延时 1 - ∞  us
	 }
}  

DS18B20读数据
uchar read_byte_ds18b20()
{
	uchar dat=0;
	uchar i;
	for(i=0;i<8;i++)
	 {
	   if(read_bit_ds18b20())
	     dat|=0x01<<i;
	   //delay(1);	   //延时 1 - ∞  us
	 
	 }
	 return(dat); 	  
}


 
int read_temp_ds18b20()
{
   uchar templ=0,temph=0;
   int temp=0;
   reset_ds18b20();//复位
   write_byte_ds18b20(0xcc); //跳过ROM
   write_byte_ds18b20(0x44); //跳过温度采集
   delay_ds18b20(10);     //750ms
   reset_ds18b20();
   write_byte_ds18b20(0xcc); //跳过ROM
   write_byte_ds18b20(0xbe); //准备好数据(开始温度转换采集)
   templ=read_byte_ds18b20();//读低字节温度值
   temph=read_byte_ds18b20();//读低字节温度值
   temp=(templ+(temph*256));
   return(temp);
}

float read_temp_ten_ds18b20()
{
   float tt;
   uchar templ=0,temph=0;
   int temp=0;
   reset_ds18b20();//复位
   write_byte_ds18b20(0xcc); //跳过ROM
   write_byte_ds18b20(0x44); //跳过温度采集
   delay_ds18b20(10);     //750ms
   reset_ds18b20();
   write_byte_ds18b20(0xcc); //跳过ROM
   write_byte_ds18b20(0xbe); //准备好数据(开始温度转换采集)
   templ=read_byte_ds18b20();//读低字节温度值
   temph=read_byte_ds18b20();//读低字节温度值
   temp=temph;
   temp<<=8;             //two byte  compose a int variable
   temp=temp|templ;
   tt=temp*0.0625;
   temp=tt*10+0.5;

   return(temp);
}

uchar DS18B20_get(void)
{
  temperature = read_temp_ds18b20(); //读ds18b20 温度值,赋给 temperature
  if((temperature&0xf800)>0)		 //判断温度数据 是否是负温度
	 ;//Disp_1602(7,1,"-",1);  		  //在1602上显示一个 ” - “ 负温度标志
  else  ;//Disp_1602(7,1,"+",1);  	 //否则在1602上显示一个 ” + “ 负温度标志  
  temperature=read_temp_ds18b20();	   //读ds18b20 温度值,赋给 temperature
  delay(1);
  //write_oneline_DS18b20_1602(8,(temperature&0x07ff)*0.625); //把读出的温度 转换成实际温度 ,并显示在1602上
  return((temperature&0x07ff)*0.625); //十六进制
  //十进制   temperature=temperature*(0.0625*10);
  }
#include <reg52.h>		//编译器自带的库用 < >	 编译器包含C52的定义
#include <stdio.h>
#include "DS18B20_Sum.h"
#include "delay_Sum.h"
#include "printf_sum.h"

#define uchar unsigned char
#define uint  unsigned int
 float temperature2=0;

void InitUART(uint choose)//使用定时器1作为串口波特率发生器
{
    TH1 = 0xFD;	     //晶振11.0592mhz 波特率设为9600
    TL1 = TH1;
    TMOD |= 0x20;	 //定时器1方式2
    SCON = 0x50;	 //串口接收使能
    ES = 1;			 //串口中断使能
    TR1 = 1;		 //定时器1使能
    TI = 1;			 //发送中断标记位,必须设置

    EA = choose;	 //开总中断

}	
void main()
{   
	InitUART(0);

	while(1)																	 
	{

	temperature2= read_temp_ten_ds18b20();	 
	printf("%.1f",temperature2/10);
	delay(200);
	
	}
}

 

 

  • 9
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值