单片机复习程序例举005 -- DS1302时钟芯片

用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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值