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

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

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

#include <reg52.h>
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或者其他的设备,可双向传输数据。

数码管定时秒表

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

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

#include <reg51.h>
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点亮

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

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用51单片机C语言编写的0-60秒表计数器程序,其中包含了各行代码的注释,方便理解。 ```c #include <reg51.h> // 包含51单片机的头文件 #define uint unsigned int // 定义无符号整型变量 uchar code table[] = { // 存储数码管的值 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, // 0-9 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x3d, 0x76, 0x30, 0x1e, // A-J 0x76, 0x38, 0x55, 0x54, 0x5c, 0x73, 0x67, 0x50, 0x6a, 0x78, // K-T 0x00 // 结束标志 }; void delay(uint i) { // 延时函数 while (i--); } void display(uint num) { // 显示函数 uint i; for (i = 0; i < 8; i++) { // 显示个位数 P0 = table[num % 10]; // 取出个位数的值 P1 = 0x01 << i; // 选择对应的数码管 delay(100); P0 = 0x00; // 关闭数码管 } for (i = 0; i < 8; i++) { // 显示十位数 P0 = table[num / 10]; // 取出十位数的值 P1 = 0x80 >> i; // 选择对应的数码管 delay(100); P0 = 0x00; // 关闭数码管 } } void main() { // 主函数 uint i, j; TMOD = 0x01; // 定时器1工作在模式1 TH0 = 0x3C; // 定时器1的初值为0x3C TL0 = 0xB0; // 定时器1的重载值为0xB0 TR0 = 1; // 启动定时器1 ET0 = 1; // 允许定时器1中断 EA = 1; // 允许所有中断 while (1) { // 主循环 for (i = 0; i < 60; i++) { // 0-59秒循环 for (j = 0; j < 20; j++) { // 延时约1秒钟 display(i); // 显示当前秒数 } } } } void timer0() interrupt 1 { // 定时器1中断函数 static uint cnt = 0; // 计数器 TH0 = 0x3C; // 定时器1的初值为0x3C TL0 = 0xB0; // 定时器1的重载值为0xB0 cnt++; // 计数器加1 if (cnt == 50) { // 每隔1秒钟 cnt = 0; // 计数器清零 } } ``` 在该程序中,通过`code`关键字定义了一个位于程序存储器中的常量`table`,用于存储数码管的值。在主函数中,使用定时器1产生1秒钟的中断,并在中断函数中每隔1秒钟计数器加1,用于计算当前秒数,并调用`display()`函数显示当前秒数。在`display()`函数中,使用`for`循环分别显示个位数和十位数,其中使用了延时函数`delay()`来控制数码管的显示时间。在`timer0()`函数中,每隔1秒钟计数器清零,用于实现0-60秒的计数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值