【51单片机】定时器应用与时钟显示技巧

定时器与串口通信

  • 一、任务目标
  • 二、实现过程
  • 2.1 中断方波信号
  • 2.1.1 Proteus仿真图
  • 2.1.2 KEIL代码
  • 2.2 显示计时时间
  • 2.2.1 Proteus仿真图
  • 2.2.2 代码实现
  • 2.3 LCD显示时钟
  • 2.3.1 Proteus仿真图
  • 2.3.2 代码实现
  • 三、实验总结
  • 一、任务目标

    请分别在Proteus和普中51单片机上完成下列程序:

    1、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫。

    2、用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按一下计时功能键时,秒表开始计时并显示;第2次按一下计时功能键时,停止计时,将计时的时间值送到数码管显示;如果计时到9.9s,将重新开始从0计时;第3次按一下计时功能键,秒表清0。再次按一下计时功能键,则重复上述计时过程。

    3、使用定时器实现一个LCD显示时钟。

    二、实现过程

    2.1 中断方波信号

    通过改变定时器的计数值来改变蜂鸣器的频率,从而产生不同的声音。

    系统时钟为12MHz,则机器周期为1µs。方波音频信号周期1ms。

    1kHz方波音频信号,因此T1的定时中断时间为0.5 ms。进入中断后,P1.0端口和P1.7端口的状态也在每次中断时取反。

    先计算T1初值,系统时钟为12MHz,则机器周期为1µs。1kHz音频信号周期为1ms,要定时计数的脉冲数为a。则T1初值:
    TH1=(65 536 −a) /256;
    TL1=(65 536 −a) %256

    2.1.1 Proteus仿真图

    Proteus仿真图1

    2.1.2 KEIL代码

    #include <reg52.h>  
    sbit BUZZ=P1^7; 													// 假设蜂鸣器接在P1.7  
    sbit P1_0=P1^0; 													// 假设示波器接在P1.0   
    #define f1(a) (65536 - a) / 256;					//用于计算定时器初值的高8位
    #define f2(a) (65536 - a) % 256;					//用于计算定时器初值的低8位
    
    unsigned int i=500;												
    //定义一个无符号整数变量i,初始值为500,用于定时器的计数值
    unsigned int j=0;													
    //定义一个无符号整数变量j,用于计数中断次数
    
    void main(void) {  
    	TMOD|=0x10;      //设置定时器T1为模式2
    	TH1=f1(i);       //用于设置定时器初值的高8位
    	TL1=f2(i);       //用于设置定时器初值的低8位
    	ET1=1;					 //允许定时器T1中断 
    	EA=1;            //开启全局中断
    	TR1=1;           //启动定时器T1
    	while(1)
    	{
    		i=460;          //设置定时器的计数值
    		while(j<2000);  //等待中断发生2000次
    		j=0;            //重置计数器j
    		i=360;
    		while(j<2000);
    		j=0;
    	}
    }
    
    void int_T1() interrupt 3 using 0  //定义定时器T1的中断服务程序
    {
    	TR1=0;      //在中断服务程序开始时,先关闭定时器T1
    	BUZZ=~BUZZ; //取反蜂鸣器的输出状态
    	P1_0=~P1_0; //取反P1.0端口的输出状态
    	TH1=f1(i);  //更新定时器T1的高8位初值
    	TL1=f2(i);  //更新定时器T1的低8位初值
    	j++;
    	TR1=1;      //重新启动定时器T1
    }
    
    

    2.2 显示计时时间

    2.2.1 Proteus仿真图

    2.2.2 代码实现

    需要编写代码来初始化定时器、扫描按键状态、更新计时时间,以及将时间显示在数码管上。
    初始化定时器

    	TMOD=0x01;			//定时器T0方式1定时
    	ET0=1;                   	//允许定时器T0中断
    	EA=1;                    		//总中断允许
    

    扫描按键状态

    		if((P3&0x80)==0x00)		//当按键被按下时
    		{	 
    			key++;			//按键次数加1
    			switch(key)		//根据按键次数分三种情况
    			{
    				case 1:		//第一次按下为启动秒表计时
    					TH0=0xee; 	//向TH0写入初值的高8位
    					TL0=0x00;	   	//向TL0写入初值的低8位,定时5ms
    					TR0=1;         		//启动定时器T0
    				break;
    				case 2:        		//按下两次暂定秒表
    					TR0=0;         		//关闭定时器T0
    				break;
    				case 3:        			//按下3次秒表清0
    					key=0;         			//按键次数清
    					second=0;      			//秒表清0
    					P0=discode1[second/10];   	//显示秒位0   				
    					P2=discode2[second%10];  	//显示0.1s位0
    				break;
    			}
    			while((P3&0x80)==0x00);     		//如果按键时间过长在此循环
    		}
    

    中断函数

    void int_T0() interrupt 1  using 0 		//定时器T0中断函数
    {						
    	TR0=0;		 	//停止计时,执行以下操作(会带来计时误差)
    	TH0=0xee;	  	//向TH0写入初值的高8位
    	TL0=0x00;	   	//向TL0写入初值的低8位,定时5ms
    	timer++;   	   	//记录中断次数
    	if (timer==20)	   	//中断20次,共计时20*5ms=100ms=0.1s
    	{
    		timer=0;    			//中断次数清0
    		second++;   			//加0.1s
    		P0=discode1[second/10]; 	//根据计时,即时显示秒位		
    		P2=discode2[second%10]; 	//根据计时,即时显示0.1s位	 }
    		if(second==99) 		 //当计时到9.9s时
    		{
    			TR0=0;			//停止计时
    			second=0;		//秒数清0		
    			key=2;	  		//按键数置2,当再次按下按键时,					//key++,即key=3,秒表清0复原	
    		}                           
    		else				//计时不到9.9s时
    		{
    			TR0=1;			//启动定时器继续计时
    		}
    	}
    }
    

    完整代码

    #include<reg51.h>  			//头文件
    unsigned char code discode1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};	
                                 	//数码管显示0~9的段码表, 带小数点
    unsigned char code discode2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};	
                                	//数码管显示0~9的段码表,不带小数点
    unsigned char timer=0;		//timer记录中断次数
    unsigned char second;        	//second储存秒
    unsigned char key=0;		//key记录按键次数
    
    void main(void)				//主函数
    {
    	TMOD=0x01;			//定时器T0方式1定时
    	ET0=1;                   	//允许定时器T0中断
    	EA=1;                    		//总中断允许
    	second=0;                		//设初始值
    	P0=discode1[second/10];   		//显示秒位0
    	P2=discode2[second%10];   		//显示0.1s位0
    	while(1)				 //循环
    	{	
    		if((P3&0x80)==0x00)		//当按键被按下时
    		{	 
    			key++;			//按键次数加1
    			switch(key)		//根据按键次数分三种情况
    			{
    				case 1:		//第一次按下为启动秒表计时
    					TH0=0xee; 	//向TH0写入初值的高8位
    					TL0=0x00;	   	//向TL0写入初值的低8位,定时5ms
    					TR0=1;         		//启动定时器T0
    				break;
    				case 2:        		//按下两次暂定秒表
    					TR0=0;         		//关闭定时器T0
    				break;
    				case 3:        			//按下3次秒表清0
    					key=0;         			//按键次数清
    					second=0;      			//秒表清0
    					P0=discode1[second/10];   	//显示秒位0   				
    					P2=discode2[second%10];  	//显示0.1s位0
    				break;
    			}
    			while((P3&0x80)==0x00);     		//如果按键时间过长在此循环
    		}
    	}
    }
    void int_T0() interrupt 1  using 0 		//定时器T0中断函数
    {						
    	TR0=0;		 	//停止计时,执行以下操作(会带来计时误差)
    	TH0=0xee;	  	//向TH0写入初值的高8位
    	TL0=0x00;	   	//向TL0写入初值的低8位,定时5ms
    	timer++;   	   	//记录中断次数
    	if (timer==20)	   	//中断20次,共计时20*5ms=100ms=0.1s
    	{
    		timer=0;    			//中断次数清0
    		second++;   			//加0.1s
    		P0=discode1[second/10]; 	//根据计时,即时显示秒位		
    		P2=discode2[second%10]; 	//根据计时,即时显示0.1s位	 }
    		if(second==99) 		 //当计时到9.9s时
    		{
    			TR0=0;			//停止计时
    			second=0;		//秒数清0		
    			key=2;	  		//按键数置2,当再次按下按键时,					//key++,即key=3,秒表清0复原	
    		}                           
    		else				//计时不到9.9s时
    		{
    			TR0=1;			//启动定时器继续计时
    		}
    	}
    }
    

    2.3 LCD显示时钟

    2.3.1 Proteus仿真图

    1

    2.3.2 代码实现

    #include<reg52.h>
    #include<lcd1602.h>
    #include<stdio.h>
    #define uchar unsigned char
    #define uint unsigned int
    uchar int_time;				//定义中断次数计数变量
    uchar second;				//秒计数变量
    uchar minute;				//分钟计数变量
    uchar hour;				//小时计数变量
    uchar code date[]="  H.I.T. CHINA  ";	//LCD第1行显示的内容
    uchar code time[]=" TIME  23:59:55 ";	//LCD第2行显示的内容
    uchar second=55,minute=59,hour=23;
    
    void clock_init()
    {
    	uchar i,j;
    	for(i=0;i<16;i++)
    	{
    		write_data(date[i]);
    	}
    write_com(0x80+0x40);
    
    for(j=0;j<16;j++)
    	{
    		write_data(time[j]);
    	}
    }
    
    void clock_write( uint s, uint m, uint h)
    {
    	write_sfm(0x47,h);
    	write_sfm(0x4a,m);
    	write_sfm(0x4d,s);
    }
    
    void main()
    {
    	init1602();		//LCD初始化
    	clock_init();		//时钟初始化
    TMOD=0x01;			 //设置定时器T0为方式1定时
    EA=1;            			// 总中断开 
    ET0=1; 				// 允许T0中断 
    TH0=(65536-46483)/256;	//给T0装初值
    TL0=(65536-46483)%256;
    TR0=1;
    int_time=0;			//中断次数、秒、分、时单元清0
    second=55;
    minute=59;
    hour=23;
    while(1)
    {
    	clock_write(second ,minute, hour);
    }
    }
    
    void  T0_interserve(void)  interrupt 1  using 1 	//T0中断服务子程序
    {	
    	int_time++;				//中断次数加1
     	if(int_time==20) 			//若中断次数计满20次
     	{ 
    		int_time=0; 			//中断次数变量清0
     		second++;			//秒计数变量加 1
     	}
     	if(second==60)			//若计满60s
     	{ 
    	second=0; 				//秒计数变量清0
     	minute ++;				//分计数变量加 1
     	}
    	
    if(minute==60)			//若计满60分
    { 	
    	minute=0;		//分计数变量清0
    	hour ++;		//小时计数变量加1
    }
    if(hour==24)
    { 	
    	hour=0;			//小时计数计满24,将小时计数变量清0
    }
    TH0=(65536-46083)/256;		//定时器T0重新赋值
    TL0=(65536-46083)%256;
    }
    
    

    三、实验总结

    以上则是我的实验过程,如有错误请各位大佬多多指教

    作者:双料毒狼_s

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【51单片机】定时器应用与时钟显示技巧

    发表回复