Electronic clock based on STC89C52 single chip microcomputer

Hedy · Dasenic Nov 07,2024 4

Realization of electronic clock based on STC89C52 single chip microcomputer


Program code:

#include 
#include 		
#define uchar unsigned char
#define uint unsigned int
//  -----Digital tube------
sbit smg0=P2^2;	//Position selection
sbit smg1=P2^3;
sbit smg2=P2^4;								   
#define duan P0	//Segment Selection
    // Without decimal point
uchartable[]={~0xC0,~0xF9,~0xA4,~0xB0,~0x99,~0x92,~0x82,~0xF8,~0x80,~0x90,~0xBF;
// With decimal point
uchar table_dot[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,~0xBF};

// -------------Timer-------------------
#define T0time 46070
uchar count=0;	//Timing 1 second T0 needs to cycle times

//---------Global Flags ------------
//Indicates which interface is currently displayed.
uchar whereNow;	//0: Clock interface; 1: Time adjustment interface; 2: Calendar interface;
sbit K1=P3^1; 	
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;

//The selected position flashes the count mark
#define shanCount 128
uchar blankCount;//Blank display Count mark
uchar normalCount;//Normal display Count mark

//------------------- clock ------------
uchar shi=0,fen=0,miao=0;	//Clock hours, minutes, seconds Initial data

//----------------------- Time Adjustment-------------------
uchar clockSetLocation;//The selected position of the record adjustment is 0, does not flash, and the plus and minus buttons cannot be used

//------------------- calendar -------------------
uchar cldSetLocation;//Records the selected location when setting the alarm
uint year=2023;	//Calendar Year Initial Data
uchar month=11,day=11;//Calendar Month, Day Initial Data
#define minYear 2020
#define maxYear 2050
//Set the upper and lower limits of the year that can be displayed on the calendar
bit isLeapYear;	//Indicates whether it is a leap year: 1 for yes; 0 for no.
bit cldSetOrNot;//Indicates whether the calendar is being set
uchar commonYearTable[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//Record the number of days in each month in a common year
uchar leapYearTable[]={0,31,29,31,30,31,30,31,31,30,31,30,31};	//Record the number of days in each month in a leap year
//The first element is just to make the subscript correspond to the month, that is, January corresponds to index[1]
//--------------------------------------------------------------------------------

void delay()	//Short delay
{
	uchar i;
	for(i=0;i<128;i++);
}

void delay_10ms(uchar c)   //Keyboard delay function 10ms
{
    uchar a,b;
    for(;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

void smg(uchar wei,uchar number)//A single position of the digital tube lights up
{
	switch(wei)//Decode and bit select
	{
	case 7:smg2=1;smg1=1;smg0=1;break;
		case 6:smg2=1;smg1=1;smg0=0;break;
	case 5:smg2=1;smg1=0;smg0=1;break;
	case 4:smg2=1;smg1=0;smg0=0;break;
	case 3:smg2=0;smg1=1;smg0=1;break;
	case 2:smg2=0;smg1=1;smg0=0;break;
	case 1:smg2=0;smg1=0;smg0=1;break;
	case 0:smg2=0;smg1=0;smg0=0;break;
	}
	duan=number;//Segment Selection
	delay();//Short delay
	duan=0x00;//Vanish
}

//-----------------------Timer T0 initialization----------------------
void timer0_initial(){
	TMOD=0x01;
	TH0=(65536-T0time)/256;//The crystal oscillator is 11.0592MHZ
	TL0=(65536-T0time)%256;
	EA=1;
	ET0=1;
	TR0=1;
	TR1=0;
}


//----------------------Determine whether it is a leap year-----------------------
void is_leap_year(){
	if((year%4==0 && year%100!=0) || (year%400==0))
		isLeapYear=1;
	else
		isLeapYear=0;
}

//----------------------Interrupt service function--------------------
void serviceTimer0() interrupt 1{
	TH0=(65536-T0time)/256;//Timer reassignment
	TL0=(65536-T0time)%256;
	count++;//Timer count flag + 1
	if(20==count)//When the timer reaches 20 times, the second increases by 1.
	{
		miao++;
		count=0;//Timer count reset
	}
	if(60==miao)//When the second count reaches 60 times, the minute +1
	{
		fen++;
		miao=0;//Reset the seconds count
	}
	if(60==fen)//When the count reaches 60 times, the hour is increased by 1
	{
		shi++;
		fen=0;//Clear minute count
	}
	if(24==shi)//When the hour count reaches 24 times, +1 per day
	{	 	
		day++;
		shi=0;//Hour count reset
	}	
	if(0==isLeapYear)//If it is a normal year
	{	
		if(day>commonYearTable[month])
		{
			 day=1;//If the day count exceeds the number of days in this month, it becomes 1
			 month++;
		}
	}else			//If it is a leap year
	{
		if(day>leapYearTable[month])
		{
			 day=1;//If the day count exceeds the number of days in this month, it becomes 1
			 month++;
		}
	}		
	if(month>12)
	{
		month=1;//If the month count exceeds 12, it becomes 1
		year++;
	}
	if(year>maxYear)
	{
		year=minYear;//If the year count exceeds a certain limit, it becomes the minimum year
	}
}

//-------------------------Digital tube dynamic display clock interface -------------------
void clock_display(){
	//Tens of the hour
		//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
		if(1==clockSetLocation&&blankCount>0)
		{
			smg(7,0x00);
			blankCount--;
		}
		//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
		else if(1==clockSetLocation&&normalCount>0)
		{
			smg(7,table[shi/10]);
			normalCount--;
		}else if(1==clockSetLocation)
		{
			blankCount=shanCount;//Flashing logo initialization
			normalCount=shanCount;	
		}else
		smg(7,table[shi/10]);

	//The unit digit of the hour
		//If this position is being adjusted and the flashing blank count is not 0, this position will continue to be blank
		if(1==clockSetLocation&&blankCount>0)
		{
			smg(6,0x00);
			blankCount--;
		}
		//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
		else if(1==clockSetLocation&&normalCount>0)
		{
			smg(6,table[shi%10]);
			normalCount--;
		}else if(1==clockSetLocation)
		{
			blankCount=shanCount;//Flashing logo initialization
			normalCount=shanCount;	
		}else
		smg(6,table[shi%10]);

	//-	
		smg(5,table[10]);

	// Tens place
		//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
		if(2==clockSetLocation&&blankCount>0)
		{
			smg(4,0x00);
			blankCount--;
		}
		//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
		else if(2==clockSetLocation&&normalCount>0)
		{
			smg(4,table[fen/10]);
			normalCount--;
		}else if(2==clockSetLocation)
		{
			blankCount=shanCount;//Flashing logo initialization
			normalCount=shanCount;	
		}else
		smg(4,table[fen/10]);

	//The unit of the minute
		//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
		if(2==clockSetLocation&&blankCount>0)
		{
			smg(3,0x00);
			blankCount--;
		}
		//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
		else if(2==clockSetLocation&&normalCount>0)
		{
			smg(3,table[fen%10]);
			normalCount--;
		}else if(2==clockSetLocation)
		{
			blankCount=shanCount;//Flashing logo initialization
			normalCount=shanCount;	
		}else
		smg(3,table[fen%10]);

	//-	
		smg(2,table[10]);

	//Tens of seconds
		//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
		if(3==clockSetLocation&&blankCount>0)
		{
			smg(1,0x00);
			blankCount--;
		}
		//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
		else if(3==clockSetLocation&&normalCount>0)
		{
			smg(1,table[miao/10]);
			normalCount--;
		}else if(3==clockSetLocation)
		{
			blankCount=shanCount;//Flashing logo initialization
			normalCount=shanCount;	
		}else
		smg(1,table[miao/10]);

	//Units of seconds
		//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
		if(3==clockSetLocation&&blankCount>0)
		{
			smg(0,0x00);
			blankCount--;
		}
		//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
		else if(3==clockSetLocation&&normalCount>0)
		{
			smg(0,table[miao%10]);
			normalCount--;
		}else if(3==clockSetLocation)
		{
			blankCount=shanCount;//Flashing logo initialization
			normalCount=shanCount;	
		}else
		smg(0,table[miao%10]);
}

//--------------------------Time Adjustment -------------------
void clock_set(){
	if(0==K1 && 0==whereNow)	//If you press the time adjustment button K1 in the clock interface
	{
		delay_10ms(3);//Debounce
		if(0==K1)//Check the button status again
		{	
			while(0==K1);//Long press to wait
			delay_10ms(3);//Debounce
			whereNow=1;
			clockSetLocation=1;
			TR0=0;
		}
	}
	if(1==whereNow)	//Enter the time adjustment interface, and the 4 independent buttons become time adjustment related buttons
	{
		if(0==K1)//If you press K1: adjust the position
		{
			delay_10ms(3);//Debounce
			if(0==K1)//Check the button status again
			{	 
				while(0==K1);//Long press to stay here
				delay_10ms(3);//Debounce
				clockSetLocation++;//Position marker +1
				if(clockSetLocation>3)clockSetLocation=1;
			}
		}

			if(1==clockSetLocation)//Add and subtract hours
			{
				if(0==K2)//Press K2: Number -1
				{
					delay_10ms(3);//Debounce
					if(0==K2)//Check the button status again
					{	 
						while(0==K2);//Long press to stay here
						delay_10ms(3);//Debounce
						if(0==shi)shi=24;
						shi--;
					}	
				}
				if(0==K3)//Press K3: Number +1
				{
					delay_10ms(3);//Debounce
					if(0==K3)//Check the button status again
					{	 
						while(0==K3);//Long press to stay here
						delay_10ms(3);//Debounce
						shi++;
						if(24==shi)shi=0;
					}	
				}
			}

			if(2==clockSetLocation)//Add and subtract points
			{
				if(0==K2)//Press K2: Number -1
				{
					delay_10ms(3);//Debounce

					if(0==K2)//Check the button status again
					{	 
						while(0==K2);//Long press to stay here
						delay_10ms(3);//Debounce
						if(0==fen)fen=60;
						fen--;
					}	
				}
				if(0==K3)//Press K3: Number +1
				{
					delay_10ms(3);//Debounce
					if(0==K3)//Check the button status again
					{	 
						while(0==K3);//Long press to stay here
						delay_10ms(3);//Debounce
						fen++;
						if(60==fen)fen=0;
					}	
				}
			}

			if(3==clockSetLocation)//Add and subtract seconds
			{
				if(0==K2)//Press K2: Number -1
				{
					delay_10ms(3);//Debounce
					if(0==K2)//Check the button status again
					{	 
						while(0==K2);//Long press to stay here
						delay_10ms(3);//Debounce
						if(0==miao)miao=60;
						miao--;
					}	
				}
				if(0==K3)//Press K3: Number +1
				{
					delay_10ms(3);//Debounce
					if(0==K3)//Check the button status again
					{	 
						while(0==K3);//Long press to stay here
						delay_10ms(3);//Debounce
						miao++;
						if(60==miao)miao=0;
					}	
				}
			}	
	 
	if(0==K4)//If K4 is pressed: confirm and exit the time adjustment mode, then return to the clock interface
   	{
		delay_10ms(3);//Debounce
		if(0==K4)//Check the button status again
		{	 
			while(0==K4);//Long press to stay here
			delay_10ms(3);//Debounce
			clockSetLocation=0;
			whereNow=0;
			TR0=1;
		}
	} 
	}
}


//------------------------Digital tube dynamic display calendar interface-------------------
void cld_display(){
//Thousands of the year
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(1==cldSetLocation&&blankCount>0)
	{
		smg(7,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(1==cldSetLocation&&normalCount>0)
	{
		smg(7,table[year/1000]);
		normalCount--;
	}else if(1==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(7,table[year/1000]);
//Hundreds of the year
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(1==cldSetLocation&&blankCount>0)
	{
		smg(6,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(1==cldSetLocation&&normalCount>0)
	{
		smg(6,table[year/100%10]);
		normalCount--;
	}else if(1==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(6,table[year/100%10]);
//Tens of the year
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(1==cldSetLocation&&blankCount>0)
	{
		smg(5,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(1==cldSetLocation&&normalCount>0)
	{
		smg(5,table[year%100/10]);
		normalCount--;
	}else if(1==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(5,table[year%100/10]);
//Year digits
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(1==cldSetLocation&&blankCount>0)
	{
		smg(4,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(1==cldSetLocation&&normalCount>0)
	{
		smg(4,table_dot[year%10]);
		normalCount--;
	}else if(1==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(4,table_dot[year%10]);
//Tenth digit of the month
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(2==cldSetLocation&&blankCount>0)
	{
		smg(3,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(2==cldSetLocation&&normalCount>0)
	{
		smg(3,table[month/10]);
		normalCount--;
	}else if(2==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(3,table[month/10]);
//Month's digit
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(2==cldSetLocation&&blankCount>0)
	{
		smg(2,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(2==cldSetLocation&&normalCount>0)
	{
		smg(2,table_dot[month%10]);
		normalCount--;
	}else if(2==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(2,table_dot[month%10]);
//Tens of the day
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(3==cldSetLocation&&blankCount>0)
	{
		smg(1,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(3==cldSetLocation&&normalCount>0)
	{
		smg(1,table[day/10]);
		normalCount--;
	}else if(3==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(1,table[day/10]);
//Units of the day
	//If the position is being adjusted and the blink blank count is not 0, the position continues to be blanked.
	if(3==cldSetLocation&&blankCount>0)
	{
		smg(0,0x00);
		blankCount--;
	}
	//If the position is being adjusted and the flash normal count is not 0, the position continues to display normally.
	else if(3==cldSetLocation&&normalCount>0)
	{
		smg(0,table_dot[day%10]);
		normalCount--;
	}else if(3==cldSetLocation)
	{
		blankCount=shanCount;//Flashing logo initialization
		normalCount=shanCount;	
	}else
	smg(0,table_dot[day%10]);	
}

//----------------------Calendar Settings------------------------
void cld_set()
{
	if(0==whereNow && 0==K3)//If you press the calendar button K3 on the clock interface
	{
		delay_10ms(3);//Debounce
		if(0==K3)//Check the button status again
		{	
			while(0==K3);//Long press to wait
			delay_10ms(3);//Debounce
			whereNow=3;
		}
	}
	
	if(3==whereNow)//If you are in the calendar interface, the four independent buttons will become calendar-related buttons.
	{
		if(0==K1)//If you press K1: adjust the position
		{
			delay_10ms(3);//Debounce
			if(0==K1)//Check the button status again
			{	 
				while(0==K1);//Long press to stay here
				delay_10ms(3);//Debounce
				cldSetLocation++;//Position marker +1
				if(cldSetLocation>3)cldSetLocation=1; 	
			}
		}		

			if(1==cldSetLocation)//Add and subtract years
			{
				if(0==K2)//Press K2: Number -1
				{
					delay_10ms(3);//Debounce
					if(0==K2)//Check the button status again
					{	 
						while(0==K2);//Long press to stay here
						delay_10ms(3);//Debounce
						if(minYear==year)year=minYear+1;//Set the calendar year to the minimum and it cannot be reduced any further
						year--;
					}	
				}
				if(0==K3)//Press K3: Number +1
				{
					delay_10ms(3);//Debounce
					if(0==K3)//Check the button status again
					{	 
						while(0==K3);//Long press to stay here
						delay_10ms(3);//Debounce
						year++;
						if(maxYear+1==year)year=maxYear;//Set the calendar year to the maximum limit and no more can be added
					}	
				}
			}

			if(2==cldSetLocation)//Add or subtract months
			{
				if(0==K2)//Press K2: Number -1
				{
					delay_10ms(3);//Debounce
					if(0==K2)//Check the button status again
					{	 
						while(0==K2);//Long press to stay here
						delay_10ms(3);//Debounce
						if(1==month)month=13;
						month--;
					}	
				}
				if(0==K3)//Press K3: Number +1
				{
					delay_10ms(3);//Debounce
					if(0==K3)//Check the button status again
					{	 
						while(0==K3);//Long press to stay here
						delay_10ms(3);//Debounce
						month++;
						if(13==month)month=1;
					}	
				}
			}

			if(3==cldSetLocation)//Add and subtract days
			{
				if(0==K2)//Press K2: Number -1
				{
					delay_10ms(3);//Debounce
					if(0==K2)//Check the button status again
					{	 
						while(0==K2);//Long press to stay here
						delay_10ms(3);//Debounce
						if(day<=1)
						{					
							if(0==isLeapYear)//If it is a normal year
							day=commonYearTable[month]+1;
							if(1==isLeapYear)//If it is a leap year
							day=leapYearTable[month]+1;	
						}	
						day--;
					}	
				}
				if(0==K3)//Press K3: Number +1
				{
					delay_10ms(3);//Debounce
					if(0==K3)//Check the button status again
					{	 
						while(0==K3);//Long press to stay here
						delay_10ms(3);//Debounce
						day++;					
						if(0==isLeapYear)//If it is a normal year
						{
							if(day>commonYearTable[month])day=1;
						}
						if(1==isLeapYear)//If it is a leap year
						{
							if(day>leapYearTable[month])day=1;
						}
					}	
				}	
			}

			if(0==K4)//If K4 is pressed: confirm and exit the calendar interface, then return to the clock interface
		   	{
				delay_10ms(3);//Debounce
				if(0==K4)//Check the button status again
				{	 
					while(0==K4);//Long press to stay here
					delay_10ms(3);//Debounce
					cldSetLocation=0;
					whereNow=0;
				}
			} 
	}		
}



void main()
{
	clockSetLocation=0;	
	cldSetOrNot=0;		
	cldSetLocation=0;  	//The position flags and whether to adjust flags of each interface are initialized to 0
	whereNow=0;			//By default, it starts in the clock interface
	blankCount=shanCount; 
	normalCount=shanCount;//Flash count flag initialization
	timer0_initial();	//Timer T0 initialization

	while(1)
	{
		is_leap_year();	//Determine whether it is a leap year
		if(0==whereNow || 1==whereNow)
			clock_display();//Digital tube dynamic display clock interface
			clock_set();	//Time adjustment (same interface as clock)
		if(3==whereNow)
			cld_display();//Digital tube dynamic display calendar interface
			cld_set();		//Calendar Settings
	}
}


Implementation effect and function analysis

The above program mainly realizes the functions of electronic clock display and adjustment and calendar display and adjustment.

Digital tube:

Three pins smg0, smg1, smg2 for controlling digital tube bit selection and pin duan for digital tube segment selection are defined.

The display code table table of common cathode digital tube and the display code table table_dot with decimal point are defined.

The smg() function is used to display a specific number at a specific position of the digital tube.

Timer:

Timer T0 is used to count time and control the dynamic display of the digital tube.

T0time defines the timing parameters of timer T0.

The timer0_initial() function is used to initialize timer T0.

The serviceTimer0() function is the interrupt service function of timer T0, which is used to process the timing logic of the clock.

Global flags:

whereNow indicates the currently displayed interface, 0 is the clock interface, 1 is the time adjustment interface, and 2 is the calendar interface.

clockSetLocation records the location selected when adjusting the time, 1 means adjusting the hour, 2 means adjusting the minute, and 3 means adjusting the second.

cldSetLocation records the location selected when setting the calendar, 1 means adjusting the year, 2 means adjusting the month, and 3 means adjusting the day.

Timing and time calculation:

Count is used for timing, and the seconds, minutes, hours, etc. are increased every certain number of times (20 times).

The serviceTimer0() function is the interrupt service function of timer T0, which is used to update the time.

Clock display and time adjustment:

The clock_display() function is used to dynamically display the clock on the clock interface.

The clock_set() function is used to adjust the clock on the time adjustment interface.

Calendar display and setting:

The cld_display() function is used to dynamically display the date on the calendar interface.

The cld_set() function is used to adjust the date on the calendar setting interface.

Main function:

Initialize various flags and timers.

Enter the main loop and call the corresponding display and operation functions according to the current interface.

Function:

Clock part:

After booting up, the system will enter the clock interface by default and start counting from 00-00-00

Press and hold K1 to enter adjustment mode. K1 can select the adjustment position, K2 means "minus 1", and K3 means "plus 1"

If the hour part is adjusted to 23 hours, K3 will change it to 00. The other time adjustments are set in the same way.

K4 is the confirmation key. Once the adjusted time is confirmed, K4 will return to the clock interface and start timing from the time just adjusted.

Calendar part:

After power-on, the default interface is the clock interface, and the K3 enters the calendar interface. The default date of the calendar is 2023.12.12. The adjustment process is similar to the clock adjustment.

Effect picture:

Figure 1 Clock interface 00-00-11

Figure 2 Clock interface after time adjustment 05-56-33

Figure 3 Calendar interface Default 2023.12.12

Figure 4 The calendar interface after the date is modified 2024.12.12


The digital clock effect is successfully realized, including the display of hours, minutes and seconds and the function setting of adjusting the time by buttons.