LED数码管秒表(精确到0.01s)

利用C51单片机实现LED数码管显示秒表。主要使用到的结构是51单片机的三个P口以及定时器。

要求:

制作一个LED数码管显示的秒表,用2位数码管显示计时时间,最小计时单位为"十毫秒",计时范围为0.01-9.99s.当第一次按下并松开计时功能键时,秒表开始计时并显示时间;第二次按下并松开计时器功能键,停止计时,计算两次按下计时功能键的时间,并在数码管上显示;第三次按下计时功能键,秒表清零,再按一次计时功能键,重新开始计时。如果计时到9.99s时将停止计时,按下计时功能键,秒表清零,再按下重新开始计时。

分析:

既然要的是三位数字那么一定要的就是三个7段数码管了,刚开始可能看着这么多的功能可能会感到很复杂,实际上我们从本质上来看,就是说如果不按键就是卡主不动,按一下就会一直走,一直走到9.99然后停止(这个时候再按一下就会清零) 按第二下就会停下来,停在当前计数的时间,按第三下就会归零回到从来没有按过的状态。从这里也可以分析处理9.99秒停止的时候的状态实际上也是按第二下的状态,再按一下就归零。这样看起来就没有那么的复杂,但是还是有些绕,我们的全局变量中当中实际上要做的就是把0-999的数字记录下来的一个值,一个记录下按键次数的值,再一个记录下中断次数的值。
代码如下:

//P0口作为I/O端口输出时,输出级属于开漏电路,必须外接10KΩ上拉电阻
#include 
unsigned char code discode1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//一共十个数,code关键字是意味着存储到ROM当中去。
unsigned char code discode2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//上面(有小数点)和下面(无小数点)都是从0到9的字节码
unsigned char code discode3[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//第三个数
unsigned char times=0;//中断了多少次
int second;//一共经历的时间,这里要注意的是如果你要记录的数据较大就不能够用char和unsigned char来定义,否则就无法表示
unsigned char key=0;
void main(void)
{
	TMOD=0x01;
	ET0=1;//允许TO进行中断
	EA=1;
	second=0;//初值赋值为0
	P0=discode1[second/100];//显示对应的秒位
	P2=discode2[second/10-(second/100)*10];//显示对应的后面
	P1=discode3[second%10];
	while(1)
	{
		if((P3&0x80)==0x00)//正常情况下为1,但开关按下去为0,此处仅仅对P3.7口做了一个判断P3^7?
		{
			while((P3&0x80)==0x00);//如果你不松开就一直保持在这个循环里面,不改变状态继续之前的中断操作	
		   key++;
		   switch(key)
		   {
			case 1://第一次按键,启动计时
				   TH0=0xee;//一次为5ms的中断
				   TL0=0x00;
				   TR0=1;//启动定时器的必备条件
				   break;
			case 2:
				TR0=0;//暂停计时
				break;
			case 3://第三下清零,并将次数设置为1
				key=0;
				second=0;//设置秒数为零
				P0=discode1[second/100];//显示对应的秒位
				P2=discode2[second/10-(second/100)*10];//显示对应的后面
				P1=discode3[second%10];
				break;
		   }
		   //while((P3&0x80)==0x00){};//按键时间过长在此循环,不添加此步一会又要返回到判断过程中,		  



		}



	}
	

}
void timer() interrupt 1 using 0
{
	TR0=0;//停止计时,在设置时间的时候就不计时了,会存在一定误差,在这里暂停说明刚才的中断T0已经溢出,所以后续操作首先要对其进行赋初值
	TH0=0xee;
	TL0=0X00;
	times++;	
	 if(times==2)//2x5ms=10ms是0.01s
	 {
	 	times=0;
		second++;//0.01为单位的数量+1
		P0=discode1[second/100];//显示对应的秒位
		P2=discode2[second/10-(second/100)*10];//显示对应的后面
		P1=discode3[second%10];//0.01位显示
	 }
	if(second==999)//当满了的时候,这个时候停止就好了
	{
	 	TR0=0;
		//TH0=0xee;
		//TL0=0x00;
		second=0;
		key=2;//用程序设置按键次数为第二次因为下次再按下去就是第三次清零,符合题目要求
	}
	else
	{

		TR0=1;//否则开中断继续计时
	}



}

代码注释已经分析的很详细了,再提醒一下就是对应的记录次数的变量要找一个>999范围的例如int型,虽然很简单的问题但是很容易忽视。

接下来就是proteus电路了如下所示,()要注意的是P0口作为I/O端口输出时,输出级属于开漏电路,必须外接上拉电阻(图中用的是一个阻排(RESPACK))否则高电平就无法输出。还有就是数码管是选择共阴极(cathnode)的而非共阳极(anode)的
LED数码管秒表(精确到0.01s)_第1张图片

元器件:

LED数码管秒表(精确到0.01s)_第2张图片

存在的问题(已解决):

我不太明白为什么AT89C51单片机为什么可以在不接外部晶振的情况下工作,因为我查到的网上资料都是说不能不接外部晶振的,然而此处的电路没有接却照样可以正常运行。

问题解决:

51单片机实际上是必须要有一个外部的晶振的,但是在proteus当中是可以省略的,因为这个仿真程序已经自动帮我添加了对应的晶振,要改变的话可以右击51单片机然后点击edit property 有一个clock frequency就是对应的晶振频率。

你可能感兴趣的:(51单片机)