DS18B20温度传感器测试环境温度及代码详解

醒醒!,还在睡呢,开始干代码了!

1.简介:

单片机通过OneWire协议与DS18B20通信,最终测出环境温度

OneWire 总线的硬件接口很简单,只需要把 DS18B20 的数据引脚和单片机的一个 IO 口接上

2.DS18B20引脚及说明

 

 

 说明:GND接地,DQ单引线用于数据的输入,VDD接电源正极(注意正负极不能接反)

3.储存形式

通过编程,将二进制的数字来表示温度

 可以看出最高五位为符号位,若全为0则温度为正值,全为1则为负值

最后四位为小数位,最高可以精确到2的-4次方,可以知道每次变化最小变化值位0.0625

 例如+25.0625°C是

 1*2的-4次方+1*2的0次方+1*2的三次方+1*2的4次方

由于高五位都是0 所以最终结果是+25.0625°C;

二.各个模块的原理

2.1.初始化

在初始化阶段,总线控制器先拉低总线至少480微秒(这里可以拉低500微秒),然后释放总线

进入接收状态,等待 15-60us,然后发出一个由 60-240us低电平信号构成的存在脉冲。

unsigned char OneWire_Init()
{
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i = 247;while (--i);		//Delay 500us
	OneWire_DQ=1;
	i = 32;while (--i);			//Delay 70us
	AckBit=OneWire_DQ;
	i = 247;while (--i);		//Delay 500us
	return AckBit;
}

先拉低,延时500微秒等待,再拉高,延时70微秒等待,然后把应答位取出来,再延时500微秒返回应答位,0位应答,1为非应答

这里延时多少可以去用软件来生成代码

2.2.写时序

有两种写时序:写 1 时序和写 0 时序,总线控制器通过写 1 时序写逻辑 1 到DS18B20,写 0 时序写逻辑 0 到 DS18B20,所有写时序必须最少持续 60us

1.发送一位

void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ=0;
	i = 4;while (--i);			//Delay 10us
	OneWire_DQ=Bit;
	i = 24;while (--i);			//Delay 50us
	OneWire_DQ=1;
}

 先把总线拉低,延迟10微秒,将bit赋值给DQ(把要发送的数据即bit放在总线上,发0即保持低电平,发1即变成高电平),然后延时50us,最后释放总线;

这里十分巧妙,给的数据是0的话就是0,不拉高总线,是1的话会拉高,延时50us后看变化如果是低电平说明发送的是0,高电平发送1,最后把总线拉高,这里10+50刚好等于60 满足最小的60us

                             2.发送一个字节(一字节也就是八位)

将上述情况重复八次就好

void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}

从低到高依次将Byte的每一位取出来。(一般取数据用&,将某个数据置1用 | )

2.3.读时序

总线控制器发起读时序时,DS18B20 仅被用来传输数据给控制器。因此,总线控制器在发出读暂存器指令[BEh]或读电源模式指令[B4H]后必须立刻开始读时序。

2.3.1接收(读)一位:

主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末尾,这样成功的概率高) 读取为低电平则为

接收0,读取为高电平则为接收1,整个时间片应大于60us

 

unsigned char OneWire_ReceiveBit()
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i = 2;while (--i);			//Delay 5us
	OneWire_DQ=1;
	i = 2;while (--i);			//Delay 5us
	Bit=OneWire_DQ;
	i = 24;while (--i);			//Delay 50us
	return Bit;
}

先拉低总线5us,再释放总线5us(此时控制权交给从机),现在时序到了10us,如果读取的数据是0,那么从机就强制拉低总线,如果读取到的数据是1,那就维持高电平,再延时50us满足时序需求.

2.3.2接收(读)一个字节:

和发送一个字节一样

将接收一位重复八次

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

这里定义一个Byte返回值初值为0x00,然后用Byte按位或0x01(从低位到高位)就可以得到Byte了.

上述的发送一位,一个字节;接收一位,一个字节,可以封装到一个文件中,起名为OneWire

下面是OneWire.c

#include <REGX52.H>


sbit OneWire_DQ=P3^7;


unsigned char OneWire_Init()
{
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i = 247;while (--i);		//Delay 500us
	OneWire_DQ=1;
	i = 32;while (--i);			//Delay 70us
	AckBit=OneWire_DQ;
	i = 247;while (--i);		//Delay 500us
	return AckBit;
}


void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ=0;
	i = 4;while (--i);			//Delay 10us
	OneWire_DQ=Bit;
	i = 24;while (--i);			//Delay 50us
	OneWire_DQ=1;
}


unsigned char OneWire_ReceiveBit()
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i = 2;while (--i);			//Delay 5us
	OneWire_DQ=1;
	i = 2;while (--i);			//Delay 5us
	Bit=OneWire_DQ;
	i = 24;while (--i);			//Delay 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()
{
	unsigned char i;
	unsigned char Byte=0x00;
	for(i=0;i<8;i++)
	{
		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
	}
	return Byte;
}

下面是OneWire.h

#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__
unsigned char OneWire_Init();
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit();
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte();


#endif

接下来是DS18B20的

ConverT():发送指令,跳过ROM,温度变换

然后是读取温度,在读取函数里面发送完两条指令后,控制权交给从机

这里数据处理比较难理解

剖析:TLSB为第八位,TMSB为高八位

Temp=(TMSB<<8)|TLSB;//将高八位左移八位,把数据整合成16位的;

最后还要把Temp/16

为什么要除以16呢?

这里还是看上面存储形式的那张图片,最低四位为小数位,但是我们整合出来的Temp最低四位是整数位,那么我们只需将Temp右移动4位即可,在二进制里面向右移动一位相当于 /2,那么向右移四位就是 /16了。

#include <REGX52.H>
#include "OneWire.h"


#define DS18B20_SKIP_ROM			0xCC
#define DS18B20_CONVERT_T			0x44
#define DS18B20_READ_SCRATCHPAD 	0xBE
void DS18B20_ConvertT()
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}


float DS18B20_ReadT()
{
	unsigned char TLSB,TMSB;
	int Temp;
	float 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;
}
#ifndef __DS18B02_H__
#define __DS18B02_H__

void DS18B20_ConvertT();
float DS18B20_ReadT();


#endif

最后是主函数测试,这里要用到LCD1602显示屏

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B02.h"
#include "Delay.h"

float 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);
	}
}

逻辑全在代码里面了,容易体会,要注意最后

         LCD_ShowNum(2,2,T,3);        
        LCD_ShowChar(2,5,'.');        
        LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//这里

温度要想显示出四位小数无误,要将float强转为long类型的,但是又不能直接转

所以我们先将整数部分取出显示出来,然后将T*10000%10000就可以取出小数部分了

这里就是DS18B20的基本内容了,还可以实现报警等等功能,在此基础上稍作修改即可,

精心摸鱼(hhh)

 

物联沃分享整理
物联沃-IOTWORD物联网 » DS18B20温度传感器测试环境温度及代码详解

发表评论