51单片机-温度传感器DS18B20

哈尔滨理工大学软件工程专业08-7李万鹏原创作品,转载请标明出处

http://blog.csdn.net/woshixingaaa/archive/2010/09/27/5910469.aspx

温度传感器是各种传感器中最常用的一种,早期使用的是模拟温度传感器,如热敏电阻,随着环境温度的变化,它的阻值也发生线性变化,用处理器采集电阻两端的电压,然后根据某个公式就可以计算出当前环境温度。美国DALLAS半导体公司推出的数字化温度传感器DS18B20采用单总线协议,即与单片机接口仅需占用一个I/O端口,无需任何外部元件,直接将环境温度转化成数字信号,以数字码方式串行输出,从而大大简化了传感器与处理器的接口。

DS18B20的三种封装:

51单片机-温度传感器DS18B20_第1张图片

DS18B20的内部结构:

51单片机-温度传感器DS18B20_第2张图片

它采用单条信号线,既可传输时钟,又可传输数据,而且数据传输是双向的。如果要控制多个DS18B20进行温度采集,只要将所有的DS18B20的I/O口全部连接到一起就可以了。在具体操作时,通过读取每个DS18B20内部芯片的序列号来识别。64位光刻ROM中的序列号是出场前被光刻好的,他可以看做该DS18B20的地址序列码。

DS18B20的复位时序:

51单片机-温度传感器DS18B20_第3张图片

DS18B20复位,确定其存在:

#include <reg52.h>
#define uint unsigned int
uint i;
sbit DQ = P3^3;
sbit bell = P3^4;

void reset(){
	DQ = 1;		//开始的时候是高脉冲
	DQ=0;		      //然后是低脉冲
	i=103;
  	while(i>0)i--;	//低脉冲需要延迟一会儿
  	DQ=1;			//数据线拉高,系统将总线放开,并进入接受状态
  	i=4;
  	while(i>0)i--;	//延时等待,若初始化成功则在15~60ms内产生一个由
	if(DQ == 0){	//DS18B20在检测到总线的上升沿后,等待15~60ms,接着
		while(DQ == 0); //在T2时刻发出存在脉冲(低电平)
		bell = 0;
	}
	else
		bell = 1;	
}

void main(){
	reset();
	while(1);
}


DS18B20的写0和写1时序:

51单片机-温度传感器DS18B20_第4张图片

DS18B20的读数据时序:

51单片机-温度传感器DS18B20_第5张图片

读出光刻ROM中的ID号,在LCD上显示:

#include <reg52.h>
#include<intrins.h>
sbit DQ = P3^3;
sbit RS = P1^0;
sbit RW = P1^1;
sbit E = P1^2;
sbit bell = P3^4;

#define uchar unsigned char
#define uint unsigned int 
#define	nop() _nop_()

uint i;
uchar value;
uchar DS[8];
uchar Time_Data[]={'0','1','2','3','4','5','6','7',
				   '8','9','A','B','C','D','E','F'};

void delay(uchar t){ 
   while(--t);
} 

void lcd_com(uchar s){ 
    RS = 0; 		   //低电平,写指令
    P2 = s; 		   //传数据
    delay(14); 	       //看时序图,数据需要稳定一段时间 
    E = 1; 			   //给一个高脉冲,发送命令
    delay(14); 		   //如图,高脉冲延时一段时间,确保命令发送
    E = 0; 			   //发送结束E置为低电平
} 

void lcd_data(uchar s){ 
    RS = 1; 
    P2 = s; 
    delay(14); 
    E = 1; 
    delay(14); 
    E = 0; 
} 

void init_lcd(){ 
    RS = 1;         //先发指令,在初始时刻RS是高,E和RW是低 
    E = 0; 
    RW = 0; 
    lcd_com(0x38); 	  //设置为16*2显示,5*7点阵,8位数据接口
    lcd_com(0x0f); 	  //开显示,显示光标,光标闪烁
    lcd_com(0x06); 	  //读写一个字符后地址指针加一
    lcd_com(0x01); 
} 

void Display_lcd(uchar y, uchar x, uchar value){
	if(y)
		lcd_com(0x80+0x40+x);   //如果y为1,写在第二行
	else
		lcd_com(0x80+x);
	lcd_data(value);			//写到LCD602上
}
	 
void DS18B20_reset(){
	DQ = 1;		//开始的时候是高脉冲
	DQ=0;		//然后是低脉冲
	i=103;
  	while(i>0)i--;	//低脉冲需要延迟一会儿
  	DQ=1;			//数据线拉高
  	i=4;
  	while(i>0)i--;	//延时等待,若初始化成功则在15~60ms内产生一个由
	if(DQ == 0){	//DS18B20返回的低电平
		while(DQ == 0);
	//	bell = 0;
	}
	else
		bell = 1;	
}

uchar DS18B20_read(void)
{
	uchar i = 0;
	uchar Value = 0;
	for(i = 0; i < 8; i ++)
		{
			DQ = 1;          
			DQ = 0;
			delay(1);   
			DQ = 1;      //在T1时刻将总线拉高,产生读时间隙
			delay(1);    //读时隙在T1和T2之间有效
			if(DQ)
				{
					Value |= 0x01 << i;
				}
			delay(17);   //必须在T3时刻之间主机完成读操作
			DQ = 1;
			nop();
		}
	return Value;
} 
	
void DS18B20_write(uchar Value){
	for(i = 0; i < 8; i++){
		DQ = 1;              
		DQ = 0;              //当t0从高拉低产生写时隙,
		delay(5);        
		DQ = Value & 0x01;   //必须在t0开始的15us内将数据送到总线上
		delay(20);           //DS18B20在t0后的15us~60us内对总线采样
		DQ = 1;              //如果采到低电平则写入0,高电平写入1
		Value >>= 1;
		delay(2);
	}	
}
  
void DS18B20_ID_read(){
	DS18B20_reset();
	DS18B20_write(0x33);
	for(i = 0; i < 8; i++)
		DS[i] = DS18B20_read();
} 

void main(){
	 init_lcd();
	 while(1){
	 	DS18B20_ID_read();
	 	Display_lcd(0,0,'>');
		Display_lcd(0,1,':');
		Display_lcd(0,2,Time_Data[DS[0]/16]);
		Display_lcd(0,3,Time_Data[DS[0]%16]);
		Display_lcd(0,4,'>');
		Display_lcd(0,5,':');
		Display_lcd(0,6,Time_Data[DS[1]/16]);
		Display_lcd(0,7,Time_Data[DS[1]%16]);
		Display_lcd(0,8,'>');
		Display_lcd(0,9,':');
		Display_lcd(0,10,Time_Data[DS[2]/16]);
		Display_lcd(0,11,Time_Data[DS[2]%16]);
		Display_lcd(0,12,'>');
		Display_lcd(0,13,':');
		Display_lcd(0,14,Time_Data[DS[3]/16]);
		Display_lcd(0,15,Time_Data[DS[3]%16]);
		Display_lcd(1,0,'>');
		Display_lcd(1,1,':');
		Display_lcd(1,2,Time_Data[DS[4]/16]);
		Display_lcd(1,3,Time_Data[DS[4]%16]);
		Display_lcd(1,4,'>');
		Display_lcd(1,5,':');
		Display_lcd(1,6,Time_Data[DS[5]/16]);
		Display_lcd(1,7,Time_Data[DS[5]%16]);
		Display_lcd(1,8,'>');
		Display_lcd(1,9,':');
		Display_lcd(1,10,Time_Data[DS[6]/16]);
		Display_lcd(1,11,Time_Data[DS[6]%16]);
		Display_lcd(1,12,'>');
		Display_lcd(1,13,':');
		Display_lcd(1,14,Time_Data[DS[7]/16]);
		Display_lcd(1,15,Time_Data[DS[7]%16]);
	 }
}

单只DS18B20工作流程:
51单片机-温度传感器DS18B20_第6张图片 
2只DS18B20并联工作流程:
51单片机-温度传感器DS18B20_第7张图片 
DS18B20温度存储格式:
51单片机-温度传感器DS18B20_第8张图片 
DS18B20暂存器的分布:
51单片机-温度传感器DS18B20_第9张图片 
DS18B20内部ROM指令:
51单片机-温度传感器DS18B20_第10张图片
DS18B20内部RAM指令:
51单片机-温度传感器DS18B20_第11张图片  
读出当前温度,在LCD上显示,温度超过一定时,报警。
#include <reg52.h>
#include<intrins.h>
sbit DQ = P3^3;
sbit RS = P1^0;
sbit RW = P1^1;
sbit E = P1^2;
sbit bell = P3^4;

#define uchar unsigned char
#define uint unsigned int 
#define	nop() _nop_()

uint i;
uchar value;
uchar DS[8];
uchar Time_Data[]={'0','1','2','3','4','5','6','7',
				   '8','9','A','B','C','D','E','F'};

void delay(uchar t){ 
   while(--t);
} 

void Lcd_Com(uchar s){ 
    RS = 0; 		   //低电平,写指令
    P2 = s; 		   //传数据
    delay(14); 	       //看时序图,数据需要稳定一段时间 
    E = 1; 			   //给一个高脉冲,发送命令
    delay(14); 		   //如图,高脉冲延时一段时间,确保命令发送
    E = 0; 			   //发送结束E置为低电平
} 

void Lcd_Data(uchar s){ 
    RS = 1; 
    P2 = s; 
    delay(14); 
    E = 1; 
    delay(14); 
    E = 0; 
} 

void Init_Lcd(){ 
    RS = 1;         //先发指令,在初始时刻RS是高,E和RW是低 
    E = 0; 
    RW = 0; 
    Lcd_Com(0x38); 	  //设置为16*2显示,5*7点阵,8位数据接口
    Lcd_Com(0x0f); 	  //开显示,显示光标,光标闪烁
    Lcd_Com(0x06); 	  //读写一个字符后地址指针加一
    Lcd_Com(0x01); 
} 

void Display_Lcd(uchar y, uchar x, uchar value){
	if(y)
		Lcd_Com(0x80+0x40+x);   //如果y为1,写在第二行
	else
		Lcd_Com(0x80+x);
	Lcd_Data(value);			//写到LCD602上
}
	 
void DS18B20_Reset(){
	DQ = 1;		//开始的时候是高脉冲
	DQ=0;		//然后是低脉冲
	i=103;
  	while(i>0)i--;	//低脉冲需要延迟一会儿
  	DQ=1;			//数据线拉高
  	i=4;
  	while(i>0)i--;	//延时等待,若初始化成功则在15~60ms内产生一个由
	if(DQ == 0){	//DS18B20返回的低电平
		while(DQ == 0);
	//	bell = 0;
	}
	else
		bell = 1;	
}

uchar DS18B20_Read(void)
{
	uchar i = 0;
	uchar Value = 0;
	for(i = 0; i < 8; i ++)
		{
			DQ = 1;
			DQ = 0;
			delay(1);
			DQ = 1;
			delay(1);
			if(DQ)
				{
					Value |= 0x01 << i;
				}
			delay(17);
			DQ = 1;
			nop();
		}
	return Value;
} 
	
void DS18B20_Write(uchar Value){
	for(i = 0; i < 8; i++){
		DQ = 1;
		DQ = 0;
		delay(5);
		DQ = Value & 0x01;
		delay(20);
		DQ = 1;
		Value >>= 1;
		delay(2);
	}	
}
  
uchar DS18B20_Temp_Read(){
	uchar temp_h,temp_l,temp;
	DS18B20_Reset();			//复位
	DS18B20_Write(0x0cc);		//跳过ROM,只有一个所以跳过
	DS18B20_Write(0x44);		//开始温度转换
	DS18B20_Reset();			//复位
	DS18B20_Write(0x0cc);		//跳过ROM
	DS18B20_Write(0x0be);		//读暂存器
	temp_l = DS18B20_Read();	//读出温度低8位
	temp_h = DS18B20_Read();	//读出温度高8位
	temp_l >>= 4;				//去掉4位小数位
	temp_h <<= 4;				//去掉4位符号位
	temp = temp_h | temp_l;		
	temp = temp & 0x7f;			//最高位是符号位
	return temp;	
}

void main(){
	 uchar temp;
	 Init_Lcd();
	 while(1){
	 	temp = DS18B20_Temp_Read();
		if(temp > 25)				 //如果温度大于25报警
			bell = 0;
		else
			bell = 1;
		Display_Lcd(0,0,'T');
		Display_Lcd(0,1,'E');
		Display_Lcd(0,2,'M');
		Display_Lcd(0,3,'P');
		Display_Lcd(0,4,':');
		Display_Lcd(0,5,Time_Data[temp/100]);
		Display_Lcd(0,6,Time_Data[temp%100/10]);
		Display_Lcd(0,7,Time_Data[temp%10]);
	 }
}

你可能感兴趣的:(数据结构,工作,Blog,F#)