单总线温度采集

资料

链接:https://pan.baidu.com/s/1z-9P_q-K4msXoJ9s_1sZlA?pwd=65bp
提取码:65bp

详情见第24章。

一、DS18B20 介绍

1.简介

DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线)”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。
DS18B20 温度传感器具有如下特点:
1、适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电。
2、独特的单线接口方式,DS18B20 在与微处理器连接时仅需要一条口线即可实现微处理器与 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、负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。
DS18B20 实物图如下图所示:
在这里插入图片描述

2.DS18B20引脚排列及说明

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
从 DS18B20 引脚图可以看到,当我们正对传感器切面(传感器型号字符那
一面)时,传感器的管脚顺序是从左到右排列。管脚 1 为 GND,管脚 2 为数据DQ(Data Queue,传输数据的总线),管脚 3 为 VDD。如果把传感器插反,那么电源将短路,传感器就会发烫,
很容易损坏,所以一定要注意传感器方向,通常我们在开发板上都会标出传感器
的凸起出,所以只需要把传感器凸起的方向对着开发板凸起方向插入即可。
使用的时候只需要把 DS18B20 的数据引脚和单片机的一个 IO 口接上就可以了。

二、DS18B20的时序

1.单片机外部设备与总线的关系

在这里插入图片描述
单总线结构:CPU内部采用的是“一条总线”贯穿整个芯片的结构,所有的外部设备都挂在这条总线上,数据在总线上传输,CPU通过访问总线上的数据就可以访问到所有的外部设备了。在总线上传递的数据通常是以高低电平的形式呈现的。
本节讨论的DS18B20作为外部设备也不例外。
形象一点说:总线就像是一条大马路,外部设备就像马路两旁的商户。

2.时序

(1)定义

单片机时序是指单片机执行指令时应发出的控制信号的时间序列。这些控制信号在时间上的相互关系就是CPU的时序。它是一系列具有时间顺序的脉冲信号。
我的理解:时序就是程序控制单片机及其外部设备运行的节奏。运行的时候节奏不能出错,否则外部设备就达不到我们控制的效果。

(2)分类

DS18B20 时序包括如下几种:初始化时序、写(0和1)时序、 读(0和1)时序。 DS18B20 发送所有的命令和数据都是字节的低位在前。

3.初始化时序

在这里插入图片描述

理论上是开始拉高就等待、延时,江协科技认为的是彻底拉高电位到1。可以把电平弹高的时间(几乎为0)忽略不计。我也这样认为算了,这样代码后面好设计一点。

关键的是:主机检测的时候一定要在从机掌握总线并拉低电平之后,否则主机检测到高电平,时序就会出错。

(1)老大(单片机)发出信号唤醒小弟(外部设备:DS18B20)

刚开始总线是高电平。主机(单片机)首先发出一个480~960us的低电平脉冲(复位),然后再拉高电平。发出这个低电平的目的就是告诉DS18B20,把他叫醒,跟他说:“做好准备,我要跟你通信了。”
然后延时15~60us,才进入检测状态。

(2)小弟回应老大

作为从机的DS18B20上电后,就一直检测总线上是否有480到960us的低电平出现。当DS18B20接收到信号后,发出60~240us的低电平回应单片机,即拉低总线 60到240 us。告诉他:“我已经做好准备了。”因为拉的是低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要480us。(这个应该是规定)

注意:主机为什么要等待(延时)15~60us才开始检测总线电平的变化呢?
因为延时15~60微秒是为了给予DS18B20足够的准备时间,以便它能够正确地检测到总线的释放(由低电平转为高电平),并做出响应(拉低总线产生应答脉冲),从而保证单总线通信的正确初始化。如果你立刻去检测,他可能还没发出低电平响应,或者发出的低电平响应不完整。
特别要注意的是:理论上主机是可以一直在检测主线上的数据,但是实际上他并不会那么做,主要是考虑到资源占用和效率,而是当有必要的时候才去检测。这里就是他已经预知了DS18B20最快的应答,他赶在应答之前一点点去检测即可。

(3)小节

至此,初始化时序完成。
从主机的角度看初始化过程:主机将总线拉成低电平至少保持480us后释放总线,延时15~60us后检测60到240us时间内检测总线是否为低电平(检测某个点是否为低电平就OK了,不必检测完),再延时240us保持时序的完整。
说人话:初始化就是老大叫小弟做好工作准备,并收到小弟回复的过程。

4.写(0和1)时序(主机发送数据给从机)

在这里插入图片描述

(1)时间限制

写时序(周期)最少为60us,最长不超过120us。

(2)步骤

①写0

写时序的开始,主机先把总线拉低至少1us,表示写时序开始。随后若主机想写0,则继续拉低至少60us直至写时序结束,然后释放总线为高电平。

②写1

若主机想写1,在拉低总线1us后就释放总线为高电平,一直到写时序结束。

作为从机的DS18B20在检测到总线被拉低1后,等待15us,从15到45us对总线采样。(采样的典型时间在采样开始第15us),在采样时间内,若检测到总线为高电平则认为主机发送了1;若检测到总线为低电平则认为主机发送了0。

5.读(0和1)时序(从机发送数据给主机)

在这里插入图片描述

(1)时间限制

同样地,读时序(周期)最少为60us,最长不超过120us。

(2)步骤

①读0

读时序的开始,主机先把总线拉低至少1us,然后释放总线,表示读时序的开始。主机释放总线后,若DS18B20发送0,即主线上送过来的数据是0,则仍保持把总线拉低,并持续至少从都周期开始的15us,然后释放总线弹回高电平。

②读1

若DS18B20发送1,即从机从主线上送过来的数据是1,则在主机释放总线后,总线迅速被拉至高电平。
无论读0或者读1,主机都须在15us内检测总线电平的高低。若检测到总线电平为低,则表示DS18B20发过来的是0;若检测到总线电平为高,则表示DS18B20发过来的是1。

6.读写时序小节

(1)无论是读还是写,都是以主机把总线拉低至少1us开始。
(2)无论是写0还是读0,都是以总线释放至少1us结束。对于写0 尤其需要注意(此时主机控制总线,设计到写代码),对于读0过程由DS18B20负责拉高(其实结束前早已拉高)。

7.归纳DS18B20的测温步骤

在这里插入图片描述
在这里插入图片描述

8.DS18B20的使用注意事项

在这里插入图片描述

三、实验

1.实验目标

(1)参考课件“【例10-1】利用DS18B20和LED数码管实现单总线温度测量系统”和普中实验板说明书第24章“24.3 软件设计:使用DS18B20温度传感器、数码管显示检测的温度值”的项目案例,分别在Proteus和普中开发板实物上完成 DS18B20 的环境温度采集。
(2)将上述实验成功的代码在Keil中进行仿真运行,使用虚拟逻辑分析仪显示单片机与DS18B20的DQ数据线连接引脚的波形,分析其“初始化–>写—>读”总线时序,与原理进行对比分析: 1)判断其是否符合技术要求;2)故意在代码中把时序弄错(改延时delay的延时值),再重新运行之前的实验,看DS18B20是否能正确相应并返回温度。

2.课件参考

(1)代码

#include "reg51.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int 
#define out P0
sbit smg1=out^4;
sbit smg2=out^5;
sbit DQ=P3^7;
void delay5(uchar);
void init_ds18b20(void);
uchar readbyte(void);
void writebyte(uchar);
uchar retemp(void);
 
void main(void)
{
uchar i,temp;
delay5(1000);
while(1)
	{
	 temp=retemp();	
	 for(i=0;i<10;i++)	
	 {
	 out=(temp/10)&0x0f;
	 smg1=0;
	 smg2=1;
	 delay5(1000);	
	 out=(temp%10)&0x0f;
	 smg1=1;
	 smg2=0;
	 delay5(1000);	
	 }
	}
 
}
 
 
void delay5(uchar n)
{
	 do
	 {
	 _nop_();
	 _nop_();
	 _nop_();
	 n--;
	 }
	 while(n);
}
 
void init_ds18b20(void)
{
	 uchar x=0; 
	 DQ =0;    
	 delay5(120); 
	 DQ =1;    
	 delay5(16);
	 delay5(80);
}
 
uchar readbyte(void)
{
	uchar i=0;
	uchar date=0;
	for (i=8;i>0;i--)
	 {
		  DQ =0;
		  delay5(1);
		  DQ =1;	
		  date>>=1;
		  if(DQ)
		  date|=0x80;
		  delay5(11);
	 }
 	return(date);
}
 
void writebyte(uchar dat)
{
 uchar i=0;
 for(i=8;i>0;i--)
	 {
	  DQ =0;
	  DQ =dat&0x01;
	  delay5(12);	  
	  DQ = 1;	   
	  dat>>=1;
	  delay5(5);
	  }
}
 
uchar retemp(void)
{
	uchar a,b,tt;
	uint t;
	init_ds18b20();
	writebyte(0xCC); 
	writebyte(0x44);
	init_ds18b20();
	writebyte(0xCC); 
	writebyte(0xBE); 
	a=readbyte();
	b=readbyte();
	t=b;
	t<<=8;
	t=t|a;
	tt=t*0.0625;
	return(tt);
}

(2)Proteus仿真

在这里插入图片描述

3.自己写

(1)代码

//main.c文件
#include <REGX52.H>
#include "LCD1602.h"
#include "OneWire.h"
#include "DS18B20.h"
#include "Delay.h"

float T;   //全局变量T

void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	LCD_Init();
	LCD_ShowString(1,1,"Temperature:");

	
	while(1)
	{
		DS18B20_ConvertT();
		T=DS18B20_ReadT();
		if(T<0)
		{
			LCD_ShowChar(2,1,'-');
			T=-T;
		}
		else
		{
			LCD_ShowChar(2,1,'+');
		}
		
		
		LCD_ShowNum(2,2,T,3);
		LCD_ShowChar(2,5,'.');
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);
	
		}
	
}
//DS18B20.c文件
#include <REGX52.H>
#include "OneWire.h"
#include "DS18B20.h"


#define DS18B20_SKIP_ROM    		0xCC
#define DS18B20_CONVERT_T			0x44
#define DS18B20_READ_SCRATCHPAD		0xBE

void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);

}

float DS18B20_ReadT(void)
{
	unsigned char TLSB,TMSB;  //分别是温度的第一个字节和第二个字节
	int Temp;
	float T;                  //局部变量T
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0;
	return T;
	
	
}
//OneWire.c文件
#include <REGX52.H>
#include "DS18B20.h"
#include "OneWire.h"

sbit OneWire_DQ=P3^7;

unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;//Acknowledgement Bit的缩写,确认位,主机用来接收总线的返回值(电平值)
	OneWire_DQ=1;  //开始总线是高电位
	OneWire_DQ=0;  //将总线电位拉低
	i=247;while(--i); //最低延时480us,我们设计延时500us
	OneWire_DQ=1;   //释放总线再次将它拉高
	i = 32;while (--i); //给他延时70us,这段时间是给DS18B20做出反应的时间
	AckBit=OneWire_DQ;  //此时恰好读取低电平
	i=247;while(--i); //再延时500us,确保将剩下的480us走完,实际上已经走了70us了
	return AckBit;
	  
}

void OneWire_SendBit(unsigned char Bit)  //写时序的函数,Bit为0或1
{
	unsigned char i;
	OneWire_DQ=0;
	i=4;while(--i);//延时10us
	OneWire_DQ=Bit; //给总线赋值
	i=24;while(--i);//延时50us
	OneWire_DQ=1;//释放总线弹回高电平
}

unsigned char OneWire_ReceiveBit(void)   //读时序的函数
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i=2;while(--i);        //延时5us
	OneWire_DQ=1;           
	i=2;while(--i);        //延时5us
	Bit=OneWire_DQ;        //采样总线电平
	i=24;while(--i);       //延时50us
	//我们不需要写代码释放总线,我们写的代码只控制总机,在总机接受信号的时候,从机后面控制总线,它后面会自己释放
	return Bit;
}

void OneWire_SendByte(unsigned char Byte)  //总线发送字节,从低位到高位
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}


unsigned char OneWire_ReceiveByte(void)
{
	unsigned char i;
	unsigned char Byte=0x00;
	
	for(i=0;i<8;i++)
	{
		if (OneWire_ReceiveBit())
		{
			Byte|=(0x01<<i);
		}
	}
	return Byte;
}

(2)实验现象

Week8_01

(3)波形分型

在这里插入图片描述
两者是一样的,因为我sbit OneWir_DQ=P3.7。

波形按照代码的设计起伏,符合要求。

(4)改变时序再查看结果

在这里插入图片描述
我直接在初始化时序的时候,把里面的延时部分,全部去掉。可以预料到,这下主机就会出问题,因为它检测太快了DS18B20根本没反应过来,他就开始检测了。所以后续的一切都会出问题。

波形如下:(和之前的比较,很明显没有长时间下拉电平做提示了)
在这里插入图片描述
现象如下:直接在重庆的夏日测出负温度,显然是错误的。
在这里插入图片描述

四、总结

这次学写了DS18B20温度传感器的用法,了解了时序有关的概念。我体会到在单片机学习中,特别是在代码设计过程中,对时序的考虑是一个非常重要的内容。往往有时候你的代码看起来合情合理,但是因为没有考虑到函数调用所花费的时间、外部设备反应所需要的时间等…会最终导致实验的结果与预期相差甚远。由于了解得比较浅,我在接下来的学习中还要好好把握时序的。

五、参考资料

1.https://www.bilibili.com/video/BV1Mb411e7re/?p=29&spm_id_from=333.880.my_history.page.click
2.https://blog.csdn.net/2201_75518371?type=blog

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值