单片机原理及应用:数码管定时秒表和LED计数器

先前我们介绍了定时器/计数器的概念与作用原理,下面我通过两个应用案例来分别演示定时器和计数器的用法。

第一个案例是用数码管配合定时器中断制作秒表,同理也可以自己改变时间单位制作不同精度的电子钟,修改方式我已经附在代码注释中了。

#include 
unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C};
unsigned char Dat[]={0,0}; //用数组储存数码管要显示的数字
unsigned char Second,t;

void Delay()			   //为了消影需要延时函数,可以忽略延时带来的定时误差
{
  unsigned char i;
     for(i=0;i<50;i++);
}

void main()
{
  EA = 1;            //总中断允许
  ET0 = 1;           //允许T0中断
  TMOD =0x01;       //计时器0工作方式1
  TH0 = -50000/256; //高位赋初值,用表达式减少了计算的麻烦
  TL0 = -50000%256;	//低位赋初值
  TR0 = 1; 			//开启计时器0
  while(1)
  {					  //进行数据分割
    Dat[0]=Second/10; //累计时间的十位存入数组
    Dat[1]=Second%10; //累计时间的各位存入数组
    
    P0=Tab[Dat[0]];	  //读取数码管相应的数字段码
    P1=0xfe;		  //位选开启十位数码管,注意仿真图,十位接在P1.0上
    Delay();
    P1=0xff;		  //消影
   
    P0=Tab[Dat[1]];	  //个位同理
    P1=0xfd;
    Delay();
    P1=0xff;
  }
}

void intserv1 (void) interrupt 1 using 1
{
  TH0= -50000/256; 	//减法赋值的简写
  TL0= -50000%256;
  t++;				//记录1s的二十分之一
  if(t==20)			//累积到1s后置零,秒数加1
  {					//如果要更改秒表的精确程度,修改这里再添加一个用于显示精确位数的数码管即可
  /*if(t==2)		//比如改为t==2,就是每0.1s在数码管显示一次,输出时再加一个用于显示十分位的数码管
	{t=0;			//同时将second的归零值改为100,不过要注意两件事情
    num++;			//一是变量在命名second容易出现语意不明,应改为num加注释说明
	if(Second>=600) Second=0;
	}*/				//二是带小数点显示的段码与先前用到的不同,需要重新设置数组
    t=0;
    Second++;
    if(Second>=60) Second=0; //到一分钟后重新开始
  }
}

仿真效果如下,为了让输出的电平更稳定,笔者采用了74LS245芯片,它是8路同相三态双向总线收发器,用来驱动LED或者其他的设备,可双向传输数据。

单片机原理及应用:数码管定时秒表和LED计数器_第1张图片

数码管定时秒表

为了不浪费太多时间,我在演示视频中剪去了中间计数的一部分,大家主要看1分钟自动置零的效果就可以了。

第二个案例是计数器,要求是双击按键切换灯光,再次双击切换另一种灯光。

#include 
unsigned char F=0;
    void Delay(unsigned int i)		
{	
	unsigned int j;		
	for(;i>0;i--)			
	for(j=0;j<125;j++);		

 }
void  main( )	
 {					//顺序可以调换,记住要配置TMOD、TCON、IE和初值
	TMOD=0x50;	    //设置定时器T1工作方式1
	TH1=0xff;		//向TH1写入初值的高8位
	TL1=0xfe;		//向TL1写入初值的低8位
	EA=1;    		//开启总中断允许
	ET1=1;   		//定时器T1中断允许  
 	TR1=1;   		//启动定时器T1
	 while(1)
	 {
		if(F==1)		   //第一次双击,灯光标志位为1,进入模式1		
	 	{	
			P1=0xff;	   //LED全部闪烁	
	 		Delay(500) ;		
	 		P1=0x00;			
	 		Delay(500); 		 
		}
		if(F==2)		   //第二次双击,灯光标志位为2,进入模式2		
	 	{	
			P1=0xaa;	   //LED奇偶位交替闪烁 	
	 		Delay(500) ;		
	 		P1=0x55;			
	 		Delay(500); 
		}
		if(F==3)		  //第三次双击,清空标志位,关闭灯光
		{	F=0;
			P1=0xff;
		}	
	 }
	}


void T1_int(void)  interrupt 3  	//计数器T1中断服务函数
{
	TH1=0xff;		//重新赋值
	TL1=0xfe;		
	F++;			//灯光执行标志+1,中断只做赋值,不执行具体程序,可以有效减少运行时间			
}




大家可以自行改变按键对应的执行程序,与其他外设组合,比如让数码管显示不同的图案,也可以更改标志位的复制逻辑,单双击赋予不同的意义。总的来说思路都相同,只是需要注意在中断服务函数里应尽量少执行操作,将重点的操作置于主函数内部,通过改变标志位的数值来执行不同的程序。 

单片机原理及应用:数码管定时秒表和LED计数器_第2张图片

按键计数器控制LED点亮

今天和大家分享了两个定时器/计数器的应用,因为笔者所学专业对单片机要求不高,亟待分享的内容只剩下几个类似的应用,这个专栏也快要走到尾声了,感谢大家一路的陪伴,我们明天再见。

你可能感兴趣的:(单片机原理及应用,单片机,嵌入式硬件,proteus,c语言,51单片机)