一、实践目的
1、项目开发实际经验
2、单片机系统开发（单片机核心系统、外围输入、输出显示及应用编程）
    3、学习C8051F410单片机及DS1302时钟芯片并结合应用
二、实践内容
    基于C8051F410单片机及DS1302时钟芯片的带校时功能实时时钟的设计与实现，包括焊接硬件电路、数码管显示、DS1302芯片实验、校时功能实时时钟等。
三、实践要求
1、定义4个按键的功能为：K1用于设置在“显示时间”时转换时钟工作状态；
K2用于设置校时时间（加1操作）；
K3用于设置切换“显示日期”与“显示时间”；
K4用于“确认”，返回正常显示。
    2、操作步骤要求：
(1) 平时时钟工作在“时钟显示”状态，每按一下K3键，进入“日期显示”状态；再按K3键返回“时钟显示”状态；
(2) 时钟工作在“时钟显示”状态，每按一下K1键，时钟依次进入校时时间的设置状态；
(3)时钟由“时钟显示”进入“秒低位设置”时，校时时间的初始值为转换时刻的时钟值;
(4)当时钟处在时间设置的4个状态时，每按一次K3键，相应的位上的数值加1，并且要能根据具体所在的位置自动做相应的调整。如秒高位的数字只能在0-5之间，而时高位的数值要限制在0、1、2（时个位数小于3时）;
(5) K4作用下，时钟时间由校时时间代替，确认完成校时的设置;
(6)当时钟处在时间设置的4个状态时，在10秒内无任何键按下，系统自动返回“时间显示”状态，设置的时间无效，不改变原时钟的计时时间;
(7)在效时时间设置的操作过程中，时钟不停止其前时间的计时过程，除非K4 “确认”时，时钟的计时时间由确认的校时时间代替而改变;
(8)时钟显示亮度均匀、无闪烁。当设置相应时间位时，该位应闪烁提示。
#include <C8051F410.h>
#define SYSCLK              24500000/8  
#define TIMER_TICKS_MS      2  
#define TIMER_TICKS_PER_MS  SYSCLK/1000
#ifndef _DS1302_H_
#define _DS1302_H_
sbit  DS1302_CLK = P0^5;	//?????????				  
sbit  DS1302_IO  = P0^6;	//?????????
sbit  DS1302_RST = P0^7;	//?????????
#define Time_24_Hour	0x00	//24????	
#define Time_Start		0x00	//????
#define Time_Stop		0x80	//????
#define BCD2DEC(X)	(((X&0x70)>>4)*10 + (X&0x0F))	
//???BCD????????
#define DEC2BCD(X)	((X/10)<<4 | (X%10))//????????BCD???
Code ;unsigned char led_7[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
0x90};
code unsigned char position[4]={0xf7,0xfb,0xfd,0xfe};
unsigned char time[2],time_set[2],time2[2];	  // ??????????
unsigned char dis_buff[4];		// ?????,??????4???????
unsigned char time_counter,key_stime_counter;	// ??????,
unsigned char clock_state = 4,return_time;
bit	point_on,set_on,time_1s_ok,key_stime_ok;
#define DS1302_SECOND	0x80	//DS1302??????????
#define DS1302_MINUTE	0x82
#define DS1302_HOUR		0x84
#define DS1302_WEEK		0x8A
#define DS1302_DAY		0x86
#define DS1302_MONTH	0x88
#define DS1302_YEAR		0x8C
#define DS1302_WRITE	0x8E
#define DS1302_POWER	0x90
#define key_input	P0     		// ?????
#define key_mask	0x0F   	    // ???????
#define key_no		0
#define key_k1		1
#define key_k2		2
#define key_k3		3
#define key_k4		4				
#define key_state_0	0
#define key_state_1	1
#define key_state_2	2			   

sfr16 TMR2RL = 0xCA;                   // Timer2 Reload Register
sfr16 TMR2   = 0xCC;                   // Timer2 Register
typedef struct __SYSTEMTIME__		//??????????,???????
{
	unsigned char Second;
	unsigned char Minute;
	unsigned char Hour;
	unsigned char Week;
	unsigned char Day;
	unsigned char Month;
	unsigned char Year;
}SYSTEMTIME;

//?????????(????)
void DS1302WriteByte(unsigned char d)
{
    unsigned char i;
	DS1302_CLK = 0;
    for(i=8; i>0; i--)
    {
        DS1302_IO  = d & 0x01;
        DS1302_CLK = 1;
        d >>= 1;
        DS1302_CLK = 0;       
    }
}

//?????????(????)
unsigned char DS1302ReadByte(void)
{
    unsigned char i, dat = 0;
    for(i=8; i>0; i--)
    {
        dat >>= 1;
        if(DS1302_IO) dat|=0x80;
        DS1302_CLK = 1;
        DS1302_CLK = 0;
    }
    return(dat);
}

//?DS1302,ucAddr: DS1302??, ucData: ?????
void Write1302(unsigned char ucAddr, unsigned char ucDa)
{
    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    DS1302WriteByte(ucAddr);       	// ??,??
    DS1302WriteByte(ucDa);       	// ?1Byte??
    DS1302_CLK = 1;
    DS1302_RST = 0;
}

//??DS1302??????
unsigned char Read1302(unsigned char ucAddr)
{
    unsigned char ucData;
    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    DS1302WriteByte(ucAddr|0x01);        // ??,??
    ucData = DS1302ReadByte();         // ?1Byte??
    DS1302_CLK = 1;
    DS1302_RST = 0;
    return(ucData);
}

//??????
void DS1302_GetTime(SYSTEMTIME *Time)
{
	unsigned char ReadValue;
	ReadValue = Read1302(DS1302_SECOND);
	Time->Second = BCD2DEC(ReadValue&0x7F);
	ReadValue = Read1302(DS1302_MINUTE);
	Time->Minute = BCD2DEC(ReadValue);
	ReadValue = Read1302(DS1302_HOUR);
	Time->Hour = BCD2DEC(ReadValue&0x7F);
	ReadValue = Read1302(DS1302_DAY);
	Time->Day = BCD2DEC(ReadValue);	
	ReadValue = Read1302(DS1302_WEEK);
	Time->Week = BCD2DEC(ReadValue);
	ReadValue = BCD2DEC(DS1302_MONTH);
	Time->Month = BCD2DEC(ReadValue);
	ReadValue = Read1302(DS1302_YEAR);
	Time->Year = BCD2DEC(ReadValue);	
}

//??????
void DS1302_SetTime(SYSTEMTIME *Time)
{
	Write1302(DS1302_WRITE,0x00);		//?????
	
	Write1302(DS1302_YEAR,DEC2BCD(Time->Year));
	Write1302(DS1302_MONTH,DEC2BCD(Time->Month));
	Write1302(DS1302_WEEK,DEC2BCD(Time->Week));
	Write1302(DS1302_DAY,DEC2BCD(Time->Day));
	Write1302(DS1302_HOUR,DEC2BCD(Time->Hour)|Time_24_Hour);
	Write1302(DS1302_MINUTE,DEC2BCD(Time->Minute));
	Write1302(DS1302_SECOND,DEC2BCD(Time->Second)|Time_Start);
	
	Write1302(DS1302_WRITE,0x80);		//?????	
}

//???DS1302
void DS1302_Initial(void)
{
	Write1302(DS1302_WRITE,0x00);		//?????

	Write1302(DS1302_SECOND,Time_Stop); //????
	Write1302(DS1302_HOUR,Time_24_Hour);//24??
	Write1302(DS1302_POWER,0xA6);		//????,4K????

	Write1302(DS1302_WRITE,0x80);		//?????
}
#endif

void display(void)				
{										  //????
	static unsigned char posit=0;
	P1 = 0xFF;	
	P2 = led_7[dis_buff[posit]]; 
	if (set_on && (posit==clock_state)) P2= 0xff;	// ????		
	if (point_on && posit==2) 
	   P2 &= 0x7F; //????????????
	P1 = position[posit];   		     
	if (++posit >=4 ) posit = 0;              
}


void DelayMs(unsigned int count)   
{      
    unsigned int i;    
    while(count) 
	{  
	    i=2350;    
        while(i>0) i--;   
        count--;   
    }   
}

// ????????????
void time_to_disbuffer(unsigned char *time)	 
{
	unsigned char i,j=0;
	for (i=0;i<2;i++)
	{
		dis_buff[j++] = time[i] % 10;
		dis_buff[j++] = time[i] / 10;
	}
}
void Port_Init (void)
{
	XBR1     = 0x40; // Enable crossbar and weak pullups
	P1MDOUT  = 0xFF; // P1 are push-pull outputs
	P0MDOUT  = 0xFF;
}

unsigned char read_key(void)
{
	static unsigned char key_state = 0,key_press;
	unsigned char key_return = key_no;

	key_press = key_input & key_mask;	// ???I/O??
	switch (key_state)
	{
	case key_state_0:		// ?????
		if (key_press != key_mask) key_state = key_state_1;	
		break;	// ????,?????????
	case key_state_1:		// ?????
		if (key_press == (key_input & key_mask))
		{
		if(key_press==0x0E)
		   key_return=key_k1;
		   else if(key_press==0x0D)
		           key_return=key_k2;
		   else if (key_press == 0xB) 
				     key_return = key_k3;
		   else if (key_press == 0x07) 
			         key_return = key_k4;
			key_state = key_state_2; // ?????????
		}
		else
			key_state = key_state_0; // ?????,????????
		break;
	case key_state_2:
		if (key_press == key_mask) key_state = key_state_0;
		break;			//?????,????????
	}
	return key_return;
}

void Timer2_Init(void)
{
	TMR2CN &= ~0x08;		// Enable Timer2 in 16 auto-reload mode
	CKCON |= 0x10;          // Timer2 uses SYSCLK

	TMR2RL = -(TIMER_TICKS_PER_MS*TIMER_TICKS_MS); 
	TMR2 = TMR2RL;                      

	TMR2CN |= 0x04;       //Start Timer2
	ET2 = 1;              // Timer2 interrupt enabled
}

void Timer2_ISR (void) interrupt 5
{
	display();		    // LED????
	if (++key_stime_counter >=5)
	{
		key_stime_counter = 0;
		key_stime_ok = 1;			// 10ms?
		if (!(++time_counter % 25)) 
		set_on = !set_on;	// ????????
		if (time_counter >= 100)
		{
			time_counter = 0;
			time_1s_ok = 1;        //     1s?  
		}
	}
	TF2H = 0;              // Reset Interrupt
}

void main (void)
{	 
    unsigned char key_temp,flag=0,i;	 
	SYSTEMTIME tm={12,59,6,3,12,5,10}; 
	PCA0MD &= ~0x40;     
	OSCICN  = 0x85;  //????     // Force Internal Osc. 1:8 prescaler
	                                                             //while ((OSCICN & 0x40 ) == 0);  // Wait until stable
	Port_Init ();  
	Timer2_Init ();     
	EA = 1;   
    DS1302_Initial();
	DS1302_SetTime(&tm);	//???
	//DS1302_GetTime(&tm);						//???
	//time[1] = tm.Second; time[0] = tm.Minute;	
	//time_to_disbuffer(time);
	//display();
	time2[1]=5;time2[0]=12;

   while (1)
	{
		if (time_1s_ok)			  // 1??
		{
			time_1s_ok = 0;
			point_on = ~point_on; // ?????
			DS1302_GetTime(&tm);
			time[0] = tm.Second; time[1] = tm.Minute;
			time_to_disbuffer(time);

			if ((++return_time >= 10) && (clock_state != 4))
			 clock_state = 4;
			if (clock_state == 4) time_to_disbuffer(time);
		}

			//key_stime_ok = 0;

			key_temp = read_key();		// ????????
			if (key_temp)				// ??????
			{
				return_time = 0;
				if(key_temp == key_k1)
				{    
			     	if (++clock_state >= 5)  
						clock_state = 0;
			  	    if (clock_state == 0)
					{
						for (i=0;i<2;i++)	
						time_set[i] = time[i];
					} 
					if (clock_state == 4)
					{
						for (i=0;i<2;i++)	
							time[i] = time_set[i];
					}
				}
			
				if ((clock_state != 4) && (key_temp == key_k2))	// K2???
				{
				    if (clock_state == 0)	time_set[0] += 1;
					if (clock_state == 1)	time_set[0] += 10;
					if (clock_state == 2)	time_set[1] += 1;
					if (clock_state == 3)	time_set[1] += 10;

					if (time_set[0] >= 60) time_set[0]-= 60;// ????????
					if (time_set[1] >= 60) time_set[1]-= 60;
					time_to_disbuffer(time_set);		// ?????????
						for (i=0;i<2;i++)	
							time[i]=time_set[i] ; 				
					   time_to_disbuffer(time);	// ?????????
				}
				if (key_temp == key_k3)	   //??K3,????,??
				{
				     for (i=0;i<2;i++)	
					time_set[i] = time2[i];	//time2??set ??
					 time_to_disbuffer(time_set);	// ?????????
					 DelayMs(500) ;
				}
				if (key_temp == key_k4)	 //??
				{
				  	clock_state = 4;    //  ????	
				}
            	tm.Minute = time[1]; tm.Second = time[0];
			   	DS1302_SetTime(&tm);
			} 
	}
}