基于51单片机的多功能秒表(校赛作品)

设计方案

设计基于LCD1602的多功能秒表,要满足在不间断计时的同时进行其他操作,由此可以联想出定时器的中断系统是其最好的选择。通过定时器中断函数的设计,可以让程序每隔一段时间进行一次计数,让LCD1602在不间断显示时间的同时,进行按键检测与计时的需要。


在代码具体时间中,为了避免代码过长、累赘、麻烦,本小组使用了模块化编程的思想,将定时器延迟函数、LCD1602操作函数、按键检测函数、延迟函数分别进行了模块化处理,这样不仅可以让主函数代码简短不少,而且可以使逻辑思维更加清晰,不再受基础函数的改动而烦恼。


在设计日历功能时,考虑到实际的电子表在平常状态下,不论是计时还是闹钟模式,日历中的时间计数都是未曾中断的,因此设计日历模式函数时,一旦日历模式被首次进入,日历中的计时就不会停止,除非重新设定日历时间。而在设定日历模式中,由于能力的不足与串口的关联性太强,本小组采用了让其在旁显示操作第几位的做法,用另一种方法,让操作者可以清晰的知道自己正在更改日历中的哪个数值。借鉴于日历模式是电子表的中心,本小组将其他模式的接口统统通向日历模式,这样在日历模式下,可以随意进入任意一个其他模式中。


在设计计时模式时,考虑到真正的电子表都有开始/暂停按键,所以本小组也参照该设计,设计了一个按键控制计时的开始与暂停。并且根据题目要求设计出了一个清零并暂停的按键满足题目需要。再次由于题目的需求,本小组设计出了检查保存结果模式,来检查可被保存的五次时间。考虑到真正的电子表和实际的按键数量,本小组并未在日历函数中安装此功能,而是将该模式接口移动到计时模式上,并且由于单片机内存有限,故酌情考虑设计了5个保存时间。
在设计倒计时模式时,由于题目本身的需要,本小组决定让操作者自己先设定倒计时的时间,再进行倒计时操作,这样能增加倒计时模式的可用性。倒计时模式仍支持检查保存结果模式,因为倒计时模式的底层逻辑与计时模式基本相同,区别在于倒计时模式可以自己设定倒计时的初始时间,而计时模式将这一功能代替为开始/暂停。倒计时模式的设定模式与日历设定模式的底层原理相同。倒计时模式与计时模式的保存结果是公用的,一是为了防止代码过长导致的操作繁琐与累赘,二是考虑到单片机的内存大小实在有限。


在设计检查保存结果模式中,设计了5个可被保存的时间。由于独立按键的缺少与代码实现的复杂度,只设计了其能一键全部清零的功能。其功能相对单一,并且只提供了前往日历功能的接口,因为日历功能下,可以前往其他任意功能,可以增加便捷性。
在实际代码中,发现日历功能、计时功能、倒计时功能的计时可能可以并被允许同时进行,故在定时器中断函数中本小组设计了3个标志变量来检查其是否能被统计计数.因为实际使用中,并不能保证程序从整毫秒开始计时,并且计时与倒计时要求的精度都比较高,所以才采用了此种方法,来保证3个功能能同时在后台进行。
总结来说,在具体实现上,代码保证的基本原则就是统一性原则,这样利于编程者的编程方便,也利于后来人的代码阅读理解,代码风格的同一可以让逻辑更加清晰,使得代码更加可读,也让该程序更好实现。


ps.51单片机的运行不太理想啊,它它它它……有点慢啊,可能是我的中断函数里写的语句太多了,不论怎么样,这其实是一个学习性的代码,参考即可啦(* ̄3 ̄)╭

MatrixKey.h

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char MatrixKey();

#endif

MatrixKey.c

#include<reg51.h>
#include<Delayms.h>
/**
  * @brief  3*4矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
	          如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey(){
	unsigned char KeyNumber=0;
	
	P3=0xFF;
	T1=0; 
	if(RXD==0){ Delayms(20); while(RXD==0); Delayms(20); KeyNumber=1; }
	if(TXD==0){ Delayms(20); while(TXD==0); Delayms(20); KeyNumber=4; }
	if(INT0==0){ Delayms(20); while(INT0==0); Delayms(20); KeyNumber=7; }
	if(INT1==0){ Delayms(20); while(INT1==0); Delayms(20); KeyNumber=10; }
	
	P3=0xFF;
	WR=0; 
	if(RXD==0){ Delayms(20); while(RXD==0); Delayms(20); KeyNumber=2; }
	if(TXD==0){ Delayms(20); while(TXD==0); Delayms(20); KeyNumber=5; }
	if(INT0==0){ Delayms(20); while(INT0==0); Delayms(20); KeyNumber=8; }
	if(INT1==0){ Delayms(20); while(INT1==0); Delayms(20); KeyNumber=11; }
	
	
	P3=0xFF;
	RD=0; 
	if(RXD==0){ Delayms(20); while(RXD==0); Delayms(20); KeyNumber=3; }
	if(TXD==0){ Delayms(20); while(TXD==0); Delayms(20); KeyNumber=6; }
	if(INT0==0){ Delayms(20); while(INT0==0); Delayms(20); KeyNumber=9; }
	if(INT1==0){ Delayms(20); while(INT1==0); Delayms(20); KeyNumber=12; }
	
	return KeyNumber;
}

Delayms.h

#ifndef __DELAYMS_H__
#define __DELAYMS_H__

void Delayms(unsigned int x);

#endif

Delayms.c

void Delayms(unsigned int x)		//@11.0592MHz
{
	unsigned char i, j;

	while(x--){
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

LCD1602.c

#include <REGX52.H>

//引脚配置:

sbit LCD_RS=P3^5;
sbit LCD_EN=P3^4;
//sbit LCD_RW;

#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
//	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
//	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

#endif

Timer0.c

#include<reg51.h>

/**
  * @brief  定时器0初始化,1毫秒@11.0592MHz
	* @param  无
	* @retval 无
	*/
void Timer0_Init(void){ //定时器初始化 
	//TMOD=0x01; //0000 0001 设置模式
	TMOD&=0xF0; //把TMOD的低四位清零,高四位保持不变
	TMOD|=0x01; //把TMOD的最低位置1,高四位保持不变
	//不可位寻址寄存器 不能 将每一位单独赋值
	//  可位寻址寄存器   能 将每一位单独赋值
	TF0=0; //中断溢出标志位 TF0=1 表示 产生中断
	TR0=1; //定时器是否开启
	TL0=0x66;		
	TH0=0xFC;
	ET0=1;
	EA=1;
	PT0=0;
}

/*
定时器中断函数模板
void Timer0_Routine() interrupt 1{
	static unsigned int T0Count;
	TL0=0x66;		
	TH0=0xFC;
	++T0Count;
	if(T0Count>=1000){
		T0Count=0;
		led1=~led1;
	}
}
*/

mian.c

#include<reg51.h>
#include<Delayms.h>
#include<MatrixKey.h>
#include<LCD1602.h>
#include<Timer0.h>

sbit beep=P2^3;

unsigned char Min,Sec,Ms; //分,秒,毫秒
unsigned char CountFlag;  //CountFlag --> 0 表示非计时状态,1 表示计时状态
unsigned char KeyNum;     //矩阵键盘键码
unsigned char SaveMin[6],SaveSec[6],SaveMs[6],SaveCount,CheckCount;
unsigned int CYear=2020,CMonth=2,CDay=29,CHour=23,CMin=58,CSec=30,CFlag;
unsigned char CSettmp,CSettmp2,CSetFlag;
unsigned char DMin,DSec,DMs,DownFlag,Dtmp;

void StartMemu();
void TimeMode();
void CheckMode();
void CalendarMode();
void CountdownMode();
void CSettingMode();
void DownSetting();

void main(){
//初始化LCD1602和定时器----
	LCD_Init();
	Timer0_Init();
//-------------------------
	while(1) StartMemu();
}

/**
  * StartMemu      开始菜单
  * s9(KeyNum=3)   日历功能
  * s13(KeyNum=6)  计时功能
  * s17(KeyNum=9)  倒计时功能
  */
void StartMemu(){
	LCD_ShowString(1,1,"Work  ");
	LCD_ShowString(2,1,"For Contest     ");
	while(1){
		KeyNum=MatrixKey();
		if(KeyNum==3)  CalendarMode();
		if(KeyNum==6)  TimeMode();
		if(KeyNum==9)  CountdownMode();
	}
}


/**
  * CalendarMode   日历模式
  * s9(KeyNum=3)   更换模式(计时模式)
  * s13(KeyNum=6)  更换模式(倒计时模式)
  * s17(KeyNum=9)  更换模式(检查保存结果模式)
  * s21(KeyNum=12) 更改日历
  */
void CalendarMode(){
	CFlag=1;
	CSetFlag=0;
	LCD_ShowString(1,1,"    -  -        ");
	LCD_ShowString(2,1,"  :  :          ");
	while(1){
		LCD_ShowNum(1,1,CYear,4);
		LCD_ShowNum(1,6,CMonth,2);
		LCD_ShowNum(1,9,CDay,2);
		LCD_ShowNum(2,1,CHour,2);
		LCD_ShowNum(2,4,CMin,2);
		LCD_ShowNum(2,7,CSec,2);
		KeyNum=MatrixKey();
		if(KeyNum==3)  TimeMode();
		if(KeyNum==6)  CountdownMode();
		if(KeyNum==9)  CheckMode();
		if(KeyNum==12) CSettingMode();
	}
}


/**
  * CSettingMode   更改日历模式
  * s9(KeyNum=3)   确认并返回日历模式
  * s13(KeyNum=6)  +1
  * s17(KeyNum=9)  -1
	* s21(KeyNum=12) 换位
  */
void CSettingMode(){
	CFlag=0;
	CSetFlag=1;
	CSettmp=1;
	LCD_ShowString(2,10,"Setting");
	while(1){
		LCD_ShowNum(1,16,CSettmp,1);
		LCD_ShowNum(1,1,CYear,4);
		LCD_ShowNum(1,6,CMonth,2);
		LCD_ShowNum(1,9,CDay,2);
		LCD_ShowNum(2,1,CHour,2);
		LCD_ShowNum(2,4,CMin,2);
		LCD_ShowNum(2,7,CSec,2);
		KeyNum=MatrixKey();
		if(KeyNum==3)  CalendarMode();
		if(KeyNum==6){
			if(CSettmp==1) ++CYear;
			if(CSettmp==2){ ++CMonth; if(CMonth==13) CMonth=1; }
			if(CSettmp==3){
				++CDay;
				if((CMonth==1|CMonth==3|CMonth==5|CMonth==7|CMonth==8|CMonth==10|CMonth==12)&&CDay==32) CDay=1;
				if((CMonth==4|CMonth==6|CMonth==9|CMonth==11)&&CDay==31) CDay=1;
				if(((CYear%4==0&&CYear%100!=0)||CYear%400==0)&&CMonth==2&&CDay==30) CDay=1;
				if(!((CYear%4==0&&CYear%100!=0)||CYear%400==0)&&CMonth==2&&CDay==29) CDay=1;
			}
			if(CSettmp==4) CHour=(CHour+1)%24;
			if(CSettmp==5) CMin=(CMin+1)%60;
			if(CSettmp==6) CSec=(CSec+1)%60;
		}
		if(KeyNum==9){
			if(CSettmp==1&&CYear) --CYear;
			if(CSettmp==2){ --CMonth; if(CMonth==0) CMonth=12; }
			if(CSettmp==3){
				--CDay;
				if((CMonth==1|CMonth==3|CMonth==5|CMonth==7|CMonth==8|CMonth==10|CMonth==12)&&CDay==0) CDay=31;
				if((CMonth==4|CMonth==6|CMonth==9|CMonth==11)&&CDay==0) CDay=30;
				if(((CYear%4==0&&CYear%100!=0)||CYear%400==0)&&CMonth==2&&CDay==0) CDay=29;
				if(!((CYear%4==0&&CYear%100!=0)||CYear%400==0)&&CMonth==2&&CDay==0) CDay=28;
			}
			if(CSettmp==4){ --CHour; if(CHour==-1) CHour=23; }
			if(CSettmp==5){ --CMin; if(CMin==-1) CMin=59; }
			if(CSettmp==6){ --CSec; if(CSec==-1) CSec=59; }
		}
		if(KeyNum==12){ ++CSettmp; CSettmp2=0; if(CSettmp==7) CSettmp=1; }
	}
}



/**
	* RunMode        计时模式
  * s9(KeyNum=3)   更换模式(检查保存结果模式)
	* s13(KeyNum=6)  清零并暂停操作
	* s17(KeyNum=9)  继续/暂停操作
	* s21(KeyNum=12) 保存当前计时功能,可保存5个
  */
void TimeMode(){
	//CountFlag=1;
	LCD_ShowString(1,1,"  :  :     S: /5");
	LCD_ShowString(2,1,"Now Timing      ");
	while(1){
		LCD_ShowNum(1,1,Min,2);
		LCD_ShowNum(1,4,Sec,2);
		LCD_ShowNum(1,7,Ms,2);
		LCD_ShowNum(1,14,SaveCount,1);
		KeyNum=MatrixKey();
		if(KeyNum==3) CheckMode();
		if(KeyNum==6){ Min=Sec=Ms=0; CountFlag=0; }
		if(KeyNum==9) CountFlag^=1;
		if(KeyNum==12&&SaveCount<5){
			++SaveCount;
			SaveMin[SaveCount]=Min;
			SaveSec[SaveCount]=Sec;
			SaveMs[SaveCount]=Ms;
		}
	}
}

/**
  * CountdownMode  倒计时模式
  * s9(KeyNum=3)   更换模式(检查保存结果模式)
  * s13(KeyNum=6)  清零并停掉蜂鸣器操作
  * s17(KeyNum=9)  设定操作
	* s21(KeyNum=12) 保存当前计时功能,可保存5个(与计时模式共用)
  */
void CountdownMode(){
	LCD_ShowString(1,1,"  :  :     S: /5");
	LCD_ShowString(2,1,"Now Downing     ");
	while(1){
		LCD_ShowNum(1,1,DMin,2);
		LCD_ShowNum(1,4,DSec,2);
		LCD_ShowNum(1,7,DMs,2);
		LCD_ShowNum(1,14,SaveCount,1);
		if(DownFlag==1&&DMin==0&&DSec==0&&DMs==0){ DownFlag=0; beep=0; }
		KeyNum=MatrixKey();
		if(KeyNum==3) CheckMode();
		if(KeyNum==6){ 
			DMin=DSec=DMs=0; DownFlag=0; beep=1; 
		}
		if(KeyNum==9) DownSetting();
		if(KeyNum==12&&SaveCount<5){
			++SaveCount;
			SaveMin[SaveCount]=DMin;
			SaveSec[SaveCount]=DSec;
			SaveMs[SaveCount]=DMs;
		}
	}
}

/**
  * DownSetting  倒计时设定
  * s9(KeyNum=3)   确认并返回倒计时模式
  * s13(KeyNum=6)  +1
  * s17(KeyNum=9)  -1
	* s21(KeyNum=12) 换位
  */
void DownSetting(){
	beep=1;
	DownFlag=0;
	Dtmp=1;
	LCD_ShowString(1,1,"  :  :          ");
	LCD_ShowString(2,1,"Now DownSetting ");
	while(1){
		LCD_ShowNum(1,1,DMin,2);
		LCD_ShowNum(1,4,DSec,2);
		LCD_ShowNum(1,7,DMs,2);
		LCD_ShowNum(1,16,Dtmp,1);
		KeyNum=MatrixKey();
		if(KeyNum==3){ DownFlag=1; CountdownMode(); }
		if(KeyNum==6){ 
			if(Dtmp==1){ ++DMin; if(DMin>99) DMin=0; }
			if(Dtmp==2){ ++DSec; if(DSec>59) DSec=0; }
			if(Dtmp==3){ ++DMs; if(DMs>99) DMs=0; }
		}
		if(KeyNum==9){ 
			if(Dtmp==1){ --DMin; if(DMin==-1) DMin=99; }
			if(Dtmp==2){ --DSec; if(DSec==-1) DSec=59; }
			if(Dtmp==3){ --DMs; if(DMs==-1) DMs=99; }
		}
		if(KeyNum==12){ ++Dtmp; if(Dtmp>3) Dtmp=1; }
	}
}

/**
  * CheckMode      检查保存结果模式
  * s9(KeyNum=3)   为更换模式(日历模式)
	* s13(KeyNum=6)  上一个
  * s17(KeyNum=9)  下一个
  * s21(KeyNum=12) 全部清空
  */
void CheckMode(){
	LCD_ShowString(1,1,"  :  :     C: / ");
	LCD_ShowString(2,1,"Now Checking    ");
	if(SaveCount) CheckCount=1; else CheckCount=0;
	while(1){
		LCD_ShowNum(1,1,SaveMin[CheckCount],2);
		LCD_ShowNum(1,4,SaveSec[CheckCount],2);
		LCD_ShowNum(1,7,SaveMs[CheckCount],2);
		LCD_ShowNum(1,14,CheckCount,1);
		LCD_ShowNum(1,16,SaveCount,1);
		KeyNum=MatrixKey();
		if(KeyNum==3) CalendarMode();
		if(KeyNum==6&&CheckCount>1&&SaveCount!=0) --CheckCount;
		if(KeyNum==9&&CheckCount<SaveCount) ++CheckCount;
		if(KeyNum==12){
			SaveCount=0;
			CheckCount=0;
		}
	}
}


void Timer0_Routine() interrupt 1{
	static unsigned int T0Count;
	static unsigned int CCount;
	static unsigned int DownCount;
	TL0=0x66;		
	TH0=0xFC;
	if(DownFlag==1){
		++DownCount;
		if(DownCount>=10){
			DownCount=0;
			if(DMs) --DMs;
			if(DMs==0&&(DSec||DMin)){
				DMs=99;
				if(DSec>0) --DSec;
				else if(DSec==0&&DMin){
					DSec=59;
					--DMin;
				}
			}
		}
	}
//如果处于即使状态每隔10毫秒进行计时---
	if(CountFlag==1){
		++T0Count;
		if(T0Count>=10){
			T0Count=0;
			++Ms;
			if(Ms>99){
				Ms=0;
				++Sec;
				if(Sec>59){
					Sec=0;
					++Min;
					if(Min>99)
						Min=0;
				}
			}
		}
	}
//-------------------------------------
//如果处于即使状态每隔1秒进行计时---
	if(CFlag==1){
		++CCount;
		if(CCount>=1000){
			CCount=0;
			++CSec;
			if(CSec>59){
				CSec=0;
				++CMin;
				if(CMin>59){
					CMin=0;
					++CHour;
					if(CHour>23){
						CHour=0;
						++CDay;
						if(CMonth==12&&CDay==32){
							CMonth=1; CDay=1;
							++CYear;
						}
						if((CMonth==1|CMonth==3|CMonth==5|CMonth==7|CMonth==8|CMonth==10)&&CDay==32){
							CDay=1;
							++CMonth;
						}
						if((CMonth==4|CMonth==6|CMonth==9|CMonth==11)&&CDay==31){
							CDay=1;
							++CMonth;
						}
						if(((CYear%4==0&&CYear%100!=0)||CYear%400==0)&&CMonth==2&&CDay==30){
							CDay=1;
							++CMonth;
						}
						if(!((CYear%4==0&&CYear%100!=0)||CYear%400==0)&&CMonth==2&&CDay==29){
							CDay=1;
							++CMonth;
						}
					}
				}
			}
		}
	}
//-------------------------------------
}
原文地址:https://www.cnblogs.com/Potrem/p/51_Clock_1.html