天天看點

單片機複習程式例舉005 -- DS1302時鐘晶片用AT89S52單片機、DS1302時鐘晶片、1602LCD做一個電子表 。各檔案例舉如下:

用AT89S52單片機、DS1302時鐘晶片、1602LCD做一個電子表 。各檔案例舉如下:

1、main()函數所在檔案部分:

/******************************************************************************
 *	說明:AT89S52晶片,12M晶振
 *	外設:HD44780控制的1602LCD 和 DS1302時鐘晶片
 *	本程式:做一個電子時鐘,顯示月曆,時間
 *			K1設定确認鍵,K2設定位選擇鍵,K3設定參數減,K4設定參數加
 ******************************************************************************/

//#include <reg52.h>
//#include <intrins.h>

#include "DELAY_FUNCTION_FELL.h"
#include "HD44780_1602LCD.h"
#include "DS1302_SPIdriver.h"
#include "DIY_clock.h"

//使用者要顯示的字元串
unsigned char calendar[17] = "Data:2000-00-00" ; //calendar[i] 年:i = 7,8 月:i= 10,11 日:i=13,14
unsigned char clock_time[17] = "00:00:00" ;	//clock_time[i] 時:i=0,1 分:i=3,4 秒i=6,7

/******************************************************************************
===============================================================================
                       void main(void)函數部分
===============================================================================
*******************************************************************************/
void main(void)
{
	//1、定義相關變量
//	unsigned char i ;

	//2、初始化
	HD44780_1602LCD_Init() ;
	DS1302_Init() ;

	//3、在HD44780控制的1602LCD上顯示時鐘資訊
	Clear_Screen() ;

	while(1)
	{
		Get_Curren_Time() ;	//擷取目前時間
		Dis_Str(0 , 1 , calendar) ; 
		Dis_Str(1 , 5 , clock_time) ;
		User_Set_Time() ; //使用者通過按鍵設定時間								 				
	}			
		
}


/******************************************************************************
 *	名稱:
 *	功能:
 *	參數:
 *	傳回:
 ******************************************************************************/
           

2、實作電子時鐘功能設定部分的函數

//DIY_clock.c


#include "DIY_clock.h"




//定義字元數組顯示數字
unsigned char code digit[10]={"0123456789"};   

//使用者自定義的字元編碼方式:在8*8的點陣中選“右上角”的“5列*7行”點陣 存放資料
//unsigned char code user_str0[] = {0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00};/* 自定義字元 ℃ */


/******************************************************************************
 *	名稱:Get_Curren_Time()
 *	功能:擷取目前時間
 *	參數:無
 *	傳回:無
 ******************************************************************************/
 void Get_Curren_Time(void)
 {
	int temp ;

	temp = Read_DS1302_Year() ;
	calendar[7] = digit[temp / 10] ;
	calendar[8] = digit[temp % 10] ;

	temp = Read_DS1302_Month() ;
	calendar[10] = digit[temp / 10] ;
	calendar[11] = digit[temp % 10] ;

	temp = Read_DS1302_Day() ;
	calendar[13] = digit[temp / 10] ;
	calendar[14] = digit[temp % 10] ;

	temp = Read_DS1302_Hour() ;
	clock_time[0] = digit[temp / 10] ;
	clock_time[1] = digit[temp % 10] ; 

	temp = Read_DS1302_Minute() ;
	clock_time[3] = digit[temp / 10] ;
	clock_time[4] = digit[temp % 10] ;
 
	temp = Read_DS1302_Second() ;
	clock_time[6] = digit[temp / 10] ;
	clock_time[7] = digit[temp % 10] ;



 }

/******************************************************************************
 *	名稱:User_Set_Time_Second()
 *	功能:本地使用者通過按鍵設定 秒位
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time_Second(void)
{
	int temp , switch_temp ;

	switch_temp = 1 ;	//程式停留在某一個設定為的開關

	/*------按一次 K1 設定:時、分、秒-------------------*/
	/*``````設定:second`````````````````````*/
	temp = Read_DS1302_Second() ;
	while(switch_temp)
	{
		if(K4 == 0)  //增加 秒
		{
			delay1ms(15) ;
			if(K4 == 0)
			{
				while(K4 == 0) { ; } //等待按鍵釋放
				temp++ ;
				if(temp == 60)
				{
					temp = 0 ;
				}
			}			
		}

		if(K3 == 0)  //減少 秒
		{
			delay1ms(15) ;
			if(K3 == 0)
			{
				while(K3 == 0) { ; } //等待按鍵釋放
				temp-- ;
				if(temp == 0)
				{
					temp = 60 ;
				}
			}			
		}
		DS1302_Set_Second(temp) ;
		Get_Curren_Time() ;
		Dis_Str(1 , 5 , clock_time) ;

		//按 K1 鍵 跳出設定 秒 的循環
		if(K1 == 0)
		{
			delay1ms(15) ;
			if(K1 == 0)
			{
				while(K1 == 0) { ; } //等待按鍵釋放
				switch_temp = 0 ;
			}
		}
					
	}
 
}
/******************************************************************************
 *	名稱:User_Set_Time_Minute()
 *	功能:本地使用者通過按鍵設定 分鐘位
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time_Minute(void)
{
	int temp , switch_temp ;

	switch_temp = 1 ;	//程式停留在某一個設定為的開關

	/*------按一次 K1 設定:時、分、秒-------------------*/
	/*``````設定:minute`````````````````````*/
	temp = Read_DS1302_Minute() ;
	while(switch_temp)
	{
		if(K4 == 0)  //增加 分鐘值
		{
			delay1ms(15) ;
			if(K4 == 0)
			{
				while(K4 == 0) { ; } //等待按鍵釋放
				temp++ ;
				if(temp == 60)
				{
					temp = 0 ;
				}
			}			
		}

		if(K3 == 0)  //減少 分鐘值
		{
			delay1ms(15) ;
			if(K3 == 0)
			{
				while(K3 == 0) { ; } //等待按鍵釋放
				temp-- ;
				if(temp == 0)
				{
					temp = 60 ;
				}
			}			
		}
		DS1302_Set_Minute(temp) ;
		Get_Curren_Time() ;
		Dis_Str(1 , 5 , clock_time) ;

		//按 K1 鍵 跳出設定 分鐘 的循環
		if(K1 == 0)
		{
			delay1ms(15) ;
			if(K1 == 0)
			{
				while(K1 == 0) { ; } //等待按鍵釋放
				switch_temp = 0 ;
			}
		}
					
	}
 
}

/******************************************************************************
 *	名稱:User_Set_Time_Hour()
 *	功能:本地使用者通過按鍵設定 分鐘位
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time_Hour(void)
{
	int temp , switch_temp ;

	switch_temp = 1 ;	//程式停留在某一個設定為的開關

	/*------按一次 K1 設定:時、分、秒-------------------*/
	/*``````設定:hour`````````````````````*/
	temp = Read_DS1302_Hour() ;
	while(switch_temp)
	{
		if(K4 == 0)  //增加 分鐘值
		{
			delay1ms(15) ;
			if(K4 == 0)
			{
				while(K4 == 0) { ; } //等待按鍵釋放
				temp++ ;
				if(temp == 24)
				{
					temp = 0 ;
				}
			}			
		}

		if(K3 == 0)  //減少 分鐘值
		{
			delay1ms(15) ;
			if(K3 == 0)
			{
				while(K3 == 0) { ; } //等待按鍵釋放
				temp-- ;
				if(temp == 0)
				{
					temp = 24 ;
				}
			}			
		}
		DS1302_Set_Hour(temp) ;
		Get_Curren_Time() ;
		Dis_Str(1 , 5 , clock_time) ;

		//按 K1 鍵 跳出設定 分鐘 的循環
		if(K1 == 0)
		{
			delay1ms(15) ;
			if(K1 == 0)
			{
				while(K1 == 0) { ; } //等待按鍵釋放
				switch_temp = 0 ;
			}
		}
					
	}
 
}

/******************************************************************************
 *	名稱:User_Set_Time_Day()
 *	功能:本地使用者通過按鍵設定 分鐘位
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time_Day(void)
{
	int temp , switch_temp ;

	switch_temp = 1 ;	//程式停留在某一個設定為的開關

	/*------按一次 K1 設定:時、分、秒-------------------*/
	/*``````設定:day`````````````````````*/
	temp = Read_DS1302_Day() ;
	while(switch_temp)
	{
		if(K4 == 0)  //增加 分鐘值
		{
			delay1ms(15) ;
			if(K4 == 0)
			{
				while(K4 == 0) { ; } //等待按鍵釋放
				temp++ ;
				if(temp == 31)
				{
					temp = 0 ;
				}
			}			
		}

		if(K3 == 0)  //減少 分鐘值
		{
			delay1ms(15) ;
			if(K3 == 0)
			{
				while(K3 == 0) { ; } //等待按鍵釋放
				temp-- ;
				if(temp == 0)
				{
					temp = 31 ;
				}
			}			
		}
		DS1302_Set_Day(temp) ;
		Get_Curren_Time() ;
		Dis_Str(1 , 5 , clock_time) ;
		Dis_Str(0 , 1 , calendar) ;

		//按 K1 鍵 跳出設定 分鐘 的循環
		if(K1 == 0)
		{
			delay1ms(15) ;
			if(K1 == 0)
			{
				while(K1 == 0) { ; } //等待按鍵釋放
				switch_temp = 0 ;
			}
		}
					
	}
 
}

/******************************************************************************
 *	名稱:User_Set_Time_Month()
 *	功能:本地使用者通過按鍵設定 分鐘位
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time_Month(void)
{
	int temp , switch_temp ;

	switch_temp = 1 ;	//程式停留在某一個設定為的開關

	/*------按一次 K1 設定:時、分、秒-------------------*/
	/*``````設定:month`````````````````````*/
	temp = Read_DS1302_Month() ;
	while(switch_temp)
	{
		if(K4 == 0)  //增加 分鐘值
		{
			delay1ms(15) ;
			if(K4 == 0)
			{
				while(K4 == 0) { ; } //等待按鍵釋放
				temp++ ;
				if(temp == 12)
				{
					temp = 0 ;
				}
			}			
		}

		if(K3 == 0)  //減少 分鐘值
		{
			delay1ms(15) ;
			if(K3 == 0)
			{
				while(K3 == 0) { ; } //等待按鍵釋放
				temp-- ;
				if(temp == 0)
				{
					temp = 12 ;
				}
			}			
		}
		DS1302_Set_Month(temp) ;
		Get_Curren_Time() ;
		Dis_Str(1 , 5 , clock_time) ;
		Dis_Str(0 , 1 , calendar) ;

		//按 K1 鍵 跳出設定 分鐘 的循環
		if(K1 == 0)
		{
			delay1ms(15) ;
			if(K1 == 0)
			{
				while(K1 == 0) { ; } //等待按鍵釋放
				switch_temp = 0 ;
			}
		}
					
	}
 
}

/******************************************************************************
 *	名稱:User_Set_Time_Year()
 *	功能:本地使用者通過按鍵設定 分鐘位
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time_Year(void)
{
	int temp , switch_temp ;

	switch_temp = 1 ;	//程式停留在某一個設定為的開關

	/*------按一次 K1 設定:時、分、秒-------------------*/
	/*``````設定:year`````````````````````*/
	temp = Read_DS1302_Year() ;
	while(switch_temp)
	{
		if(K4 == 0)  //增加 分鐘值
		{
			delay1ms(15) ;
			if(K4 == 0)
			{
				while(K4 == 0) { ; } //等待按鍵釋放
				temp++ ;
				if(temp == 99)
				{
					temp = 0 ;
				}
			}			
		}

		if(K3 == 0)  //減少 分鐘值
		{
			delay1ms(15) ;
			if(K3 == 0)
			{
				while(K3 == 0) { ; } //等待按鍵釋放
				temp-- ;
				if(temp == 0)
				{
					temp = 99 ;
				}
			}			
		}
		DS1302_Set_Year(temp) ;
		Get_Curren_Time() ;
		Dis_Str(1 , 5 , clock_time) ;
		Dis_Str(0 , 1 , calendar) ;

		//按 K1 鍵 跳出設定 分鐘 的循環
		if(K1 == 0)
		{
			delay1ms(15) ;
			if(K1 == 0)
			{
				while(K1 == 0) { ; } //等待按鍵釋放
				switch_temp = 0 ;
			}
		}
					
	}
 
}


/******************************************************************************
 *	名稱:User_Set_Time()
 *	功能:本地使用者通過按鍵設定時鐘月曆
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void User_Set_Time(void)
{
	int temp , switch_temp ;
	int set_bit = 0 ;
	/*------1、按一次 K1 鍵,進入設定環節------------------------------*/
	if(K1 == 0)
	{
		delay1ms(15) ;  //按鍵消抖
		if(K1 == 0)
		{
			while(K1 == 0)	{ ; } //等待按鍵釋放

			/*------2、按 K2 鍵,通過設定num,确定設定的是時鐘的哪一位---*/
			switch_temp = 1 ;
			while(switch_temp)
			{
				//将set_bit列印到1602lcd上,判斷要設定哪一位時鐘資訊
				Dis_Char(1,0,'F') ;
				Dis_Char(1,1,digit[set_bit]) ;
				Dis_Char(1,2,':') ;

				if(K2 == 0)
				{
					delay1ms(10) ;
					if(K2 == 0)
					{
						delay1ms(7) ;
						if(K2 == 0)
						{
							while(K2 == 0)	{ ; } //等待按鍵釋放
							set_bit++ ;
							if(set_bit == 6)
							{
								set_bit = 0 ;
							}	
						}					
					}

				}

				//按 K1 跳出設定num的循環
				if(K1 == 0)
				{
					delay1ms(15) ;
					if(K1 == 0)
					{
						while(K1 == 0)	{ ; } //等待按鍵釋放
						switch_temp = 0 ;
					}
				}
			}

			/*------3、根據 set_bit 的值調用不同的函數,對時鐘進行設定---*/
			switch(set_bit)
			{
				case 0 ://設定second位
					User_Set_Time_Second() ;
					break;

				case 1 ://設定minute位
					User_Set_Time_Minute() ;
					break;

				case 2 ://設定hour位
					User_Set_Time_Hour() ;
					break;

				case 3 ://設定day位
					User_Set_Time_Day() ;
					break;

				case 4 ://設定month位
					User_Set_Time_Month() ;
					break;

				case 5 ://設定year位
					User_Set_Time_Year() ;
					break;

				default ://其他值不設定
					break;

			}




		}
	}
	/*------4、清除1602LCD螢幕上的設定标志位-----------------------------*/
	Dis_Char(1,0,' ') ;
	Dis_Char(1,1,' ') ;
	Dis_Char(1,2,' ') ;

}

/******************************************************************************
 *	名稱:
 *	功能:
 *	參數:
 *	傳回:
 ******************************************************************************/
           
//DIY_clock.h
#ifndef __DIY_CLOCK_H__
#define __DIY_CLOCK_H__

#include <reg52.h>
#include <intrins.h>

#include "DELAY_FUNCTION_FELL.h"
#include "HD44780_1602LCD.h"
#include "DS1302_SPIdriver.h"

sbit K1 = P1^4 ;	//User設定時間的開關
sbit K2 = P1^5 ;	//設定參數,确定具體設定時鐘的哪一位
sbit K3 = P1^6 ;	//設定位的值遞減
sbit K4 = P1^7 ;	//設定位的值遞增

extern unsigned char calendar[17] ;
extern unsigned char clock_time[17] ;

 void Get_Curren_Time(void) ;
 void User_Set_Time_Second(void) ;
 void User_Set_Time_Minute(void) ;
 void User_Set_Time_Hour(void) ;
 void User_Set_Time_Day(void) ;
 void User_Set_Time_Month(void) ;
 void User_Set_Time_Year(void) ;
 void User_Set_Time(void) ;

#endif





           

3、DS1302時鐘晶片配置檔案

//DS1302_SPIdriver.c

#include "DS1302_SPIdriver.h"


/*****************************************************
函數功能:向1302寫一個位元組資料
入口參數:x
***************************************************/ 
void Write1302(unsigned char dat)
{
  unsigned char i; 
  SCLK=0;            //拉低SCLK,為脈沖上升沿寫入資料做好準備
  delay1us(2);       //稍微等待,使硬體做好準備
  for(i=0;i<8;i++)      //連續寫8個二進制位資料
    {
	     DATA=dat&0x01;    //取出dat的第0位資料寫入1302  低位在前,高位在後
		 delay1us(2);       //稍微等待,使硬體做好準備
		 SCLK=1;           //上升沿寫入資料
		 delay1us(2);      //稍微等待,使硬體做好準備
		 SCLK=0;           //重新拉低SCLK,形成脈沖
		 dat>>=1;          //将dat的各資料位右移1位,準備寫入下一個資料位
	  }
	
 }
/*****************************************************
函數功能:根據指令字,向1302寫一個位元組資料
入口參數:Cmd,儲存指令字;dat,儲存待寫的資料
***************************************************/ 
void WriteSet1302(unsigned char Cmd,unsigned char dat)
 {	  
        RST=0;           //禁止資料傳遞
        SCLK=0;          //確定寫數居前SCLK被拉低
	    RST=1;           //啟動資料傳輸
	    delay1us(2);     //稍微等待,使硬體做好準備
	    Write1302(Cmd);  //寫入指令字
	    Write1302(dat);  //寫資料
	    SCLK=1;          //将時鐘電平置于高電平狀态
	    RST=0;           //禁止資料傳遞
 }
/*****************************************************
函數功能:從1302讀一個位元組資料
入口參數:x
***************************************************/ 
 unsigned char Read1302(void)
 {
    unsigned char i,dat;
	delay1us(2);       //稍微等待,使硬體做好準備
	for(i=0;i<8;i++)   //連續讀8個二進制位資料
	 {	 dat>>=1;
		 if(DATA==1)    //如果讀出的資料是1
		 dat|=0x80;    //将1取出,寫在dat的最高位
		 SCLK=1;       //将SCLK置于高電平,為下降沿讀出
		 delay1us(2);  //稍微等待
		 SCLK=0;       //拉低SCLK,形成脈沖下降沿
		 delay1us(2);  //稍微等待
	  }	 
  return dat;        //将讀出的資料傳回
}  
/*****************************************************
函數功能:根據指令字,從1302讀取一個位元組資料
入口參數:Cmd
***************************************************/ 
unsigned char  ReadSet1302(unsigned char Cmd)
 {
  unsigned char dat;
  RST=0;                 //拉低RST
  SCLK=0;                //確定寫數居前SCLK被拉低
  RST=1;                 //啟動資料傳輸
  Write1302(Cmd);       //寫入指令字
  dat=Read1302();       //讀出資料
  SCLK=1;              //将時鐘電平置于已知狀态
  RST=0;               //禁止資料傳遞
  return dat;          //将讀出的資料傳回
}

/******************************************************************************
 *	名稱:DS1302_Set_Second()
 *	功能:設定時鐘 秒 位
 *	參數:int second
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Second(int second)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
	   	WriteSet1302(0x80,((second/10)<<4|(second%10)));   //根據寫秒寄存器指令字,寫入秒的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }

 /******************************************************************************
 *	名稱:DS1302_Set_Minute()
 *	功能:設定時鐘 分 位
 *	參數:int minute
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Minute(int minute)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
		WriteSet1302(0x82,((minute/10)<<4|(minute%10)));   //根據寫分寄存器指令字,寫入分的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }

 /******************************************************************************
 *	名稱:DS1302_Set_Hour()
 *	功能:設定時鐘 時 位
 *	參數:int hour
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Hour(int hour)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
		WriteSet1302(0x84,((hour/10)<<4|(hour%10))); //根據寫小時寄存器指令字,寫入小時的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }

 /******************************************************************************
 *	名稱:DS1302_Set_Day()
 *	功能:設定時鐘 日 位
 *	參數:int day
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Day(int day)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
		WriteSet1302(0x86,((day/10)<<4|(day%10))); //根據寫日寄存器指令字,寫入日的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }

 /******************************************************************************
 *	名稱:DS1302_Set_Month()
 *	功能:設定時鐘 月 位
 *	參數:int month
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Month(int month)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
		WriteSet1302(0x88,((month/10)<<4|(month%10))); //根據寫月寄存器指令字,寫入月的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }

 /******************************************************************************
 *	名稱:DS1302_Set_Weekday()
 *	功能:設定時鐘 星期 位
 *	參數:int weekday
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Weekday(int weekday)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
		WriteSet1302(0x8a,( weekday%7 ));  //根據寫星期寄存器指令字,寫入星期的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }

 /******************************************************************************
 *	名稱:DS1302_Set_Year()
 *	功能:設定時鐘 年 位
 *	參數:int year
 *	傳回:無
 ******************************************************************************/
 void DS1302_Set_Year(int year)
 {
 	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
		WriteSet1302(0x8c,((year/10)<<4|(year%10)));  //根據寫年寄存器指令字,寫入年的初始值
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
 }






/*****************************************************
函數功能: 1302進行初始化設定
***************************************************/ 
void DS1302_Init(void)
{	
  unsigned char flag;
   
    flag= ReadSet1302(0x81);
	if(flag&0x80)	
	{      //判斷時鐘晶片是否關閉
	    WriteSet1302(0x8E,0x00);                 //根據寫狀态寄存器指令字,寫入不保護指令 
	   	WriteSet1302(0x80,((55/10)<<4|(55%10)));   //根據寫秒寄存器指令字,寫入秒的初始值
		WriteSet1302(0x82,((59/10)<<4|(59%10)));   //根據寫分寄存器指令字,寫入分的初始值
		WriteSet1302(0x84,((23/10)<<4|(23%10))); //根據寫小時寄存器指令字,寫入小時的初始值
		WriteSet1302(0x86,((5/10)<<4|(5%10))); //根據寫日寄存器指令字,寫入日的初始值
		WriteSet1302(0x88,((4/10)<<4|(4%10))); //根據寫月寄存器指令字,寫入月的初始值
		WriteSet1302(0x8a,( 6%7 ));  //根據寫星期寄存器指令字,寫入星期的初始值
		WriteSet1302(0x8c,((14/10)<<4|(14%10)));  //根據寫年寄存器指令字,寫入年的初始值
		WriteSet1302(0x90,0xa5);                //打開充電功能 選擇2K電阻充電方式
		WriteSet1302(0x8E,0x80);			   //根據寫狀态寄存器指令字,寫入保護指令
	}

  }

/******************************************************************************
 *	名稱:Read_DS1302_Second()
 *	功能:讀DS1302的 秒 位
 *	參數:無
 *	傳回:second
 ******************************************************************************/
 int Read_DS1302_Second(void)
 {
 	  int second ;
	  unsigned char ReadValue ; 

 	  ReadValue = ReadSet1302(0x81);   //從秒寄存器讀資料
     second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//将讀出資料轉化十進制數
	 return second ;

 }

 /******************************************************************************
 *	名稱:Read_DS1302_Minute()
 *	功能:讀DS1302的 分 位
 *	參數:無
 *	傳回:minute
 ******************************************************************************/
 int Read_DS1302_Minute(void)
 {
 	  int minute ;
	  unsigned char ReadValue ;

	  ReadValue = ReadSet1302(0x83);  //從分寄存器讀
      minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将讀出資料轉化
	  return minute ;
 
 }

 /******************************************************************************
 *	名稱:Read_DS1302_Hour()
 *	功能:讀DS1302的 時 位
 *	參數:無
 *	傳回:hour
 ******************************************************************************/
 int Read_DS1302_Hour(void)
 {
 	  int hour ;
	  unsigned char ReadValue ;

     ReadValue = ReadSet1302(0x85);  //從分寄存器讀
     hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将讀出資料轉化
	 return hour ;
 
 }

 /******************************************************************************
 *	名稱:Read_DS1302_Day()
 *	功能:讀DS1302的 日 位
 *	參數:無
 *	傳回:day
 ******************************************************************************/
 int Read_DS1302_Day(void)
 {
 	  int day ;
	  unsigned char ReadValue ;

     ReadValue = ReadSet1302(0x87);  //從分寄存器讀
     day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将讀出資料轉化
	 return day ; 
 
 }

 /******************************************************************************
 *	名稱:Read_DS1302_Month()
 *	功能:讀DS1302的 月 位
 *	參數:無
 *	傳回:month
 ******************************************************************************/
 int Read_DS1302_Month(void)
 {
 	  int month ;
	  unsigned char ReadValue ;

	  ReadValue = ReadSet1302(0x89);  //從月寄存器讀
      month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将讀出資料轉化
	  return month ;

 }

 /******************************************************************************
 *	名稱:Read_DS1302_Weekday()
 *	功能:讀DS1302的 星期 位
 *	參數:無
 *	傳回:weekday
 ******************************************************************************/
 int Read_DS1302_Weekday(void)
 {
 	  int weekday ;
	  unsigned char ReadValue ;

 	  ReadValue = ReadSet1302(0x81);   //從星期寄存器讀資料
      weekday = ReadValue&0x0F ;//将讀出資料轉化
	  return weekday ;
 
 }

 /******************************************************************************
 *	名稱:Read_DS1302_Year()
 *	功能:讀DS1302的 年 位
 *	參數:無
 *	傳回:year
 ******************************************************************************/
 int Read_DS1302_Year(void)
 {
 	  int year ;
	  unsigned char ReadValue ;

	  ReadValue = ReadSet1302(0x8d);  //從年寄存器讀
      year = ((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0F); //将讀出資料轉化
	  return year ;
 
 }
           
//DS1302_SPIdriver.h
#ifndef __SPIDRIVER_H__
#define __SPIDRIVER_H__

#include<reg52.h>     //包含單片機寄存器的頭檔案
#include<intrins.h>   //包含_nop_()函數定義的頭檔案
#include "DELAY_FUNCTION_FELL.h"

sbit SCLK=P1^0;   //位定義1302晶片的接口,時鐘輸出端口定義在P1.0引腳
sbit DATA=P1^1;   //位定義1302晶片的接口,資料輸出端定義在P1.1引腳
sbit RST=P1^2;    //位定義1302晶片的接口,複位端口定義在P1.2引腳


 void Write1302(unsigned char dat) ;	//向DS1302寫一個位元組的資料(或指令)
 unsigned char Read1302(void) ;	//從DS1302中讀一個位元組的資料
 void WriteSet1302(unsigned char Cmd,unsigned char dat) ;//根據指令字,向1302寫一個位元組資料
 unsigned char  ReadSet1302(unsigned char Cmd) ; //根據指令字,從1302讀取一個位元組資料

 void DS1302_Set_Second(int second) ; //設定秒
 void DS1302_Set_Minute(int minute) ;	//設定分
 void DS1302_Set_Hour(int hour) ;	//設定時
 void DS1302_Set_Day(int day) ;	//設定日
 void DS1302_Set_Month(int month) ;	//設定月
 void DS1302_Set_Weekday(int weekday) ;	//設定星期
 void DS1302_Set_Year(int year) ;	//設定年 

 void DS1302_Init(void) ; //對1302進行初始化設定

 int Read_DS1302_Second(void)	;
 int Read_DS1302_Minute(void) ; 
 int Read_DS1302_Hour(void) ; 
 int Read_DS1302_Day(void) ;
 int Read_DS1302_Month(void) ; 
 int Read_DS1302_Weekday(void) ;
 int Read_DS1302_Year(void) ;


#endif




           

4、HD44780控制的1602LCD部分的配置檔案

/**************************************************************************************************
 * 	HD44780_1602LCD配置檔案名:HD44780_1602LCD.c     
 *	和HD44780_1602LCD.h配套使用
 *	本程式當時是依據AT89S52單片機開發闆寫的
 *	RS R/W E 這三位引腳分别和單片機引腳 P2^0 P2^1 P2^2 相連
 *	八位資料引腳DB0……DB7分别和單片機的P0端口的P0^0……P0^7相連 (BF位其實就對應DB7引腳和P0^7相連)
 *	将此檔案來驅動1602LCD時,隻需更改下面的位定義和資料線的端口号即可
 *	對于HD44780控制的1602LCD的詳細資料和11條指令的描述參考一下連接配接
 *	http://blog.csdn.net/dragon12345666/article/details/22819827
 **************************************************************************************************/


#include"HD44780_1602LCD.h"


/******************************************************************************
 *	名稱:Busy_Test()
 *	功能:檢測HD44780控制的1602LCD是否處于忙狀态
 *	參數:無							   
 *	傳回:bit result  忙則傳回 1 , 不忙則傳回 0 。
 ******************************************************************************/
bit Busy_Test(void)
{
	//1、定義變量,存儲傳回值
	bit result ;

	//2、讀狀态位
	RS = 0 ; RW = 1 ; 
	E = 1 ;
	_nop_() ; _nop_() ; _nop_() ; _nop_() ;	 //延時4個機器周期,給硬體響應,
											 //即:使E=1;穩定
	result = BF ;	//将忙狀态位BF的值讀給函數要傳回的變量

	//3、将時能位E複位到低電平
	E = 0 ;

	//4、将忙狀态位讀的結果作為函數的參數傳回
	return result ;

} 


/******************************************************************************
 *	名稱:Write_Com()
 *	功能:向HD44780寫控制1602LCD的控制指令
 *	參數:unsigned char dictate
 *	傳回:無
 ******************************************************************************/
 void Write_Com(unsigned char dictate)
 {
 	//1、檢測LCD忙狀态,忙,則等待
	while(Busy_Test() == 1) { ; }

	//2、向HD44780控制的1602LCD寫控制指令
		/*----2.1、操作對象是指令,執行對象:寫入----------------------------*/
			RS = 0 ;
		    RW = 0 ;

		/*----2.2、在E 為 0 時,先将指令資料寫到P0口的DB0--DB7資料線上-------*/
			E = 0 ;

			_nop_() ; //給硬體反應時間,等待E = 0 ;穩定 
			_nop_() ;

			P0 = dictate ;	//将指令先暫時寫到資料線上

			_nop_() ; //確定硬體把指令資料寫完了
			_nop_() ; 
			_nop_() ; 
			_nop_() ; 

		/*----2.3、在E 為 1 時,将資料線上的指令資料寫到DH44780的寄存器裡----*/
			E = 1 ;
			_nop_(); _nop_(); _nop_(); _nop_(); //等待 E = 1 穩定

		/*----2.4、在E 為 下降沿 時,執行寫入的指令--------------------------*/
			E = 0 ;	//從 E = 1 到 E = 0 産生下降沿,HD44780執行指令

 }


/******************************************************************************
 *	名稱:Write_Address()
 *	功能:通過指令來控制第一個要顯示的字元或下一個即将要顯示的字元在LCD上的位置
 *	參數:unsigned char addr  在LCD上要顯示的位置
 *	傳回:無
 ******************************************************************************/
void Write_Address(unsigned char addr)
{
	//向HD44780寫指令8:設定DDRAM位址的指令。
	//即:即将要顯示的字元在1602LCD上的指令需要的位址 = 0x80|(字元在LCD螢幕上的位置)
	Write_Com(0x80|addr) ;
}

/******************************************************************************
 *	名稱:Write_Data()
 *	功能:1、向HD44780控制的1602LCD寫要顯示的字元資料;
 *		  2、向CGRAM中,對應位址的存儲單元寫使用者自定義的字元資料
 *	參數:unsigned char char_data 要顯示的字元(其實字元的值和它的ASCII碼值一樣)
 *	傳回:無
 ******************************************************************************/
void Write_Data(unsigned char char_data)
{
	//1、檢測HD44780控制的1602LCD忙狀态位,忙,則等待
	while(Busy_Test() == 1) { ; }
	//2、向HD44780控制的1602LCD寫要顯示的字元資料
		/*----2.1、操作對象是資料,執行對象:寫入----------------------------*/
			RS = 1 ;
		    RW = 0 ;

		/*----2.1、在E 為 0 時,先将字元資料寫到P0口的DB0--DB7資料線上-------*/
			E = 0 ;
			_nop_() ; _nop_() ; //給硬體反應時間,等待E = 0 ;穩定
			P0 = char_data ;	//将字元資料先暫時寫到資料線上
			_nop_() ; _nop_() ; _nop_() ; _nop_() ; //確定硬體把字元資料寫完了

		/*----2.2、在E 為 1 時,将資料線上的字元資料寫到DH44780的寄存器裡----*/
			E = 1 ;
			_nop_(); _nop_(); _nop_(); _nop_(); //等待 E = 1 穩定

		/*----2.3、在E 為 下降沿 時,執行寫入的指令--------------------------*/
			E = 0 ;	//從 E = 1 到 E = 0 産生下降沿,HD44780執行指令

}

/******************************************************************************
 *	名稱:HD44780_1602LCD_Init()
 *	功能:對HD44780控制的1602LCD進行初始化 (包含硬體類型,屏顯,光标)
 *	參數:無
 *	傳回:無
 ******************************************************************************/
void HD44780_1602LCD_Init(void)
{
	//1、首次寫指令前,給LCD硬體一段較長的反應時間
	delay1ms(15) ;
	//2、顯示模式設定
		/*----1、比對硬體的設定: 指令6:8位資料線,2行顯示,5*7點陣------------*/
		Write_Com(0x38) ; delay1ms(5) ; //3次寫指令,確定硬體比對成功
		Write_Com(0x38) ; delay1ms(5) ; 
		Write_Com(0x38) ; delay1ms(5) ; 

		/*----2、顯示屏、光标、閃爍的設定: 指令4:開顯示,不開光标,光标不閃爍------*/
		Write_Com(0x0c) ; delay1ms(5) ;

		/*----3、光标、螢幕移動的設定: 指令3:光标右移,螢幕整體不移動----------*/
		Write_Com(0x06) ; delay1ms(5) ;

	//3、清屏。指令1
	Write_Com(0x01) ; delay1ms(5) ;	 

}

/******************************************************************************
 *	名稱:Write_User_char()
 *	功能:将一個使用者自定義的字元寫入CGRAM中(CGRAM最多寫8個字元)
 *	參數:unsigned char addr_num : 存入CGRAM中的第addr_num個8位元組存儲塊 (0--8)
 *	參數:unsigned char *str : 指向存放使用者自定義字元的數組
 *	傳回:無
 ******************************************************************************/
 void Write_User_char(unsigned char addr_num , unsigned char *str)
 {
	/*----1、定義變量--------------------------------------------------------*/
 	unsigned char i ;
 	unsigned char CGRAM_addr ;

	/*----2、處理位址,CGRAM存儲單元有8*8==64個位元組,可存入8個自定義字元-----*/
	//指令7的指令碼	  01 xxx 000 :第一個 xxx 表示自定義字元存入 第xxx個8位元組的存儲空間
	//									 000 表示第xxx個8位元組存儲空間的首位址
	addr_num = _crol_(addr_num,3) ;	
	CGRAM_addr = 0x40 | addr_num ;

	/*----1、指令7:設定将自定義字元資料存入CGRAM中存儲單元的位址------------*/
	//指令固定值01、第n個自定義字元、存儲第n個自定義字元的數組的首位址(8byte)
	Write_Com(CGRAM_addr) ; //
	delay1ms(5) ;
	
	/*----2、将使用者自定義的字元寫入CGRAM中對應位址的存儲單元中----------------*/
	i = 0 ;
	for(i = 0 ; i < 8 ; i++)
	{
		Write_Data(str[i]) ;
	}

 }

/******************************************************************************
 *	名稱:Dis_User_char()
 *	功能:顯示自定義字元:在1602LCD螢幕指定位置上顯示第num個自定義字元
 *	參數:unsigned char line , unsigned char x	 在螢幕的第line行第x列顯示 
 *	參數:unsigned char num	 :顯示CGRAM中8個自定義字元的第num個 num = 0-->7
 *	傳回:無
 ******************************************************************************/
void Dis_User_char(unsigned char line , unsigned char x ,unsigned char num)
{
//3.2.2 
	/*----1、設定在1602LCD螢幕上顯示的坐标位置(位址)------------*/ 
	Write_Address(0x40 * line + x) ; //顯示在第line行的第x位
	delay1ms(5) ;

	/*----2、将CGROM/CGRAM對應位址中的資料,顯示在螢幕對應的位置---*/
	Write_Data(num) ; //顯示CGRAM中8個自定義字元的第num個 num = 0-->7
					   //和顯示CGROM中資料不同之處在于:不用和0x80相與

}


/******************************************************************************
 *	名稱:Switch_Screen()
 *	功能:控制顯示屏開關,(不顯示光标)
 *	參數:unsigned char scr_key = 1:開 ; = 0:關
 *	傳回:無
 ******************************************************************************/
 void Switch_Screen(unsigned char scr_key)
 {
 	delay1ms(50) ;
	if(scr_key == 1)
	{
		Write_Com(0x0c) ; //指令4 ,0000 1100 :開螢幕顯示 ,無光标
	}

	if(scr_key == 0)
	{
		Write_Com(0x08) ; //指令4 ,0000 1100 :關螢幕顯示
	}

 	delay1ms(50) ;
 }

 /******************************************************************************
 *	名稱:Switch_Cursor()
 *	功能:控制光标開關和閃爍
 *	參數:unsigned char cursor_key 
 *	參數:unsigned char twinkle_key
 *	傳回:無
 ******************************************************************************/
 void Switch_Cursor(unsigned char cursor_key , unsigned char twinkle_key)
 {
 	delay1ms(50) ;
	if(cursor_key == 1)
	{
		if(twinkle_key == 1)
		{
			Write_Com(0x0f) ; //指令4 ,0000 1111 :開螢幕顯示,開光标,光标閃爍
		}
		else
		{
			Write_Com(0x0e) ; //指令4 ,0000 1110 :開螢幕顯示 ,開光标		
		}
	}

	if(cursor_key == 0)
	{
		Write_Com(0x0c) ; //指令4 ,0000 1100 :開螢幕顯示
	}

 	delay1ms(50) ;
 }

/******************************************************************************
 *	名稱:Move_Screen()
 *	功能:控制螢幕整體左右移動
 *	參數:unsigned char r_l = 1 :右移  ; = 0 :左移
 *	參數:unsigned char move_bit_num  :螢幕向右或向左移動多少位
 *	參數:unsigned char move_delay :每移動一位後,延時多少 ms
 *	傳回:無
 ******************************************************************************/
 void Move_Screen(unsigned char r_l,unsigned char move_bit_num,unsigned char move_delay)
 {
 	unsigned char i ;
 	delay1ms(move_delay) ;

	if(r_l == 1) //螢幕整體右移
	{
		for(i = 0 ; i < move_bit_num ; i++)
		{
			Write_Com(0x1c) ; //指令5 : 0001 1100 螢幕整體右移一位	
			delay1ms(move_delay) ;	
		}

	}

	if(r_l == 0) //螢幕整體左移
	{
		for(i = 0 ; i < move_bit_num ; i++)
		{
			Write_Com(0x18) ; //指令5 : 0001 1000 螢幕整體左移一位	
			delay1ms(move_delay) ;	
		}

	}
 }

/******************************************************************************
 *	名稱:Dis_Str()
 *	功能:在顯示HD44780控制的1602LCD上顯示一個字元串
 *	參數:unsigned char line , unsigned char x 在LCD上顯示的位置
 *	參數:unsigned char *str 要顯示的字元串的指針(首位址)
 *	傳回:無
 ******************************************************************************/
void Dis_Str(unsigned char line , unsigned char x , unsigned char *str)
{
	unsigned char i ;

	//1、 設定在LCD1602上顯示字元的開始位置 : 從 第line行 坐标x 開始顯示
	Write_Address(0x40 * line + x) ; delay1ms(5) ;	

	//2、 顯示要顯示的字元串
	i = 0 ;
	while(str[i] != '\0')
	{
		Write_Data(str[i]) ;
		i++ ;
		delay1ms(1) ;
	}
}

/******************************************************************************
 *	名稱:Dis_Char()
 *	功能:在顯示HD44780控制的1602LCD上顯示一個字元
 *	參數:unsigned char line , unsigned char x 在LCD上顯示的位置
 *	參數:unsigned char ch 要顯示的字元
 *	傳回:無
 ******************************************************************************/
void Dis_Char(unsigned char line , unsigned char x , unsigned char ch)
{
	//1、 設定在LCD1602上顯示字元的開始位置 : 從 第line行 坐标x 開始顯示
	Write_Address(0x40 * line + x) ; delay1ms(5) ;	

	//2、 顯示要顯示的字元串
	Write_Data(ch) ;
	delay1ms(10) ;

}

/******************************************************************************
 *	名稱:Clear_Screen()
 *	功能:清屏
 *	參數:無
 *	傳回:無
 ******************************************************************************/
 void Clear_Screen(void)
 {
	delay1ms(5) ;
	Write_Com(0x01) ; 
	delay1ms(5) ; 
 }

           
/**************************************************************************************************
 * 	HD44780_1602LCD配置檔案:HD44780_1602LCD.h
 *	本程式當時是依據AT89S52單片機開發闆寫的
 *	RS R/W E 這三位引腳分别和單片機引腳 P2^0 P2^1 P2^2 相連
 *	八位資料引腳DB0……DB7分别和單片機的P0端口的P0^0……P0^7相連 (BF位其實就對應DB7引腳和P0^7相連)
 *	将此檔案來驅動1602LCD時,隻需更改下面的位定義和資料線的端口号即可
 *	對于HD44780控制的1602LCD的詳細資料和11條指令的描述參考一下連接配接
 *	http://blog.csdn.net/dragon12345666/article/details/22819827
 **************************************************************************************************/
#ifndef __HD44780_1602LCD_H__
#define __HD44780_1602LCD_H__

#include<reg52.h>
#include<intrins.h>
#include "DELAY_FUNCTION_FELL.h"

sbit RS = P2^0 ;	//對象标志位: = 0(對象是指令或狀态位);= 1(對象是資料)
sbit RW = P2^1 ;	//讀寫标志位: = 0(寫);= 1(讀)
sbit E  = P2^2 ;	//使能位:為 1 時,讀寫資訊,為 負跳變 時,執行指令
sbit BF = P0^7 ;	//HD44780控制的1602LCD的 忙 狀态位(隻能通過指令讀取)


 bit Busy_Test(void) ;
 void Clear_Screen(void) ;
 void Dis_Str(unsigned char line , unsigned char x , unsigned char *str) ;
 void Dis_User_char(unsigned char line , unsigned char x ,unsigned char num) ;
 void Dis_Char(unsigned char line , unsigned char x , unsigned char ch) ;
 void HD44780_1602LCD_Init(void) ;
 void Move_Screen(unsigned char r_l,unsigned char move_bit_num,unsigned char move_delay) ;
 void Switch_Cursor(unsigned char cursor_key , unsigned char twinkle_key) ;
 void Switch_Screen(unsigned char scr_key) ;
 void Write_Address(unsigned char addr) ;
 void Write_Com(unsigned char dictate) ;
 void Write_Data(unsigned char char_data) ;
 void Write_User_char(unsigned char addr_num , unsigned char *str) ;

 #endif
           

5、延時函數部配置設定置檔案

//DELAY_FUNCTION_FELL.c
#include "DELAY_FUNCTION_FELL.h"

/******************************************************************************
 *	名稱:dlcd_delay1us()
 *	功能:延時若幹1ns
 *	參數:int t
 *	傳回:無
 ******************************************************************************/
void delay1us(int t)
{
	while(t--)
	{
		_nop_() ;
	}
}


/******************************************************************************
 *	名稱:dlcd_delay1ms()
 *	功能:延時若幹1ms
 *	參數:int t
 *	傳回:無
 ******************************************************************************/
void delay1ms(int t)
{
	unsigned char i ;

	while(t--)
	{
		for(i = 0 ; i < 125 ; i++)
		{
			;
		}
	}
}



           
//DELAY_FUNCTION_FELL.h
#ifndef __DELAY_FUNCTION_FELL_H__
#define __DELAY_FUNCTION_FELL_H__

#include<reg52.h>     //包含單片機寄存器的頭檔案
#include<intrins.h>   //包含_nop_()函數定義的頭檔案

extern void delay1us(int t) ;
extern void delay1ms(int t) ;


#endif