51单片机的仿真实验——数码管显示万年历与温度

学习目标:

(1)学习AT89C51内部定时/计数器的原理及应用
(2)了解使用单片机处理复杂逻辑的方法
(3)掌握多位数码管动态显示的方法
(4)掌握DS18B20数字温度传感器的工作原理及使用方法
(5)掌握对DS18B20转换数据进行处理的方法
(6)学习用数码管显示复杂数据的方法

学习内容:

用AT89C51单片机的定时/计数器T0产生一秒的定时时间,作为秒计数时间,当一秒产生时,秒计数加1。开机时显示00-00-00的时间,开始计时:P1.0控制“秒“的调整,每按一次加1秒;P1.1控制“分“的调整,每按一次加1分;P1.2控制”时“的调整,没按一次加1小时。计时满23-59-59时,返回00-00-00重新计时。P1.3用做复位键,在计时过程中如果按下复位键,则返回00-00-00重新计时。
用AT89C51控制DS18B20,读取数据,并对DS18B20转换后的数据进行处理,最后在数码管上显示DS18B20测出的温度。要求使用6位数码管显示,最高位为符号位,如果温度值为正,不显示,如果温度为负,则显示负号;第2—4位显示温度值的整数部分,并在第4位数据上显示小数点;第5位显示一位小数,最低位显示摄氏度符号“C”。

实验要求:

a.用AT89C51单片机的定时/计数器T0产生一秒的定时时间,作为秒计数时间。
b.当一秒产生时,秒计数加1。
c.开机时,显示00-00-00,并开始连续计时。计时满23-59-59时,返回00-00-00重新开始计时。
d.用AT89C51控制DS18B20,读取数据
e.对DS18B20转换后的数据进行处理,转换成实际温度值
f. 将符号位,整数值和小数值分别存放在特定的存储单元中.

高级要求:

在以上设计基础上,在单片机的P1.0-P1.3口分别接入4个按键:
a.P1.0控制“秒”的调整,每按一次加1秒
b.P1.1控制“分”的调整,每按一次加1分
c.P1.2控制“时”的调整,每按一次加1时
d.P1.3用作复位键,在计时过程中如果按下复位键,则返回00-00-00重新计数。
e.使用6位数码管显示测得的温度
f.最高位为符号位,如果温度值为正,不显示,如果温度为负,则显示负号
g.第2—4位显示温度值的整数部分,并在第4位数据上显示小数点
h.第5位显示一位小数
i.最低位显示摄氏度符号“C”

学习产出:

项目工程及仿真资料(链接:https://pan.baidu.com/s/1ILLeTeofJFg4dU7A5gznVw 提取码:1234 )

原理图设计

本实验主要有单片机、七个按键、一个8位数码管、一个6位数码管以及温度传感器组成,实现电路如下:
51单片机的仿真实验——数码管显示万年历与温度_第1张图片

代码编写过程

a.各个变量与引脚的定义 本实验将温度传感器的输出口DQ输入到单片机的P1_4处。

#include
#define uchar unsigned char
#define uint unsigned int
unsigned char tab[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x39};
uchar code led_7seg[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};
uint hour=23,minute=59,second=580,month=12,day=31;
uint n=0,i=0;
uint count=0,year=2000,a,b;
sbit P2_0=P2^0;
sbit P2_1=P2^1;
sbit P2_2=P2^2;
sbit P2_3=P2^3;
sbit P2_4=P2^4;
sbit P2_5=P2^5;
sbit P2_6=P2^6;
sbit P2_7=P2^7;
//sbit DQ =P2^4 ;
sbit DQ =P1^4 ;
uint flag=0;

b.延迟函数定义

void delay(unsigned int j)
{
	while(j--);
} 

c.温度传感器的初始化 每隔一定时间对DQ口进行电平的拉高拉低。

void Init_DS18B20(void)
{
	unsigned char x=0;
	DQ = 1; 
	delay(8); 
	DQ = 0; 
	delay(80); 
	DQ = 1; 
	delay(14);
	x=DQ;
	delay(20);
}	  	

d.传感器数据按字读取

ReadOneChar(void)
{
	unsigned char i = 0;
	unsigned char dat = 0;
	for (i=8;i>0;i--)
	{
		DQ = 0; 		     
		dat>>=1;
		DQ = 1; 			   
		if(DQ)
			dat|=0x80;
		delay(4);
	}
	return(dat);
}	

e.传感器数据按字节写入dat中

void WriteOneChar(unsigned char dat)
{
	unsigned char i=0;
	for (i=8; i>0; i--)
	{
		DQ = 0;
		DQ = dat&0x01;
		delay(5);
		DQ = 1;
		dat>>=1;
	}
	delay(4);
}	  

f.将读取到的数据处理成可读的温度数据

ReadTemperature(void)
{
	unsigned char a=0;
	unsigned char b=0;
	unsigned int t=0;
	Init_DS18B20();
	WriteOneChar(0xCC);		  														     
	WriteOneChar(0x44); 
	Init_DS18B20();
	WriteOneChar(0xCC);
	WriteOneChar(0xBE); 
	a=ReadOneChar(); 
	b=ReadOneChar();   
	t=b<<8; 
	t=t|a;
	return(t);
}

g.将温度信息显示到6位数码管上

void display_tempmain(unsigned int i) 
{
	float temp ;
	unsigned char xiaoshu;
	unsigned int zhengshu;
	if((0xf000&i)==0xf000)
	{
  		i=~i+1;	
  		P0=0x00;
  		P0=tab[10];
 		P3=0xfe;
  		delay(1000);
	}
 	temp = (0x000f & i) * 10.0 * 0.0625;
 	xiaoshu = temp;
 	zhengshu= i>>4;
 	P0=0x00;
 	P0=tab[zhengshu/100];
 	P3=0xfd;
 	delay(500);
 	P0=0x00;
 	P0=tab[zhengshu%100/10];
 	P3=0xfb;
 	delay(500);
 	P0=0x00;
 	P0=tab[zhengshu%100%10] | ~0x7f;
 	P3=0xf7;
 	delay(1000);
 	P0=0x00;
 	P0=tab[xiaoshu];
 	P3=0xef;
 	delay(1000);
 	P0=0x00;
 	P0=tab[11];
 	P3=0xdf;
 	delay(1000);
 	P3=0xff;  
}

h.对时钟进行初始化

void init_timer0(void)
{
	TMOD=0x01;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	ET0=1;
	TR0=1;
	EA=1;
}

i.当时间为23:59:59时可对其进行清零处理

void qinglin()
{
	for(i=0;i<100;i++);
		P2=0;
}

j.将时间数据显示在8位数码管上记为display1(void)

void display1(void)
{
//		  P3=led_7seg[year/1000];
		  P0=led_7seg[hour/10]; 
		  P2_0=1;
		  qinglin();
//		  P3=led_7seg[year/100%10];
		  P0=led_7seg[hour%10];
		  P2_1=1;
		  qinglin();
//		  P3=led_7seg[year/10%10];
		  P0=0xBF;
		  P2_2=1;
		  qinglin();
//		  P3=led_7seg[year%10];
		  P0=led_7seg[minute/10];
		  P2_3=1;
		  qinglin();
//		  P3=led_7seg[month/10];
		  P0=led_7seg[minute%10];
		  P2_4=1;
		  qinglin();
//		  P3=led_7seg[month%10];
		  P0=0xBF;
		  P2_5=1;
		  qinglin();
//		  P3=led_7seg[day/10];
		  P0=led_7seg[second/165];
		  P2_6=1;
		  qinglin();
//		  P3=led_7seg[day%10];
		  P0=led_7seg[second*10/165%10];
		  P2_7=1;
		  qinglin();
}

k.将日历数据显示在8为数码管上记为display2(void)

void display2(void)
{
		  P0=led_7seg[year/1000];
//		  P0=led_7seg[hour/10];
		  P2_0=1;
		  qinglin();
		  P0=led_7seg[year/100%10];
//		  P0=led_7seg[hour%10];
		  P2_1=1;
		  qinglin();
		  P0=led_7seg[year/10%10];
//		  P0=0xBF;
		  P2_2=1;
		  qinglin();
		  P0=led_7seg[year%10];
//		  P0=led_7seg[minute/10];
		  P2_3=1;
		  qinglin();
		  P0=led_7seg[month/10];
//		  P0=led_7seg[minute%10];
		  P2_4=1;
		  qinglin();
		  P0=led_7seg[month%10];
//		  P0=0xBF;
		  P2_5=1;
		  qinglin();
		  P0=led_7seg[day/10];
//		  P0=led_7seg[second/165];
		  P2_6=1;
		  qinglin();
		  P0=led_7seg[day%10];
//		  P0=led_7seg[second*10/165%10];
		  P2_7=1;
		  qinglin();
}

l.闰年情况的判断

void runnian(void)
{
	if((year%4==0)&&(year%100!=0)||(year%400==0))
	{
		if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
		{b=32;}
		if((month==4)||(month==6)||(month==9)||(month==11))
		{b=31;}
		if(month==2)
		{b=30;}
	}
	else{
		if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
		{b=32;}
		if((month==4)||(month==6)||(month==9)||(month==11))
		{b=31;}
		if(month==2)
		{b=29;}
	}
}

m.1秒延迟定义,方便后续函数的编写

void dl_10ms(void)
{
	int i;
	for(i=1000;i>0;i--);
}

n.按键的初始化

uchar kbscan(void)
{
	uchar sccode,recode;
	P1=0xF0;
	if((P1&0xF0)!=0xF0)
	{
		dl_10ms();
		if((P1&0xF0)!=0xF0)
		{
			sccode=0xFE;
			while((sccode&0x10)!=0)
			{
				P1=sccode;
				if((P1&0xF0)!=0xF0)
				{
					recode=(P1&0xF0)|0x0F;
					return((~sccode)+(~recode));
				}
				else
				{
					sccode=(sccode<<1)|0x01;
				}
			}
		}
	}
	return 0;
}			 

o.主函数编写 引用上述提到的所有函数 实现按键控制时间 日历与温度的交替出现,并且可以对时间进行相应的调试

void main (void)
{
	unsigned int temp;
	uchar key;
	init_timer0();
	qinglin();
	while(1)
	{
	//	temp=ReadTemperature();
 	//	display_tempmain(temp);
		if(flag==0)
		{
		    display1();
		}
		else if(flag==1)
		{
			display2();
		}
		else if(flag==2)
		{
			temp=ReadTemperature();
 			display_tempmain(temp);

		}
		key=kbscan();
		switch(key)
		{
			case 0x11:
			{	
				flag=0;
				if(hour<23)hour++;
				else 
				{
				    
					hour=0;
					day++;
				}
				while(key==0x11)
				{
					key=kbscan();
				}
			}
				break;
			case 0x21:
			{
				flag=0;
				if(minute<59) minute++;
				else 
				{	
					minute=0;
					hour++;
				}
				while(key==0x21)
				{
					key=kbscan();
				}
			}
				break;
			case 0x41:
			{
				flag=1;
				runnian();
				if(day<(b-1)) day++;
				else 
				{
					day=1;
					month++;
					if(month==13) 
						month=1;
				}
				while(key==0x41)
				{
					key=kbscan();
				}
			}
				break;
			case 0x81:
			{
				flag=1;
				if(month<=11) month++;
				else 
				{
					month=1;
					year++;
				}
				while(key==0x81)
				{
					key=kbscan();
				}
			}
			break;
			case 0x12:
			{	
				flag=1;
				year++;
				while(key==0x12)
				{
					key=kbscan();
				}
			}
			break;
			case 0x22:
			{	
				flag=1;
				year--;
				while(key==0x22)
				{
					key=kbscan();
				}
			}
			break;
		/*	case 0x42:
			{	
				flag=0;
				while(key==0x42)
				{
					key=kbscan();
				}
			}
			break;
			case 0x82:
			{	
				flag=1;
				while(key==0x82)
				{
					key=kbscan();
				}
			}
			break; */
			case 0x42:
			{	
				if(flag==0)
					flag=1;
					else if(flag==1)
						flag=2;
						else if(flag==2)
							flag=0;
				while(key==0x42)
				{
					key=kbscan();
				}
			}
			break;
/*			case 0x82:
			{	
				if(flag==0||flag==1)
				flag=2;
				else flag=0;
				while(key==0x82)
				{
					key=kbscan();
				}
			}
			break;	  */
		default:break;
		}	
	}
}	  

p.中断函数 时间的进位

void timer0_int(void) interrupt 1 
{
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	second++; 
	dl_10ms();
/*	for(n=0;n<20;n++){
		switch(n & 0x07)
		{
		case 0:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[hour%10];
				P3=led_7seg[year/100%10];P2=0x02;}break;
		case 1:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[hour/10];
				P3=led_7seg[year/1000];P2=0x01;}break;
		case 2:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[10];
				P3=led_7seg[year/100%10];P2=0x04;}break;
		case 3:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[minute%10];
				P3=led_7seg[month/10];P2=0x10;}break;
		case 4:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[minute/10];
				P3=led_7seg[year%10];P2=0x08;}break;
		case 5:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[10];
				P3=led_7seg[month%10];P2=0x20;}break;
		case 6:{P0=0xFF; P2=0x00; P3=0xFF;
				P0=led_7seg[second%10];
				P3=led_7seg[day%10];P2=0x80;}break;
		case 7:{P0=0xFF; P2=0x00;
				P0=led_7seg[second/10];
				P3=led_7seg[day/10];P2=0x40;}break;
		default:break;
		}	
	}	 */
/*	if(count==10)
	{
		count=0;
		second++;				 */
		if(second==990)
		{
			second=0;
			minute++;
			if(minute==60)
			{
				minute=0;
				hour++;
				if(hour==24)
				{
					hour=0;
					day++;
					runnian();
					if(day==b)
					{
						day=1;
						month++;
						if(month==13)
						{
							month=1;
							year++;
						}
					}
				}
			}
		//}
	}
}

将上述代码直接复制到工程的主函数内,通过编译出来.OBJ文件。调用到仿真器里的单片机文件内模拟烧录。即可出来原理图上的实验结果。

总结:

通过今次单片机实训,使我对单片机的认识有了更深刻的理解。通过键盘控制和数码管显示实现了基本时钟显示功能、时间调节功能,还有温度计DS18B20的显示等。能实现本设计题目的基本要求和发挥部分。
由于时间有限和本身知识水平的限制,本系统还存在一些不够完善的地方, 要作为实际应用还有一些具体细节问题需要解决。例如:不能实现只用两个按键来控制时钟时间,还不能实现闹钟等扩展功能。
希望本博客能在51单片机上给读者一定的帮助,省下找各种解决方案的时间成本。感谢各位观看,如有不足,欢迎在评论内留言与讨论。如果觉得写得好的,可以给我点赞+收藏+关注哦,再次感谢各位!
在这里插入图片描述

你可能感兴趣的:(51单片机,单片机,物联网,c语言,c++,编程语言)