51单片机学习笔记:可对时电子钟

本篇是对上一篇的改进,昨天学习了第4章 中的独立键盘的使用

 独立键盘拥有自己独有的IO口,所以比较简单,我上一篇写的电子钟程序只能烧程序对时,

不能手动按键对时,这肯定是最差劲的做法,所以学习了按键之后,就立马动手改进我的电子钟了

 同时改进了数码管小数点的显示,消除了叠影 

 

使用芯片STC89C52RC, 2个锁存器

6个带小数点共阴极数码管显示一个24时制时钟

没有时钟芯片,所以掉电后时间会复位

原理图为TX-1C开发板

 

==============================

最终显示的<时.分.秒>是 16.31.37  形式

 

使用3个按键,  S2  S3   S5

其中S2和S3是加减数值,S5是切换对时状态,

 

#include <reg52.h>
#include "MY51.H"

void show();
int8  shi=22;   //初识时间22:45:00  按S5键进入对时模式
int8  fen=45;
int8  miao=0;
uint8  timeFlag=0;//0计时模式,1校对时钟,2校对分钟,3校对秒钟
void main() 	
{
	startT0(1000);  //开始定时器
	while(1)
	{		
		show();		//送入数码管显示
		if(keyS5==keyDown) //按下S5键
		{
			delayms(5);//消抖处理
			if(keyS5==keyDown)
			{
                while(1)
                {
                    show();
                    if(keyS5==keyUp)//放开按钮
                    {
                        delayms(5); //消抖处理
                        if(keyS5==keyUp)
                        {
                            break;
                        }
                    }
                }
				timeFlag=(++timeFlag)%4; //按S5键进行状态切换   
				while(timeFlag)
				{
					if(timeFlag==1)
					{
                        led=0xff;
                        led7=0;       //进入对时钟模式,且打开7号指示灯                 
					}
					else if(timeFlag==2)
					{
                         led=0xff;
                         led5=0;   	 //进入校对分钟模式,且打开5号指示灯
					}
					else if(timeFlag==3)
					{
                         led=0xff;
                         led3=0;	 //进入校对秒钟模式,且打开3号指示灯
					}
	
					show();			//刷新数码管
					if(keyS2==keyDown)//S2和S3用于调整数值,加减运算
					{
						delayms(5);//消抖处理
						if(keyS2==keyDown)
						{
							if(timeFlag==1)
							{
                                shi--;
                                if(shi<0) 
                                {
                                    shi=23;
                                }                        
							}
							else if(timeFlag==2)
							{
                                fen--;
                                if(fen<0)
                                {
                                    fen=59;
                                }
							}
							else if(timeFlag==3)
							{
                                miao--;
                                if(miao<0)
                                {
                                    miao=59;
                                }
							}
							while(1)
							{
								show(); //就算S2键被按着,也要刷新数码管
								if(keyS2==keyUp)
								{
									delayms(10);
									if(keyS2==keyUp)
									{
										break;
									}
								}
							}

						}	
					}
					
					if(keyS3==keyDown)
					{
						delayms(5);//消抖处理
						if(keyS3==keyDown)
						{
							if(timeFlag==1)
							{
                                shi++;
                                if(shi>23)
                                {
                                    shi=0;
                                }                          
							}
							else if(timeFlag==2)
							{
                                fen++;
                                if(fen>59)
                                {
                                    fen=0;
                                }
							}
							else if(timeFlag==3)
							{
                                miao++;
                                if(miao>59)
                                {
                                    miao=0;
                                }
							}
							while(1)
							{
								show();
								if(keyS3==keyUp)
								{
									delayms(5);
									if(keyS3==keyUp)
									{
										break;
									}
								}
							}

						}	
					}	
					
					if(keyS5==keyDown)
					{
						delayms(5);//消抖处理
						if(keyS5==keyDown)
						{
							timeFlag=(++timeFlag)%4;//按S5键切换状态
							while(1)
							{
								show();
								if(keyS5==keyUp)
								{
									delayms(5);
									if(keyS5==keyUp)
									{
										break;
									}
								}
							}
						}	
					}	
				}
				led=0xff;  //对时结束,指示灯灭
			}	
		}
	}
}


void show()  //显示时钟
{
	uint8 oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela; //oneWela是最左边的数码管
	sixWela =miao%10;
	fiveWela=miao/10;	
	foreWela=fen%10;
	threeWela=fen/10;
	twoWela=shi%10;
	oneWela=shi/10;
	displaySMG(oneWela,twoWela,threeWela,foreWela,fiveWela,sixWela,0xf5); //0xf5是小数点的位置
}

void T0_Work()  //T0定时器调用的工作函数
{  
   miao++;
	if(miao>59)
	{
		miao=0;
		fen++;
	}

	if(fen>59)
	{
		fen=0;
		shi++;
	} 
	
	if(shi>23)
	{
		shi=0;
	}
}

 

 

#ifndef _MY51_H_
#define _MY51_H_
#include <math.h>
#include <intrins.h>

typedef int   				int16  ;
typedef int   				INT16  ;
typedef unsigned int    uint16 ;
typedef unsigned int    UINT16 ;
typedef unsigned short  uint ;
typedef unsigned short  UINT ;
typedef unsigned short  word ;
typedef unsigned short  WORD ;
typedef unsigned long   uint32 ;
typedef unsigned long   UINT32 ;
typedef unsigned long   DWORD ;
typedef unsigned long   dword ;
typedef signed long	   int32	 ;
typedef signed long	   INT32  ;
typedef float		    	    float32	 ;
typedef double		    	double64  ;
typedef signed char		int8 ;
typedef signed char 		INT8 ;
typedef unsigned char	byte ;
typedef unsigned char    BYTE 	 ;		//WINDOWS的windef.h里面是这么定义的
typedef unsigned char	uchar ;
typedef unsigned char	UCHAR ;
typedef unsigned char	UINT8 ;
typedef unsigned char	uint8 ;
typedef unsigned char	BOOL	 ;		//windows中定义BOOL为int
typedef unsigned char	bool	 ;		    //bool是c++的内置类型

#define TRUE     1
#define true     1
#define FALSE    0
#define false    0

#define open     1    //open和close用于 标志打开和关闭状态
#define OPEN     1
#define close    0
#define CLOSE    0
#define lock     0
#define start    1
#define START    1
#define stop     0
#define STOP     0
#define keyDown  0
#define keyUp    1

sbit dula =P2^6;  //段选锁存器控制  控制笔段
sbit wela =P2^7;  //位选锁存器控制  控制位置

#define led P1    //灯总线控制
sbit led0=P1^0;   //8个led灯,阴极送低电平点亮
sbit led1=P1^1;
sbit led2=P1^2;
sbit led3=P1^3;
sbit led4=P1^4;
sbit led5=P1^5;
sbit led6=P1^6;
sbit led7=P1^7;

sbit keyS2=P3^4; 	//4个独立按键
sbit keyS3=P3^5;
sbit keyS4=P3^6;
sbit keyS5=P3^7;

void displaySMG(uint8 one,uint8 two,uint8 three,uint8 four,uint8 five,uint8 six,uint8 dot); 
void delayms(uint16 ms);
void T0_Work();

void delayms(uint16 ms)  //软延时函数
{
	uint16 i,j;
	for(i=ms;i>0;i--)
	{
        for(j=113;j>0;j--)
        {}
	}
}
///////////////////////////////////////////////////////////////////////////
#define dark	0x11  //在段中,0x11是第17号元素,为0是低电平,数码管不亮
#define dotDark 0xff //小数点全暗时
uint8 code table[]= { 			//0~F外加小数点和空输出的数码管编码
 0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 3
 0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
 0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
 0x39 , 0x5e , 0x79 , 0x71 , // C D E F
 0x80 , 0x00                 // . 空     空时是第0x11号也就是第17号元素
 };

/////////////////////////////////////////////////////////////////////////////
uint8   TH0Cout=0 ;	    //初值	
uint8   TL0Cout=0 ;	   
uint16  T0IntCout=0;     //中断计数
uint16  T0IntCountAll=0; //(N-1)/65536+1;  //总中断次数
bool    bT0Delay=false;  //使用延时函数标志,初始未用
bool    bT0Over=false; 	 //中断处理函数执行结果之一

void startT0(uint32 ms)  //开启定时器
{	
	float32   	t=ms/1000.0;		   		 //定时时间
	double64    fox =11.0592*(pow(10,6));   //晶振频率
	uint32    	N=(t*fox)/12 ; 				 //定时器总计数值

	TH0Cout =(65536-N%65536)/256;      	 //装入计时值零头计数初值
	TL0Cout =(65536-N%65536)%256;
	T0IntCountAll=(N-1)/65536+1;			 //总中断次数
	TMOD=TMOD | 0x01; 						 //设置定时器0的工作方式为1
	
	EA =open;   //打开总中断
	ET0=open;   //打开定时器中断

	TH0=TH0Cout;  //定时器装入初值
	TL0=TL0Cout;
	TR0=start;	 //启动定时器
}

void delayT0(uint32 ms)		//硬延时函数,自己乱写的不好用,求指点
{
	startT0(ms);				//启动定时器
	bT0Delay=true;    		//告诉T0定时器,起用延时模式
	while(bT0Over==false);	//时间没到的话继续检测
	bT0Over=false;				//时间到了,让标志复位
}

void T0_times() interrupt 1 //T0定时器中断函数
{
	T0IntCout++;
	if(T0IntCout==T0IntCountAll)  //达到总中断次数值
	{	
		T0IntCout=0; 		 //中断次数清零,重新计时
		bT0Over=true;     //时间真的到了
		if(bT0Delay)		//本次中断是用来延时的吗
		{
			TR0=stop; 		 //如果是由延时函数开启T0的话,关闭T0
			return;
		}

		TH0=TH0Cout;   		//循环定时的话要重装初值,每次定时1秒,重装一次
		TL0=TL0Cout;
		T0_Work();     		//工作函数
	}
}

////////////////////////////////////////////////////////////////////////////////
void displaySMG(uint8 oneWela,uint8 twoWela,uint8 threeWela,uint8 fourWela,uint8 fiveWela,uint8 sixWela,uint8 dot)
{		//控制6位数码管显示函数,不显示的位用参数 dark
		P0=0;
		dula=1;
		dula=0;	 //段选数据清空并锁定
//////////////////////////
		P0=0xff; //送位数据前关闭所有显示
		wela=1;
		P0=0xfe;
		wela=0;

		P0=0;  	//低电平输到数码管阳极,避免数码管吴亮
      dula=1;
		P0=table[oneWela]|((0x01&dot)?0x00:0x80);   //送段数据,小数点可选显示		dula=0;
		delayms(2);
/////////////////////////
		P0=0xff;
		wela=1;
		P0=0xfd;
		wela=0;

		P0=0;
		dula=1;
		P0=table[twoWela]|((0x02&dot)?0x00:0x80);
		dula=0;
		delayms(2);
/////////////////////////
		P0=0xff;
		wela=1;
		P0=0xfb;
		wela=0;
		P0=0;
		dula=1;
		P0=table[threeWela]|((0x04&dot)?0x00:0x80);
		dula=0;
		delayms(2);
/////////////////////////
		P0=0xff;
		wela=1;
		P0=0xf7;
		wela=0;

		P0=0;
		dula=1;
		P0=table[fourWela]|((0x08&dot)?0x00:0x80);
		dula=0;
		delayms(2);
/////////////////////////
		P0=0xff;
		wela=1;
		P0=0xef;
		wela=0;

		P0=0;
		dula=1;
		P0=table[fiveWela]|((0x10&dot)?0x00:0x80);
		dula=0;
		delayms(2);
/////////////////////////
		P0=0xff;
		wela=1;
		P0=0xdf;
		wela=0;

		P0=0;
		dula=1;
		P0=table[sixWela]|((0x20&dot)?0x00:0x80);
		dula=0;
		delayms(2);
}

#endif

 

你可能感兴趣的:(单片机,时钟)