资讯详情

蓝桥杯单片机设计与开发⑩ --- DS18B20温度传感器

1、DS18B20

DS18B20本身就是温度传感器,只需要DS18B20数据引脚和单片机I/O单片机通过片机通过1-Wire协议与DS18B通信,读出温度。 相关模块电路图: 在这里插入图片描述

2.温度转换规则

DS18B20可以直接读取数字的温度值。温度传感器的精度为用户可编程的9、10、11或12位,分别为0.5℃,0.25℃,0.125℃和0.0625℃增量增加。默认上电精度为12位。也就是说温度每变化0.0625度,二进制数字变化1。转换精度由配置寄存器决定,如下:(R1R0出厂默认11) DS18B当需要进行温度测量和AD转换时,必须发出总线控制器[44h]命令,启动温度转换,即Write18b20(0x44)。转换后,以两个字节的形式存储产生的温度数据 高速暂存器 在温度寄存器中(先低后高),DS18b20继续等待。

DS18B20温度数据格式如下,转换后获得12位数据,存储在DS18B20的两个8位的RAM中。MSB高字节存储在里面LSB低字节存储在里面。 高字节的前五位是符号位。如果测量温度大于0,则为0,只要测量值乘以0.0625可获得实际温度;若温度小于0,则为1,测得的值需要先减1,然后乘以0.0625实际温度际温度。

3、ROM&RAM操作指令

(1)ROM指令集

指令 约定代码 功能
Read ROM 33H 读DS18B20温度传感器ROM编码,即64位地址
Match ROM 55H 后跟64位ROM让总线控制器在多点总线上匹配特定的序列DS18B20.匹配的从机器可以响应后续命令,其不匹配的从机可以等待复位脉冲。当总线上有单个或多个设备时,可以使用该命令。
Skip ROM CCH
Search ROM F0H 用于确定挂在同一总线上的用途DS18B64位ROM地址,准备操作各种设备。
Alarm ROM ECH 执行后,温度超过上限或下限的电影响应。

当我们只挂一个DS18B20点,只需要写一篇关于ROM的指令,即Write18b20(0xcc);。

(2) RAM指令集

指令 约定代码 功能
启动温度转换(Convert T) 44H 启动DS18B20进行温度转换,从转换到获取温度的时间取决于DS18B20的精度,12位转换最长750ms,结果存入9字节RAM。
读暂存器 BEH 读9字节RAM的内容
写暂存器 4EH
复制暂存器 48H 将RAM复制第三、四字节的内容EEPROM中
重调E2PROM B8H 将EEPROM内容恢复到RAM中的3、4字节
读供电方式 B4H 读DS18B20供电模式,寄生供电时DS18B20发送0DS18B20发送“1”。

4.通过单线总线端口访问DS18B20流程

类似于I2C的寻址,1-Wire在总线开始时,有必要检查这条总线是否存在DS18B20.如果存在,总线将按时间顺序返回低电平;如果没有,则不返回,即总线将保持高电平。该过程称为脉冲检测。 获取存在脉冲有两个作用:①检测是否存在DS18B20 ②通过此过程通知DS18B准备20,单片机要操作。

脉冲检测的时序图如下: 整个过程描述如下:

①单片机拉下引脚,持续480~960us (以持续500us为例) ②单片机释放总线,即提高电平。 ③15 ~60us后,如果DS18B当这个装置存在时,它会主动降低引脚,返回低脉冲(为了确保读到这个脉冲,选择延迟60us,但不能超过75us) ④持续60 ~240us后,DS18B20释放总线,I0端口被上拉电阻拉高。

对应程序如下:

void Delayus(uint us)  //@11.0592MHz { 
          do{ 
           _nop_();
		_nop_();
		_nop_();
	  }while(us--);
} 
bit Init_18b20()
{ 
        
	bit initflag;
	EA = 0;				//关闭总中断
	DQ = 0;				//读写之前都要将该引脚拉低
	Delayus(500);		//延时500us
	DQ = 1;
	Delayus(60);		//延时60us
	initflag = DQ; 		//读取存在脉冲,0存在,1不存在
	while(!DQ);			//等待存在脉冲结束,即DQ = 1
	EA = 1;				//打开总中断
	return initflag;	
}
	

注:需要说明的是,DS18B20对时序的要求非常严格,所以在开始对某一位操作前要先关闭中断,防止中途受到干扰。但是位与位之间的间隔是可以无穷大的,完全可以在完成一位的操作之后,去干别的事情,结束之后再回来操作下一位。

一条总线上只接一个器件的情况,此时只需要直接跳过ROM,不进行ROM检测。用到的语句如下:

Write18b20(0xcc);//跳过ROM操作

常用到的两条如下:

Write18b20(0x44);//启动一次温度转换
Write18b20(0xbe);//发送读指令

写数据 过程描述如下:在给DS18b20写数据之前,单片机要先把引脚拉低,持续一段时间(2us),而后DS18b20会在60us之内读完这位数据。然后释放总线(拉高引脚) 代码如下:

//向DS18B20写入一个字节,dat为带写入字节
void Write_18b20(u8 dat)
{ 
        
	u8 i;
	EA = 0;
	for(i=0;i<8;i++)
	{ 
        
		DQ = 0;
		Delayus(2);//产生2us的低电平脉冲
		DQ = dat & 0x01; //先读取低位
		Delayus(60);
		dat >>= 1; //右移一位,准备写入下一位
		DQ = 1;		
	}
	EA = 1;
}

读数据 过程描述如下:在读取DS18B20数据之前,单片机首先要拉低这个引脚,并且至少保持1us。而后释放这个引脚(拉高电平),尽快读取。从拉低这个引脚到读取不能超过15us。再延时60us,确保读取完毕。

//从DS18B20读取一个字节,返回值为读到的字节
u8 Read_18b20()
{ 
        
	u8 i,dat;
	EA = 0;
	for(i=0;i<8;i++)
	{ 
        
		DQ = 0;
		Delayus(2);
		DQ = 1;
		Delayus(2);
		dat >>= 1;
		if(DQ)
			dat |= 0x80;//先读的是低位,依次右移
		Delayus(60);
	}
	EA = 1;
	return dat;
}

实时测量室内温度并通过数码管显示完整程序:

#include "sys.h"
#include "18b20.h"
bit GET_TEMP_FLAG;
void main()
{ 
        
	int Temp = 0;				      		    //读取当前的温度值
	//int Temp_int = 999, Temp_dec = 999; //温度值的整数和小数部分

	ALL_Init();
	Timer0Init();
	while(1)
	{ 
        
		
		if(GET_TEMP_FLAG)
		{ 
        
			GET_TEMP_FLAG = 0;
			if(Start_18b20())
			{ 
        	//放大10倍 让数码管显示小数点后一位
				Temp = Temp_Get()*0.0625*10+0.5;	//+0.5 --> 4舍5入
			// Temp_int = Temp >> 4; //分离出温度值整数部分
			// Temp_dec = Temp & 0xF; //分离出温度值小数部分
			// Temp_dec = Temp_dec * (10000 / 16); //二进制小数部分转换为4位十进制 
			}
		}
		Nixie_Drive(Temp);		
	}
}

#include "sys.h"
#include "18b20.h"

extern uchar smg1;
void Delayus(uint us)		//@11.0592MHz
{ 
        
	do{ 
        
		_nop_();
		_nop_();
		_nop_();
	  }while(us--);
} 
bit Init_18b20()
{ 
        
	bit initflag;
	EA = 0;//关闭总中断
	DQ = 0;//读写之前都要将该引脚拉低
	Delayus(500);//延时500us
	DQ = 1;
	Delayus(60);//延时60us
	initflag = DQ; //读取存在脉冲,0存在,1不存在
	while(!DQ);//等待存在脉冲结束,即DQ = 1
	EA = 1;//打开总中断
	return initflag;	
}
		 
//向DS18B20写入一个字节,dat为带写入字节
void Write_18b20(u8 dat)
{ 
        
	u8 i;
	EA = 0;
	for(i=0;i<8;i++)
	{ 
        
		DQ = 0;
		Delayus(2);//产生2us的低电平脉冲
		DQ = dat & 0x01; //先读取低位
		Delayus(60);
		dat >>= 1; //右移一位,准备写入下一位
		DQ = 1;		
	}
	EA = 1;
}

//从DS18B20读取一个字节,返回值为读到的字节
u8 Read_18b20()
{ 
        
	u8 i,dat;
	EA = 0;
	for(i=0;i<8;i++)
	{ 
        
		DQ = 0;
		Delayus(2);
		DQ = 1;
		Delayus(2);
		dat >>= 1;
		if(DQ)
			dat |= 0x80;//先读的是低位,依次右移
		Delayus(60);
	}
	EA = 1;
	return dat;
}

bit Start_18b20()
{ 
        
	bit ack;
	ack = Init_18b20();//执行总线复位,获取18b20的应答
	if(ack == 0)//如果18b20应答,启动一次转换
	{ 
        
		Write_18b20(0xcc);//跳过RAM操作
		Write_18b20(0x44);//启动一次温度转换
	}
	return ~ack; //ack == 0 表示操作成功,返回值对其取反
	
}

int Temp_Get()
{ 
        
	bit ack;
	u8 LSB,MSB;
	u16 temp;
	ack = Init_18b20();//执行总线复位,获取18b20的应答
	if(ack == 0)
	{ 
        
		uchar check;
		Write_18b20(0xcc);
		Write_18b20(0xbe);
		LSB = Read_18b20();
		//MSB的3~7这5位为符号位,当5位都为0时为正温度 都为1时为负温度
		MSB = Read_18b20();
		
		//MSB = 0xfc; // -55℃ 负温度检验代码
		//LSB = 0x90;
		//检测正负温度
		check = MSB; 
		temp = ((int) MSB << 8) + LSB;	//合成16bit的整数
		//当check大于等于0x08时,说明采集到的数据为负温度值
		//负数是以补码的形式存在内存中,要求:原码 = 补码取反 + 1 
		if(check >= 0x08)
		{ 
        
			temp = ~temp + 1;
			smg1 = 1; //数码管1显示 - 符号
		}else
			smg1= 0;  //数码管1不显示任何
	}
	return temp;
}

#include "sys.h"


					// 0 1 2 3 4 5 6 7
uchar code nixie[] = { 
        0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
				    // 8 9 a b c d e f u
					  0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xc1};	//共阳数码管码字

uchar NixieBuff[] = { 
        0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

uchar smg1,smg2,smg3,smg4,smg5,smg6,smg7,smg8;
uchar code Symbol[] = { 
        0xff,0xbf};	//全灭,-


void Nixie_Scan()
{ 
        
	static uchar index;
	HC138_Set(7);
	P0 = 0xff;//消影
	HC138_Set(6);
	P0 = 0x01<<index;
	HC138_Set(7);
	P0 = NixieBuff[index];
	HC138_Set(0);
	
	index++;
	index &= 0x07;
}

void Nixie_Show()
{ 
        
	NixieBuff[0] = Symbol[smg1];
	NixieBuff[1] = nixie[smg2];
	NixieBuff[2] = nixie[smg3]&0x7f;
	NixieBuff[3] = nixie[smg4];
	NixieBuff[4] = nixie[smg5];
	NixieBuff[5] = Symbol[smg6];
	NixieBuff[6] = Symbol[smg7];
	NixieBuff[7] = Symbol[smg8];
	
}

void Nixie_Drive(u16 dat)
{ 
        
	smg2 = dat/100;
	smg3 = dat%100/10;
	smg4 = dat%10;
	smg5 = 12;
	smg6 = smg7 = smg8 = 0;
}

#include "sys.h"
extern bit GET_TEMP_FLAG;
/** *@brief 外设初始化 *@param[in] none *@return none **/
void ALL_Init()
{ 
        
	P2 = (P2&0x1f)|0xa0;	//打开Y5C
	P0 = 0x00;				//关闭蜂鸣器&继电器
	P2 = (P2&0x1f)|0xe0;	//打开Y7C
	P0 = 0xff;				//关闭数码管
	P2 = (P2&0x1f)|0x80;	//打开Y4C
	P0 = 0xff;				//关闭LED
	P2 = P2&0x1f;			//关闭所用使能
}
/** *@brief 延时函数 *@param[in] 延时多少ms(0~65535) *@return none **/
void Operate_Delay(u16 ms)
{ 
        
	u16 i;
	for(ms;ms>0;ms--)
		for(i=921;i>0;i--);
}
/** *@brief 74HC138译码器通道选择 *@param[in] channel (通道) *@return none **/
void HC138_Set(u8 channel)
{ 
        
	switch(channel)
	{ 
        
		case 0: P2 =  P2 & 0x1f;     break;     //关闭所有通道
		case 4: P2 = (P2&0x1f)|0x80; break;     //选择Y4对应的模块 (LED), 运算结果为P2高三位 100
		case 5: P2 = (P2&0x1f)|0xa0; break;     //选择Y5对应的模块 (蜂鸣器), 运算结果为P2高三位 101
		case 6: P2 = (P2&0x1f)|0xc0; break;     //选择Y6对应的模块 (数码管位选), 运算结果为P2高三位 110
		case 7: P2 = (P2&0x1f)|0xe0; break;     //选择Y7对应的模块 (数码管段选), 运算结果为P2高三位 111
	}
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{ 
        
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

void Timer0() interrupt 1
{ 
        
	static uint i;
	i++;
	if(i==1200)
	{ 
        
		i = 0;
		GET_TEMP_FLAG = 1;
	}
	Nixie_Show();
	Nixie_Scan();
}

标签: 体温枪用到的传感器f0温度传感器室内温度传感器t7412a

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台