《51单片机入门:制作一个精美的数字时钟》

文章目录

  • 1. 前言
  • 1.1. 设计要求
  • 2. 硬件原理
  • 2.1. 时钟信号(晶振)
  • 2.2. 按键开关
  • 2.3. 数码管显示
  • 3. 原理图
  • 3.1. 仿真原理图
  • 3.2. AD原理图
  • 3.3. PCB图
  • 4. 软件设计
  • 4.1. 初版代码(无年月日)
  • 4.2. 终版代码
  • 5. 元器件清单
  • 5.1. 仿真软件
  • 5.2. 实物
  • 1. 前言

    在此之前我们已经学习了单片机的定时器、中断、数码管。这篇文章主要讲述如何用上述的知识自己制作一个基于51单片机的数字时钟。

    1.1. 设计要求

    (1)主电路由秒信号发生器、“时、分、秒”计数器、译码器及显示器、校准电路等构成。
    (2)秒信号发生器一般用石英晶体振荡器加分频器实现。
    (3)译码电路将时、分、秒计数器的输出状态送七段译码器译码,经过八位LED七段共阴显示器显示出来。
    (4)校时电路用来对时、分、秒显示数字进行校对。

    2. 硬件原理

    2.1. 时钟信号(晶振)


    单片机晶振部位电路,详情请参考《51单片机入门——单片机最小系统》,在此项目中我们选择 11.0592 MHz的晶振。

    2.2. 按键开关


    按键部分我们选择使用单片机的P3.0、P3.1、P3.2 三个 I/O 口 使用。

    初版原理:按下开关K2“时”加一,按下开关K3“分”加一,按下开关K4“秒”加一。

    终版原理:按下开关K3加一,按下开关K2控制按钮2的位移(例如:刚开始按K3无反应,按一下K2后秒加、再按分加),按下开关K4控制“时分秒”与“年月日”的切换。

    2.3. 数码管显示

    在仿真软件中我们选择使用两个4位共阴极数码管(红色),实际电路中选择两个4位0.36英寸的红色共阴极数码管。
    仿真软件

    PCB设计软件3D图

    3. 原理图

    3.1. 仿真原理图

    3.2. AD原理图

    3.3. PCB图

    4. 软件设计

    4.1. 初版代码(无年月日)

    //该程序使用两个四位共阴数码管,10.0592Mhz晶振,STC89C52RC单片机,三个轻触开关 
    #include<reg51.h>
    #define uchar unsigned char
    #define uint unsigned int
    //单独控制某个引脚的电平不能直接写P3^0=1,必须先定义引脚
    sbit key0 = P3^0 ;		 
    sbit key1 = P3^2 ;
    sbit key2 = P3^3 ;
    
    uchar s[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};	   //共阴数码管0~9
    uchar a = 0 ,hour = 0 , min = 0 , sec = 0 ;					   
    uchar b = 0 , c = 0 , d = 0;
    
    void time0_server_() interrupt 1      // interrupt  0表示外部中断0 , 1表示定时器中断0 , 2表示外部中断1 , 3表示定时器中断1 , 4表示串口中断
    {
    	TH0 = 0x4c ;
    	TL0 = 0x00 ;
    	a++;
    	if(a == 20)						//20 * 50 = 1000ms = 1s 即每隔1s“秒”加1
    	{
    		a = 0 ;
    		sec = sec + 1 ;
    	}
    	if(sec == 60)				   //sec=60时清空,“分”加1
    	{
    		min = min + 1 ;
    		sec = 0 ;
    	} 
    	if(min == 60)				  //min=60时清空,“时”加1
    	{
    		hour = hour + 1 ;
    		min = 0 ;
    	}
    	if(hour == 24)				 //hour=24时清空
    	{
    		hour = 0 ;
    	}
    }
    
    void init_t0()
    {
    	TMOD = 0x01 ;	   //采用16位定时器
    	TH0 = 0x4C ;	   //50ms (65536-50000)/256
    	TL0 = 0x00 ;	   //       (65536-50000)%256   
    	EA = 1 ;		   //开启定时器0的中断
    	ET0 = 1 ;          //开启总中断		  
    	TR0 = 1 ;		   //启动定时器0		  
    }
    
    void delay(uint n)			   //延时函数(运行空项目以达到延迟时间的效果)
    {
    	uint i,j;
    	for(i = 0 ; i < n ; i ++)
    	{
    		for(j = 0 ; j < 120 ; j ++);
    	}	
    }
    
    void display1()						   //在数码管上显示
    {
    	uchar t0 = 0 ,t1 = 0 , t2 = 0 , t3 = 0 , t4 = 0 , t5 = 0 ;
    	t0 = hour / 10 ;		  //t0表示时针的十位
    	t1 = hour % 10 ;		  //t1表示时针的个位
    	t2 = min / 10 ;			  //t2表示分针的十位
    	t3 = min % 10 ;			  //t3表示分针的个位
    	t4 = sec / 10 ;			  //t4表示秒针的十位
    	t5 = sec % 10 ;			  //t5表示秒针的个位
    	P2 = 0x7f ;				  //P2^7低电平	 0111 1111	 控制第一个数码管 
    	P0 = s[t0] ;			  //用来显示“时”的十位
    	delay(1) ;				  //延时大约1ms
    	P2 = 0xbf ;				  //P2^6低电平	 1011 1111	 控制第二个数码管 
    	P0 = s[t1] ;			  //用来显示“时”的个位
    	delay(1) ;
    	P2 = 0xdf ;				  //P2^5低电平	 1101 1111	 控制第三个数码管 
    	P0 = 0x40 ;				  //显示“—”来分割“时”与“分”
    	delay(1) ;
    	P2 = 0xef ;				  //P2^4低电平	 1110 1111	 控制第四个数码管 
    	P0 = s[t2] ;			  //用来显示“分”的十位
    	delay(1) ;
    	P2 = 0xf7 ;				  //P2^3低电平	 1111 0111	 控制第五个数码管 
    	P0 = s[t3] ;			  //用来显示“分”的个位
    	delay(1) ;
    	P2 = 0xfb ;				  //P2^2低电平	 1111 1011	 控制第六个数码管 
    	P0 = 0x40 ;				  //显示“—”来分割“分”与“秒”
    	delay(1) ;
    	P2 = 0xfd ;				  //P2^1低电平	 1111 1101	 控制第七个数码管 
    	P0 = s[t4] ;			  //用来显示“秒”的十位
    	delay(1) ;
    	P2 = 0xfe ;				  //P2^0低电平	 1111 1110	 控制第八个数码管 
    	P0 = s[t5] ;			  //用来显示“秒”的个位
    	delay(1) ;	
    }
    
    void KEY0()							//开关0控制“时”加1
    {
    	if(key0 == 0 && c == 0)
    	{
    		c = 1 ;
    	}
    	if(key0 == 1 && c == 1)
    	{
    		c = 0 ;
    		hour = hour + 1 ;
    	}
    }
    
    void KEY1()						 //开关1控制“分”加1
    {
    	if(key1 == 0 && d == 0)
    	{
    		d = 1 ;
    	}
    	if(key1 == 1 && d == 1)
    	{
    		d = 0 ;
    		min = min + 1 ;
    	}
    }
    
    void KEY2()						 //开关2控制“秒”加1
    {
    	if(key2 == 0 && b == 0)
    	{
    		b = 1 ;
    	}
    	if(key2 == 1 && b == 1)
    	{
    		b = 0 ;
    		sec = sec + 1 ;
    	}
    }
    
    void main()					  //主函数
    {
    	init_t0();
    	while(1)
    	{
    		KEY0();
    		KEY1();
    		KEY2();
    		display1();
    	}	
    }
    

    4.2. 终版代码

    #include<reg51.h>
    #define uchar unsigned char
    #define uint unsigned int
    sbit key1 = P3^0 ;
    sbit key0 = P3^1 ;		 
    sbit key2 = P3^2 ;
    sbit key3 = P3^3 ;
    
    uchar s[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};	   //共阴数码管0~9
    uchar hour = 10 , min = 10 , sec = 0 ,day = 25 , month = 1 , year = 20 ;					   
    uchar a = 0 ,b = 0 , c = 0 , d = 0 , e = 0 ,f = 0 ;
    uchar b_1 = 0 ,c_1 = 0 ;		   
    
    void time0_server_() interrupt 1      
    {
    	TH0 = 0x4c ;
    	TL0 = 0x00 ;
    	a++;
    	e = 2000 + year ;
    	if(a == 20)					
    	{
    		a = 0 ;
    		sec = sec + 1 ;
    	}
    	if(sec == 60)				   
    	{
    		min = min + 1 ;
    		sec = 0 ;
    	} 
    	if(min == 60)				 
    	{
    		hour = hour + 1 ;
    		min = 0 ;
    	}
    	if(hour == 24)				 
    	{
    		day = day + 1 ;
    		hour = 0 ;	
    	}
    	switch(month)			//根据月份来控制天数
    	{
    		case 1: 
    		case 3:
    		case 5:
    		case 7:
    		case 8:
    		case 10:
    		case 12:if(day == 32)
    				{
    					month = month + 1 ;
    					day = 1 ;
    				}
    				break ;
    		case 4:
    		case 6:
    		case 9:
    		case 11:if(day == 31)
    				{
    					month =month + 1;
    					day = 1 ;
    				}
    				break ;
    		case 2:if(e%400==0||e%4==0&&e%100!=0)
    			    {
    				 	if(day == 30)
    					{
    						month = month + 1 ;
    						day = 1 ;	
    					}
    				}
    				else if(day == 29)
    					 {
    					 	month = month + 1 ;
    						day = 1 ;	
    					 }
    				break ;
    	}
    	if(month == 13)
    	{
    		year = year + 1 ;
    		month = 1 ;
    	} 
    
    }
    
    void init_t0()
    {
    	TMOD = 0x01 ;	   
    	TH0 = 0x4C ;	   
    	TL0 = 0x00 ;	     
    	EA = 1 ;		   
    	ET0 = 1 ;          		  
    	TR0 = 1 ;		   		  
    }
    
    void delay(uint n)	 //延时函数	大约1ms	   
    {
    	uint i,j;
    	for(i = 0 ; i < n ; i ++)
    	{
    		for(j = 0 ; j < 120 ; j ++);
    	}	
    }
    
    void display1()		//显示 “时、分、秒”				 
    {
    	uchar t0 = 0 ,t1 = 0 , t2 = 0 , t3 = 0 , t4 = 0 , t5 = 0 ;
    	t0 = hour / 10 ;		  
    	t1 = hour % 10 ;		  
    	t2 = min / 10 ;		
    	t3 = min % 10 ;			  
    	t4 = sec / 10 ;			 
    	t5 = sec % 10 ;
    /************* 74HC138译码器 辅助控制数码管 ******/			  
    //	P2 = 0x1c ;
    //	P0 = s[t0] ;
    //	delay(2) ;
    //	P2 = 0x18 ;
    //	P0 = s[t1] ;
    //	delay(2) ;
    //	P2 = 0x14 ;
    //	P0 = 0x40 ;
    //	delay(2) ;
    //	P2 = 0x10 ;
    //	P0 = s[t2] ;
    //	delay(2) ;
    //	P2 = 0x0c ;
    //	P0 = s[t3] ;
    //	delay(2) ;
    //	P2 = 0x08 ;
    //	P0 = 0x40 ;
    //	delay(2) ;
    //	P2 = 0x04 ;
    //	P0 = s[t4] ;
    //	delay(2) ;
    //	P2 = 0x00 ;
    //	P0 = s[t5] ;
    	delay(2) ;
    /*********** P2直接控制数码管 *********/
    	P2 = 0x7f ;				  
    	P0 = s[t0] ;		
    	delay(1) ;			
    	P2 = 0xbf ;				  
    	P0 = s[t1] ;		
    	delay(1) ;
    	P2 = 0xdf ;			
    	P0 = 0x40 ;			
    	delay(1) ;
    	P2 = 0xef ;			
    	P0 = s[t2] ;			  
    	delay(1) ;
    	P2 = 0xf7 ;				 
    	P0 = s[t3] ;			
    	delay(1) ;
    	P2 = 0xfb ;				 
    	P0 = 0x40 ;				
    	delay(1) ;
    	P2 = 0xfd ;				
    	P0 = s[t4] ;			 
    	delay(1) ;
    	P2 = 0xfe ;			
    	P0 = s[t5] ;		
    	delay(1) ;	
    }
    
    void display2()	   //显示 “年、月、日”
    {
    	uchar t0 = 0 ,t1 = 0 , t2 = 0 , t3 = 0 , t4 = 0 , t5 = 0 ;
    	t0 = year / 10 ;		  
    	t1 = year % 10 ;		  
    	t2 = month / 10 ;		
    	t3 = month % 10 ;			  
    	t4 = day / 10 ;			 
    	t5 = day % 10 ;	
    	/************* 74HC138译码器 辅助控制数码管 ******/	
    //	P2 = 0x1c ;
    //	P0 = s[t0] ;
    //	delay(2) ;
    //	P2 = 0x18 ;
    //	P0 = s[t1] ;
    //	delay(2) ;
    //	P2 = 0x14 ;
    //	P0 = 0x40 ;
    //	delay(2) ;
    //	P2 = 0x10 ;
    //	P0 = s[t2] ;
    //	delay(2) ;
    //	P2 = 0x0c ;
    //	P0 = s[t3] ;
    //	delay(5) ;
    //	P2 = 0x08 ;
    //	P0 = 0x40 ;
    //	delay(2) ;
    //	P2 = 0x04 ;
    //	P0 = s[t4] ;
    //	delay(2) ;
    //	P2 = 0x00 ;
    //	P0 = s[t5] ;
    //	delay(2) ;
    /*********** P2直接控制数码管 *********/
    	P2 = 0x7f ;				  
    	P0 = s[t0] ;		
    	delay(1) ;			
    	P2 = 0xbf ;				  
    	P0 = s[t1] ;		
    	delay(1) ;
    	P2 = 0xdf ;			
    	P0 = 0x40 ;			
    	delay(1) ;
    	P2 = 0xef ;			
    	P0 = s[t2] ;			  
    	delay(1) ;
    	P2 = 0xf7 ;				 
    	P0 = s[t3] ;			
    	delay(1) ;
    	P2 = 0xfb ;				 
    	P0 = 0x40 ;				
    	delay(1) ;
    	P2 = 0xfd ;				
    	P0 = s[t4] ;			 
    	delay(1) ;
    	P2 = 0xfe ;			
    	P0 = s[t5] ;		
    	delay(1) ;				
    }
    
    void KEY0()		//控制按钮2的位移
    {
    	if(key0 == 0 && c == 0)
    	{
    		c = 1 ;
    	}
    	if(key0 == 1 && c == 1)
    	{
    		c = 0 ;
    		c_1 = c_1 + 1 ;
    	}
    	if(c_1 == 4)
    	{
    		c_1 = 0 ;
    	}
    }
    
    void KEY1()		  //控制 "秒"、“分”、“时”、“天”、“月”、“年”	的加1
    {
    	switch(c_1)
    	{
    		case 1: if(b_1 == 0)
    				{
    				 	if(key1 == 0 && d == 0)
    					{
    						d = 1 ;
    					}
    					if(key1 == 1 && d == 1)
    					{
    						d = 0 ;
    						sec = sec + 1 ;
    					}
    				}
    				else if(b_1 == 1)
    				{
    					if(key1 == 0 && d == 0)
    					{
    						d = 1 ;
    					}
    					if(key1 == 1 && d == 1)
    					{
    						d = 0 ;
    						day = day + 1 ;
    					}	
    				}
    				break ;
    		case 2: if(b_1 == 0)
    				{
    					if(key1 == 0 && d == 0)
    					{
    						d = 1 ;
    					}
    					if(key1 == 1 && d == 1)
    					{
    						d = 0 ;
    						min = min + 1 ;
    					}
    				}
    				else if(b_1 == 1)
    				{
    					if(key1 == 0 && d == 0)
    					{
    						d = 1 ;
    					}
    					if(key1 == 1 && d == 1)
    					{
    						d = 0 ;
    						month = month + 1 ;
    					}
    				}
    				break ;
    		case 3: if(b_1 == 0)
    				{
    					if(key1 == 0 && d == 0)
    					{
    						d = 1 ;
    					}
    					if(key1 == 1 && d == 1)
    					{
    						d = 0 ;
    						hour = hour + 1 ;
    					}
    				}
    				else if(b_1 == 1)
    				{
    					if(key1 == 0 && d == 0)
    					{
    						d = 1 ;
    					}
    					if(key1 == 1 && d == 1)
    					{
    						d = 0 ;
    						year = year + 1 ;
    					}
    				}
    				break ;
    	}
    }
    
    void KEY2()		  //控制 "秒"、“分”、“时”、“天”、“月”、“年”	的减1
    {
    	switch(c_1)
    	{
    		case 1: if(b_1 == 0)
    				{
    				 	if(key2 == 0 && f == 0)
    					{
    						f = 1 ;
    					}
    					if(key2 == 1 && f == 1)
    					{
    						f = 0 ;
    						sec = sec - 1 ;	
    						if(sec == 255)
    						{
    							sec = 59 ;
    						}
    					}
    				}
    				else if(b_1 == 1)
    				{
    					if(key2 == 0 && f == 0)
    					{
    						f = 1 ;
    					}
    					if(key2 == 1 && f == 1)
    					{
    						f = 0 ;
    						day = day - 1 ;
    						if(day <= 1)
    						{
    							day = 1 ;
    						}
    					}
    				}
    				break ;
    		case 2: if(b_1 == 0)
    				{
    					if(key2 == 0 && f == 0)
    					{
    						f = 1 ;
    					}
    					if(key2 == 1 && f == 1)
    					{
    						f = 0 ;
    						min = min - 1 ;
    						if(min == 255)
    						{
    							min = 0 ;
    						}
    					}
    				}
    				else if(b_1 == 1)
    				{
    					if(key2 == 0 && f == 0)
    					{
    						f = 1 ;
    					}
    					if(key2 == 1 && f == 1)
    					{
    						f = 0 ;
    						month = month - 1 ;
    						if(month <= 1)
    						{
    							month = 1 ;
    						}
    					}
    				}
    				break ;
    		case 3: if(b_1 == 0)
    				{
    					if(key2 == 0 && f == 0)
    					{
    						f = 1 ;
    					}
    					if(key2 == 1 && f == 1)
    					{
    						f = 0 ;
    						hour = hour - 1 ; 
    						if(hour == 255)
    						{
    							hour = 0 ;
    						}
    					}
    				}
    				else if(b_1 == 1)
    				{
    					if(key2 == 0 && f == 0)
    					{
    						f = 1 ;
    					}
    					if(key2 == 1 && f == 1)
    					{
    						f = 0 ;
    						year = year - 1 ;
    						if(year == 255)
    						{
    							year = 0 ;
    						}
    					}
    				}
    				break ;
    	}
    }
    void KEY3()		//控制“时、分、秒”与“年、月、日”的转换
    {
    	if(key3 == 0 && b == 0)
    	{
    		b = 1 ;
    	}
    	if(key3 == 1 && b == 1)
    	{
    		b = 0 ;
    		b_1 = b_1 + 1;
    	}
    	if(b_1 == 2)
    	{ 
    		b_1 = 0 ;
    	}
    	switch(b_1)
    	{
    		case 0: display1() ;
    				break ;
    		case 1: display2() ;
    				break ;
    	}
    }
    
    void main()
    {
    	init_t0();
    	while(1)
    	{
    		KEY0();
    		KEY1();
    		KEY2();
    		KEY3();
    	}	
    }
    

    5. 元器件清单

    5.1. 仿真软件

    数码管:7SEG-MPX4-CC
    单片机:AT89C52
    按键:BUTTON
    排阻:RESPACK-8

    5.2. 实物

    名称 封装 数量
    STC89C52 PDIP-40 1
    排阻 4.7K A472J 1
    10K色环电阻 AXIAL0.5 1
    0.36寸共阴数码管 CL3631AH 2
    轻触开关 DIP-6x6x6 4
    30pF电容 RAD-0.2 2
    10uF电解电容 DIP-EC2.0X5X11 1
    11.0592MHz晶振 OSC HC-49S 1
    物联沃分享整理
    物联沃-IOTWORD物联网 » 《51单片机入门:制作一个精美的数字时钟》

    发表评论