郭天祥51单片机的实时环境温度(AD/DA芯片的应用)


  如果学习51单片机,郭天祥的开发板是比较经典的一款,学习到最后可能会需要做一个综合应用的作业,我们的综合作业就是在单片机上实现实时监测环境温度,并且当温度改变时通过串口通信发送给串口调试助手,同时需要将温度通过I2C储存。
   程序有三个模式:
   第一个模式是单片机刚启动时,显示上次断电时的温度;
   第二个模式是显示实时温度,同时在温度变化时通过串口通信发送给串口调试助手,并且通过I2C储存。
   第三个模式是PC通过串口调试助手发送0-7来调节DA芯片控制的LED灯的亮度,亮度为8个等级,通过开发板上的8个LED灯来表示目前处于第几级亮度。
   模式的切换通过外部中断1来控制,可以将外部中断1口与P3.7通过杜邦线连接起来,这样就可以通过独立按键的最后一个来切换模式。
   实现的代码如下:

#include <reg52.h>
#define uchar unsigned char;
#define uint unsigned int;

//码字表部分

//段选码字表0~9
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//ASCII码字表
uchar code tableAscii[]={'0','1','2','3','4','5','6','7','8','9'};
//把电流分为八个大等级,形成码字表(32是一个大等级)
uchar code electricLevel[]={0x1f,0x3f,0x5f,0x7f,0x9f,0xbf,0xdf,0xff};
//LED灯指示等级
uchar code showLevel[]={0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00};
//位选码字表
uchar code tablewela[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//显示数组--AD
uchar ToDisplay[6]={0,0,0,0,0,0};

//位定义部分
sbit dula=P2^6;				//段选
sbit wela=P2^7;				//位选
sbit sda=P2^0;				//数据线
sbit scl=P2^1;				//时钟线
sbit csda=P3^2;				//DA片选
sbit wr=P3^6;				//DA写入
sbit DS18B20_IO=P2^2; 		//温度传感器io口

//全局变量定义部分
uchar buf;					//承接接收的数据
uchar current=0;			//用于数码管动态显示
uint temperture;			//温度
uchar last_temperture;		//记录上次温度
uchar ge,shi,bai;			//将显示的温度分为三位
uchar flag=0;				//运行模式
uchar number1,number2;		//帮助掉电重连


//函数申明部分
void initial();				//初始化
void Display();				//数码管显示
void whenGetValue();		//当收到串口调试助手数据时
void IIC_init();			//IIC初始化
void write();				//写入数据
void read();				//读取数据
void update();				//温度数据更新
void DS18B20_change();		//开始温度转换
void restart();				//掉电重连


//延时函数部分
void someNop(){					//微秒级延时
	;;;
}
void delay8ms(){				//8ms的延时
	unsigned int a,b;
	for(a=24;a>0;--a){
		Display();
		for(b=0;b<300;++b);	
	}
}
void delayXms(unsigned int x){	//延时Xms
	unsigned char a,b,c;
	for(a=x;a>0;a--)
		for(b=10;b>0;b--)
			for(c=100;c>0;c--);
}

//主函数部分
void main(){
	initial();
	read();
	restart();
	while(1){
		while(flag==0){
			delay8ms();
		}
		while(flag==1){
			Display();
			update();
		}
		wela=1;
		P0=0xff;
		wela=0;
		dula=1;
		P0=0;
		dula=0;
		while(flag==2);
	}
}




//掉电重连部分
void restart(){										//上电后将掉电前的值发送给电脑
	char i;
	for(i=0;i<10;i++){
		if(ToDisplay[0]==table[i]){
			number1=i;
			break;
		}
	}
	for(i=0;i<10;i++){
		if(ToDisplay[1]==table[i]){
			number2=i;
			break;
		}
	}
	SBUF=number1*16+number2;
	delay8ms();
	delay8ms();
	delay8ms();
	for(i=0;i<10;i++){
		if(ToDisplay[2]==table[i]){
			number1=i;
			break;
		}
	}
	SBUF=number1;
}



//DA转换部分
void Exchange(){									//将ASCII码转换成对应码字表位
	if(buf>=48&&buf<=57)		//'0'<buf<'9'
	{
		buf=buf-48;				//buf-'0'
	}
}
void DA_SignalControl_LED(unsigned char input_DA){  //进行DA转换
	csda=0;
	wr=0;
	P0=input_DA;
}
void initial(){										//初始化
	TMOD=0x20;				//设置定时器1为工作方式2
	TH1=0xfd;				//设置常量值	
	TL1=0xfd;				//设置初值
	TR1=1;					//打开定时器1
	SCON=0x50;				//选择方式1,REN置1
	EA=1;					//打开总中断
	ES=1;					//打开串口中断
	EX1=1;					//外部中断1				
	IT1=1;					//跳边沿触发
	IIC_init();				//IIC初始化
	DS18B20_change();		//开始温度转换
}


//串行口中断程序
void ser() interrupt 4{							//串口中断
	if(RI==1)
	{
		RI=0; 				//数据
		buf=SBUF;			//承接接收到的数据
		Exchange();			//将ASCII码转换成对应码字表位
		DA_SignalControl_LED(electricLevel[buf]);
		P1=showLevel[buf];
	
	}else if(TI==1){
		TI=0;
	}
}
void INT_1() interrupt 2{						//外部中断1
	flag++;
	if(flag==3){
		flag=1;
	}
	P1=~P1;
}


//DS18B20部分
unsigned char DS18B20_delay;					//用于温度传感器分脉冲延时
void DS18B20_reset(){							//DS18B20复位
	DS18B20_IO=1;
	someNop();
	DS18B20_IO=0;
	DS18B20_delay=108;
	while(DS18B20_delay>0)DS18B20_delay--;
	DS18B20_IO=1;
	DS18B20_delay=8;
	while(DS18B20_delay>0)DS18B20_delay--;
}
bit DS18B20_read_bit(){							//DB18B20读取一位
	bit B;
	DS18B20_IO=0;DS18B20_delay++;
	DS18B20_IO=1;
	DS18B20_delay++;
	DS18B20_delay++;
	B=DS18B20_IO;
	DS18B20_delay=8;
	while(DS18B20_delay>0)DS18B20_delay--;
	return B;
}
uchar DS18B20_read_byte(){						//DB18B20读取一个字节
	unsigned char i,j,byte_data;
	byte_data=0;
	for(i=0;i<8;i++){
		j=DS18B20_read_bit();
		byte_data=(j<<7)|(byte_data>>1);//把获得的字节逆序
	}
	return byte_data;
}
void DS18B20_write_byte(unsigned char byte_data){//DB18B20写入一个字节
	unsigned char i,j;
	bit tmp_bit;
	for(i=0;i<8;i++){
		tmp_bit=byte_data&0x01;
		byte_data=byte_data>>1;
		if(tmp_bit){
			DS18B20_IO=0;
			j++;j++;
			DS18B20_IO=1;
			DS18B20_delay=8;
			while(DS18B20_delay--);
		}else{
			DS18B20_IO=0;j++;j++;
			DS18B20_delay=8;
			while(DS18B20_delay--);
			DS18B20_IO=1;
			DS18B20_delay++;
			DS18B20_delay++;
		}
	}
}
void DS18B20_change(){							//开始温度转换
	DS18B20_reset();			//复位
	delayXms(1);
	DS18B20_write_byte(0xcc);	//跳过
	DS18B20_write_byte(0x44);	//开始温度转换
}
uint DS18B20_getTemperature(){					//获得温度
	unsigned char a,b;
	float real_temperture;
	DS18B20_reset();		//复位
	delayXms(1);
	DS18B20_write_byte(0xcc);//跳过ROM选择
	DS18B20_write_byte(0xbe);//获取温度
	a=DS18B20_read_byte();
	b=DS18B20_read_byte();
	temperture=b;			//获取高位
	temperture<<=8;
	temperture=temperture|a;//获取低位
	real_temperture=temperture*0.0625;//获取真实温度
	temperture=real_temperture*10+0.5;//四舍五入法保留一位小数
	return temperture;
}
void Display(){		 							//数码管显示
	wela=1;
	P0=tablewela[current];	//取位选值
	wela=0;
	P0=0x0;
	dula=1;
	P0=ToDisplay[current];	//取段选值
	dula=0;
	P0=0xff;
	current++;				
	if(current==3)
	{
		current=0;
	}
}
void update(){									//更新ToDisplay中的值
	 int tmp;
	 DS18B20_change();		//开始温度转换
	 Display();				//延时一下
	 tmp=DS18B20_getTemperature();
	 bai=tmp/100;
	 shi=tmp/10%10;
	 ge=tmp%10;
	 ToDisplay[0]=table[bai];
	 ToDisplay[1]=table[shi]+0x80;		
	 ToDisplay[2]=table[ge];
		if(tmp!=last_temperture){
			last_temperture=tmp;
			tmp=bai*16+shi;
			SBUF=tmp;
			write();
			SBUF=ge;
		}	

}



//IIC部分
void IIC_init(){							//IIC初始化
	sda=1;
	someNop();
	scl=1;
	someNop();
}
void start(){								//开始接收数据
	sda=1;
	someNop();
	scl=1;
	someNop();
	sda=0;
	someNop();
	scl=0;
	someNop();
}
void stop(){								//停止接收数据
	sda=0;
	someNop();
	scl=1;
	someNop();
	sda=1;
	someNop();
	scl=0;
	someNop();
}
void ack(){									//等待应答
	unsigned char i=0;
	IIC_init();
	while((sda==0)&&(i<250))
		i++;
	scl=0;
	someNop();
}
void write_byte(unsigned char _data){		//写入数据
	unsigned char tmp,i;
	tmp=_data;
	scl=0;
	someNop();
	
	for(i=0;i<8;++i){
		tmp=tmp<<1;
		sda=CY;
		someNop();
		scl=1;
		someNop();
		scl=0;
		someNop();
	}
}
uchar read_byte(){							//读取数据
	unsigned char i,j,k;
	scl=0;
	someNop();
	for(i=0;i<8;++i){
		scl=1;
		someNop();
		j=sda;
		someNop();
		k=(k<<1)|j;
		scl=0;
		someNop();
	}
	return k;
}
void write(){								//将数码管内容写入24C02
	unsigned char i;
	for(i=0;i<3;++i){
		start();
			write_byte(0xa0);
			ack();
			write_byte(i);
			ack();
			write_byte(ToDisplay[i]);
			ack();
			stop();
			delay8ms();
	}

}
void read(){								//从24C02中读出六位数据
		unsigned char i;
	for(i=0;i<3;++i){
		start();
			write_byte(0xa0);
			ack();
			write_byte(i);
			ack();
		start();
			write_byte(0xa1);
			ack();
			ToDisplay[i]=read_byte();
	stop();
	}

}


  由于时间问题,以上的代码有些细节未经过处理,如外部中断可能触发多次,这个问题可以通过延时来解决,可以延时200ms或者更多的时间,只要保证在这个时间段内使用者不会想要连续按两次即可。或者通过按键消抖加上松手检测也可以解决。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值