c51单片机之利用外部中断实现数字时钟,且具有调时功能

仿真图:

代码段:

/*整体功能:用八位共阳极数目管作电子时钟显示,并用key0位控制进行时分秒位的选择,当按一次时代表选中时位,两次选中分位,三次选中秒位,第四次取消选中时钟正常运行
且选中时该位的小数点会亮代表该位已被选中;key1按键用来对位进行加一操作,key2用来对位进行减一操作*/
#include<reg52.h>
#define uint unsigned int      //重定义,方便使用
#define uchar unsigned char
sbit key0=P3^1;         //位定义,此处赋予key0设置功能,通过对key0的操作来选中时钟的三个位
sbit key1=P3^2;        //赋予key1按一次加一功能
sbit key2=P3^3;        //赋予key2按一次减一功能
sbit DU=P2^0;         //P2^0为段选开关,即数码管段码显示的开关
sbit WE=P2^1;         //P2^1为位选开关,即数码管位数选择的开关
void delay(uint z);    //延时函数
void display();        //数码管显示函数      
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};   //此处用共阳极八段数码管,前十位为0~9显示的段码,第十一个即table[10]为显示位之间的横杠的段码
uchar code wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};    //74HC573芯片,第二片控制位选,高四位二进制数决定位选,最高位为第一位。
uchar a[8];    //缓冲区变量,用来存放八个数码管要显示的数字;
uchar hour=05;    //设置小时的初始量为05
uchar minute=21;  //设置分钟的初始量为21
uchar second=00;   //设置秒的初始量为00
uchar n;         //定义变量n ,表示定时器T0的中断次数,以50ms一个中断,要中断20次为一秒
uchar t=0;      //定义变量t,用来统计key0按下的次数,依次为条件对时分秒位进行选中之后的操作
/********延时函数 **********/
void delay(uint z){    //此处延迟函数带一个参数z,这样方便对延迟的控制,也可以不带参数,但那样要改变延迟的话只能对函数内的条件进行改变
  uint j,k;
	for(j=0;j<z;j++)
	for(k=0;k<25;k++);
}
/******数码管显示函数******/
void display (uchar t) {
		uint i;                
	  for(i=0;i<8;i++){
			P0=wei[i];    //先送位选信号,即先选择对哪一位进行显示,由于74HC573芯片的锁存特性,故对此进行一个方波的脉冲信号即可进行数据的锁存,但应先送数据后进行脉冲
			WE=0;
			WE=1; 
			WE=0;           //由于控制位选的芯片和控制段选的信号连接在C51的同一个P0口处,因此当向74HC573送段选信号时,应关闭位选开关
			if(t>0&&t==i){         //此处对key0按下的次数t进行判断,用来让选择的那一位的小数点亮
						P0=table[a[i]]&0x7f;     //注意:此处的&为与操作符,目的是让对应的数字和数字的小数点同时点亮
						DU=0;
						DU=1;
						DU=0;	
						delay(10);				
		}
			else{
			P0=table[a[i]];    //对没有选中的位进行段码的输出显示
			DU=0;
			DU=1;
			DU=0;
			delay(10);		   //延迟
		}
		 }
			}
/******主函数*******/
void main () {
	a[2]=a[5]=10;    //让数码管的第3和第6位显示-
	TMOD=0x01;       //由于单次中断定时为50ms,因此应使用16位定时器,对应的工作方式的状态字为01,即TMOD=0x01                 课本P83 表3.2
	TH0=0x3C;        //单片机的晶振频率为12M,定时时间为50ms,对应的时间常数的十六位显示为3CB0,往TH0中送入高八位3C 					课本P86  例
	TL0=0xB0;        //往TL0中送入低八位B0                                                                                   
	IE=0x82;         //IE位的第7位为EA为CPU中断允许标志,第0位为定时器T0中断允许位,将这两位和EX0置1,对应的状态字为0x82    课本P79
	TR0=1;           //启动定时器T0                  课本P83
	IT0=1; 					 //设置外部中断为眺沿触发                课本P78最后一行
	IT1=1;    			 //同理
	while(1){
		display(t);    //开启状态对初始设定值进行显示
		if(key0==0){    //当按键按下时
			t++;          //t自加,记录按下的次数,调时
			EX0=1;        //调时状态下允许外部INT0,INT1中断,即只有按下key0后,再按key1,key2才有作用
			EX1=1;        //用来调小时,分,秒
			if(t>7){      //当调完即跳出选中状态时  
				t=0;        //灭小数点,对计数器归零
				n=0;        //中断次数计数器也归零,准备开始计时
				TR0=1;      //启动计数器T0
				EX0=0;      //关闭外部中断
				EX1=0;
}
			else if(t==2) t=4;  //调分   当按键按下两次后,为了让选中位为分的个位,让t=4,即此时选中数码管的第5位(最左侧为第一位)
			else if(t==5) t=7;  //调秒   同理,选中秒的个位  
			while(key0==0)  display(t);   //等待按键松开
	}
		if(n>=20&&t==0){      //中断20次,1秒到,正常计时状态下时钟计时
			n=0;
			second++;
			if(second>=60){
				second=0;
				minute++;
				if(minute>=60){
					minute=0;
					hour++;
					if(hour>=24)
					 hour=0;
}
		}
				}
    a[0]=hour/10;      //把八位要显示的数字放在a[]中,方便使用
		a[1]=hour%10;
		a[3]=minute/10;
		a[4]=minute%10;
		a[6]=second/10;
    a[7]=second%10;
						}
								}
void T0_0() interrupt 1{    //定时器T0中断服务程序
		TH0=0x3C;
	  TL0=0xb0;              //送时间常数
	  n++;                   //n计数,中断次数加一
}
void INT0_0() interrupt 0{   //外部中断INT0服务程序,为加一操作
	if(t==1){          //调小时
			hour++;       
			if(hour>=24)
			hour=0;
}
	if(t==4){         //调分
		minute++;       
		if(minute>=60)
		minute=0;
}
	if(t==7){          //调秒
		second++;  
		if(second>=60)
		second=0;
}
	}
void INT1_0() interrupt 2{       //外部中断INT1服务程序,为减一操作
	if(t==1){       //调小时
		hour--; 
		if(hour==0xff)
		hour=23;
}
	if(t==4){       //调分钟
		minute--;  
		if(minute==0xff)
		minute=59;
}
	if(t==7){       //调秒
		second--;
		if(second==0xff)
		second=59;
}
	}

 

  • 9
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
下面是一个汇编语言实现c51单片机实时时钟的例子,其中片内RAM42H、41H、40H分别存放秒、分、时单元的数值。 首先,我们需要定义三个变量,来分别表示秒、分、时单元的数值。假设我们将它们定义为 sec、min 和 hour,并且将它们存放在片内 RAM42H、41H、40H 中。 ``` ORG 0H MOV SP,#30H ; 初始化堆栈指针 ; 初始化 RAM42H、41H、40H MOV A, #RAM_INIT MOVX @DPTR, A MOV A, #sec MOVX @DPTR, A INC DPTR MOV A, #min MOVX @DPTR, A INC DPTR MOV A, #hour MOVX @DPTR, A ; 设置定时器 MOV TMOD, #01H ; 定时器0,模式1 MOV TH0, #256-((SYSCLK/12)/1000) ; 1ms 中断 MOV TL0, #256-((SYSCLK/12)/1000) SETB TR0 ; 启动定时器0 SETB ET0 ; 使能定时器0中断 ; 主循环 MAIN_LOOP: ; do something SJMP MAIN_LOOP ; 定时器0中断服务程序 TIMER0_ISR: INC sec ; 秒数加1 CJNE sec, #60, NO_MIN_INC ; 如果不等于60,跳过min加1 CLR sec INC min ; 分钟加1 CJNE min, #60, NO_HOUR_INC ; 如果不等于60,跳过hour加1 CLR min INC hour ; 小时加1 CJNE hour, #24, NO_RESET ; 如果不等于24,跳过重置 CLR hour NO_RESET: NO_HOUR_INC: NO_MIN_INC: ; 清除定时器0中断标志 CLR TF0 RETI ; 初始化 RAM42H、41H、40H 的标志 RAM_INIT: DB 0FFH END ``` 在上面的代码中,我们使用定时器0来实现每秒钟更新秒单元的数值。定时器0的计数器初值为 256-((SYSCLK/12)/1000),即每1ms中断一次,从而实现每秒钟更新一次秒单元的数值。 在定时器0的中断服务程序中,我们将 sec++,如果 sec 达到 60,将 sec 设为 0,min++。如果 min 达到 60,将 min 设为 0,hour++。如果 hour 达到 24,将 hour 设为 0。 在程序中,我们还需要初始化 RAM42H、41H、40H,以便在断电后能够恢复正确的时间。我们将当前的时间写入这些 RAM 地址中,以便在下一次上电时读取。在代码中,我们使用一个标志 RAM_INIT 来记录 RAM42H、41H、40H 是否已经初始化过。 综上所述,汇编语言实现c51单片机实时时钟的设计涉及到定时器的设置、中断服务程序的编写以及 RAM 的读写操作。可以根据具体的应用场景和需求,进行相应的扩展和改进。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值