基于MCS-51单片机的数字时钟设计

基于MCS-51单片机的数字时钟设计

源码链接

项目面试问题
C/C++/嵌入式—面试题汇总

一、项目描述

1.基于DS1302时钟模块,可以完成年、月、日、时、分、秒、周的正确显示。
2.可以通过外部按键对当前时间进行校准。
3.能够以12小时和24小时制表示方式显示时间。
4.能够通过外部按键设置闹钟提醒时间。

实际操作:
LCD1602显示时钟,按K3键进入时钟设置,此时秒钟停止走动,按K1键选择设置的秒、分、时、
日、月、星期、年,按K2键进行加1,设置完成后,再次按下K3键继续走时,按下K4进入闹钟
界面设置(在闹钟界面不能按下K3),K1进行选择时、分,K2进行加一,再按下K4返回时钟界面,
当时间走到设置时间时,蜂鸣器会响起大概五秒钟,之后继续走时。按下矩阵按键P15进行12/24小时制切换。

二、项目功能展示

1.日期显示
在这里插入图片描述
2.闹钟时间设置
在这里插入图片描述
3.二十四小时制显示
在这里插入图片描述
在这里插入图片描述
4.十二小时制显示
在这里插入图片描述在这里插入图片描述

三、代码展示

在这里插入图片描述

1、main.c

/*******************************************************************************
参考LCD1602液晶显示实验接线图
参考DS1302时钟实验接线图
K1-->P31
K2-->P30
K3-->P32
K4-->P33(该按键未做功能,可扩展)

实验操作:
LCD1602显示时钟,按K3键进入时钟设置,此时秒钟停止走动,按K1键选择设置的秒、分、时、
日、月、星期、年,按K2键进行加1,设置完成后,再次按下K3键继续走时,按下K4进入闹钟
界面设置(在闹钟界面不能按下K3),K1进行选择时、分,K2进行加一,再按下K4返回时钟界面,
当时间走到设置时间时,蜂鸣器会响起大概五秒钟,之后继续走时。
按下矩阵按键P15进行12/24小时制切换。 

此时开机时钟默认为12:00:55,闹钟时间为12:01(分)
*******************************************************************************/

#include <reg51.h>
#include "lcd.h"
#include "ds1302.h"

#define GPIO_KEY P1

sbit K1=P3^1;
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;	 //管脚接线
sbit beep=P1^5;

sbit line=P1^4;
sbit list1=P1^3;
sbit list2=P1^2;

sbit led1=P2^0;
sbit led2=P2^1;
sbit led3=P2^2;
sbit led4=P2^3;
sbit led5=P2^4;

void Int0Configuration();
void LcdDisplay();
void DisplayTime();
void DisplayClock();
void write_sfm(uchar add,uchar date);
unsigned char toCompare();
unsigned char SetState,SetPlace,SetClock;
bit ClockPlace;
bit ClockFlag;
void Delay10ms(void);   //误差 0us

unsigned char C_shi=12,C_fen=1;
int count = 0;
uint APM = 0;	   //为0时表示24小时制,为1时表示上午,为2时表示下午
int temp = 0;	   //为0时表示24小时制,为1时表示12小时制
uint h=0x23;    //默认初始24小时制
uint key;
uint key_num;//键盘扫描值,键盘键值

/*******************************************************************************
* 函数名         : main
* 函数功能		   : 主函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void delay(uint i)
{
	while(i--);
}

void main()
{	
    
    uint keynum();
	unsigned char result;
	unsigned int i;
	unsigned int time = 1500;
	Int0Configuration();
	LcdInit();
	Ds1302Init();
	while(1)
	{
		key=16;
        key = keynum();
		
        if(key==7)		//检测按键K2是否按下
		{   
		    led5=0;
			delay(20000);
			led5=1;
			Delay10ms();	//消除抖动
			if(key==7)
			{	
			    led5=0;
			    delay(20000);
			    led5=1;
				SetPlace=2;

				 
				if((TIME[SetPlace]>=0x0c) && (temp==0))		
				{
				    /*LcdWriteCom(0x80+0x40+10);
   	                LcdWriteData('P');LcdWriteData('M');   */
					TIME[SetPlace]=TIME[SetPlace]-18;
					APM = 2;
					temp = 1;	
				}
				else if((TIME[SetPlace]<0x0c)  &&  (temp==0))
				{	  
				    /*LcdWriteCom(0x80+0x40+10);
   	                LcdWriteData('A');LcdWriteData('M'); */
				    APM = 1;
					temp = 1;
				}
				else if((TIME[SetPlace]<0x0c)  &&  (APM==2))
				{
				    /*LcdWriteCom(0x80+0x40+10);
   	                LcdWriteData(' ');LcdWriteData(' ');*/
					TIME[SetPlace]=TIME[SetPlace]+18;
				    APM = 0;
					temp = 0;
				}
				else if((TIME[SetPlace]<0x0c)  &&  (APM==0))
				{
				    /*LcdWriteCom(0x80+0x40+10);
   	                LcdWriteData('A');LcdWriteData('M'); */
				    APM = 1;
					temp = 1;
				}
				else if((TIME[SetPlace]<0x0c)  &&  (APM==1))
				{
				    /*LcdWriteCom(0x80+0x40+10);
   	                LcdWriteData(' ');LcdWriteData(' '); */
					APM = 0;
					temp = 0;
				}
			 }

			while((i<50)&&(key==7))	 //检测按键是否松开
			{
				Delay10ms();
				i++;
			}
			i=0;
			
		}  

         if(APM == 0)
		{
		    LcdWriteCom(0x80+0x40+10);
   	        LcdWriteData(' ');LcdWriteData(' '); 
		}
		else if(APM == 1)
		{
		    LcdWriteCom(0x80+0x40+10);
   	        LcdWriteData('A');LcdWriteData('M'); 
		}
		else if(APM == 2)
		{
		    LcdWriteCom(0x80+0x40+10);
   	        LcdWriteData('P');LcdWriteData('M');
		}

		if(ClockFlag)
		{
			while(time>0)
			{
				time--;
				beep=0;
				i=150;
				while(i>0)
				{
					i--;
				}
				beep=1;
				i=150;
				while(i>0)
				{
					i--;
				}
			}
		}
		if(K4==0)
		{
		    led4=0;
			delay(20000);
			led4=1;
			Delay10ms();	//消除抖动
			if(K4==0)
			{
				while(!K4);	//等待按键释放
				SetClock = ~SetClock;
				LcdWriteCom(0x01);  //清屏
			}
		}
		if(SetClock == 0)
		{	
			DisplayTime();
			result=toCompare();	
			if(result)	//闹钟响起
				ClockFlag=1;
				
		}	
		else
			DisplayClock();			
	}	
}

/********************************************************************/
//函数名:delay_1ms(uint x)
//功能:利用定时器0精确定时1ms; 自加 time_t的值为后面时间调整函数服务
//调用函数:
//输入参数:x,1ms计数
//输出参数:
//说明:延时的时间为1ms乘以x
/********************************************************************/
void delay_1ms(uint x)
{
	TMOD=0X01;//开定时器0,工作方式为1
	TR0=1;//启动定时器0;
	while(x--)
	{
		TH0=0Xfc;//定时1ms初值的高8位装入TH0
		TL0=0X18;//定时1ms初值的低8位装入TL0
		while(!TF0);//等待,直到TF0为1
		TF0=0;
	}		
	TR0=0;//停止定时器0;
}


/**********************************************************/
//函数名:keyscan()
//功能:得出4x4键盘的行列扫描值
//调用函数:delay_1ms(uint x)
//输入参数:
//输出参数:
//说明:通过P1口的扫描得出扫描值key,无键按下key为16
/**********************************************************/
uchar keyscan()
{
 	uchar code_h;		//行扫描值
	uchar code_l;		//列扫描值
	P1=0XF0;			 //P1.0-P1.3全为0,(行状态全为低电平)
	if((P1&0xF0)!=0XF0)	//如果P1.4-P1.7不全为1,可能有键按下(为准确识别按键动作)
	{
	    delay_1ms(5);	//廷时去抖动,为准确识别按键动作
	    if((P1&0xF0)!=0XF0)//重读高4位(列状态),若还是不全为1,定有键按下
            {			
	        code_h=0xfe;  //开始行扫描 (0xfe:11111110)
	        while((code_h&0x10)!=0x00)//判断是否扫描四行(X0~X3)完毕,若不是,继续扫描(0x10:00010000)	 
               {
	           P1=code_h;	//第1次P1.0置为0,其余高电平;第2次P1.1置为0,其余高电平	;第3次P1.2置为0,其余高电平;第4次P1.3置为0,其余高电平
	           if((P1&0xF0)!=0XF0) //如果P1.4-P1.7不全为1,该行有键按下(0xF0:11110000)
                   {
		       		code_l=(P1&0xF0|0x0F);//保留P1口高4位,低4位变为1,作为列值
		       		return((~code_h)+(~code_l));//键盘编码=行扫描值+列扫描值 (取反后用,相当于改为按下按键对应的行、列标识为1,其它为0)				 
	           }
	           else                           //左移后补0,但是我们需要将其他位置1,所以+1
		       		code_h=(code_h<<1)|0x01;  //若该行无键按下,行扫描值左移+1,扫描下一行 
	         }
	     }
	 }
	return(16);	 //无键按下,返回16 
 }

/**********************************************************/
//函数名:keynum()
//功能:得出4x4按键的键值
//调用函数:keyscan()
//输入参数:
//输出参数:
//说明:通过key的值确定按键键值
/**********************************************************/
uint keynum()
{
    int i=0,j=0;
    int tab[4][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}; 
    //4x4键盘各键值标注
    key=16;
    key = keyscan();//引入key值
    if((key&0x01)!=0) i=0;	//判断出按下按键的行列号 (即找出低电平的行、列)
    if((key&0x02)!=0) i=1;
    if((key&0x04)!=0) i=2;
    if((key&0x08)!=0) i=3;
    if((key&0x10)!=0) j=0;
    if((key&0x20)!=0) j=1;
    if((key&0x40)!=0) j=2;
    if((key&0x80)!=0) j=3;
	key_num=key;
    if(key!=16) 
    {
   		key_num = tab[i][j];//通过比较得出4x4键盘的键值
    } 
	return key_num; 
}



/*******************************************************************************
* 函数名         : toCompare()
* 函数功能		 : 比较闹钟和时钟
* 输入           : 无
* 输出         	 : 0:时间不同		1:时间相同
*******************************************************************************/
unsigned char toCompare()
{
	unsigned char shi,fen;
	shi = (TIME[2]/16)*10 + TIME[2]&0x0f;
	fen = (TIME[1]/16)*10 + TIME[1]&0x0f;
	if((shi==C_shi)&&(fen==C_fen))
		return 1;
	else
		return 0;
}

/*******************************************************************************
* 函数名         : DisplayClock()
* 函数功能		 : 闹钟显示的函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void DisplayClock()
{	
	LcdInit();
	LcdWriteCom(0x80);
	LcdWriteData('C');LcdWriteData('l');LcdWriteData('o');LcdWriteData('c');LcdWriteData('k');LcdWriteData(':');
	
	if(K1==0)
	{
	    led1=0;
		delay(20000);
		led1=1;
	    
		Delay10ms();
		if(K1==0)
		{
		    led1=0;
			delay(20000);
			led1=1;
			while(!K1);	//等待按键释放
		   	ClockPlace = ~ClockPlace;
		}		
	}
	if(K2==0)
	{
	    led2=0;
		delay(2000);
		led2=1;
		Delay10ms();
		if(K2==0)
		{
		    led2=0;
			delay(20000);
			led2=1;
			while(!K2);
			if(ClockPlace == 0)
			{
				C_shi++;
				if(C_shi>23)
					C_shi=0;
				LcdWriteCom(0x80+0x40+6);
				LcdWriteCom(0x0f);
			}
			if(ClockPlace == 1)
			{
				C_fen++;
				if(C_fen>59)
					C_fen=0;
				LcdWriteCom(0x80+0x40+9);
				LcdWriteCom(0x0f);
			}
		}	
	}
	Delay10ms();
	LcdWriteCom(0x80+0x40+7);LcdWriteData(':');
	Delay10ms();
	write_sfm(5,C_shi);
	Delay10ms();
	write_sfm(8,C_fen);
	Delay10ms();
}

void write_sfm(uchar add,uchar date)	//在液晶上写时分秒
{
	uchar shi,ge;
	shi=date/10;
	ge=date%10;
	LcdWriteCom(0x80+0x40+add);		//说明显示位置
	LcdWriteData(shi+0x30);
	LcdWriteData(ge+0x30);
}

/*******************************************************************************
* 函数名         : DisplayTime()
* 函数功能		 : 时钟显示的函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void DisplayTime()
{
	unsigned char i;
	if(SetState==0)
	{
		Ds1302ReadTime();
	}
	else	//key3按下,进入校准界面
	{	
		count=0;

        if(temp==0)
		{
		    h = 0x23 ;		   	//此时为24小时制
		}
		else if(temp==1)
		{
		    h = 0x11;		   //此时为12小时制
		}

		if(K1==0)		//检测按键K1是否按下
		{
		    led1=0;
			delay(20000);
			led1=1;
			Delay10ms();	//消除抖动
			if(K1==0)
			{
		        led1=0;
			    delay(20000);
			    led1=1;	    
				SetPlace++;
				if(SetPlace>=7)
					SetPlace=0;
									
			}

			while((i<50)&&(K1==0))	 //检测按键是否松开
			{
				Delay10ms();
				i++;
			}
			i=0;
		}
		if(K2==0)		//检测按键K2是否按下
		{   
		    led2=0;
			delay(20000);
			led2=1;
			Delay10ms();	//消除抖动
			if(K2==0)
			{	
			    led2=0;
			    delay(20000);
			    led2=1;
				TIME[SetPlace]++;
				if((TIME[SetPlace]&0x0f)>9)					 //换成BCD码。
				{
					TIME[SetPlace]=TIME[SetPlace]+6;
				}
				if((TIME[SetPlace]>=0x60)&&(SetPlace<2))		//分秒只能到59
				{
					TIME[SetPlace]=0;
				}
				if((TIME[SetPlace]>h)&&(SetPlace==2))		//小时只能到23
				{
					TIME[SetPlace]=0;
					if(APM==1)
					{
					    APM=2;
					}
					else if(APM==2)
					{
					    APM=1;
					}
					
				}
				if((TIME[SetPlace]>=0x32)&&(SetPlace==3))		//日只能到31
				{
					TIME[SetPlace]=0;	
				}
				if((TIME[SetPlace]>=0x13)&&(SetPlace==4))		//月只能到12
				{
					TIME[SetPlace]=0;
				}	
				if((TIME[SetPlace]>=0x7)&&(SetPlace==5))		//周只能到7
				{
					TIME[SetPlace]=1;
				}		
//					if(SetPlace==5)		//月只能到12
//					{
//						TIME[SetPlace]=;
//					}	
			}
			
			while((i<50)&&(K2==0))	 //检测按键是否松开
			{
				Delay10ms();
				i++;
			}
			i=0;
			
		}
		key=16;
        key = keynum();
		
		if(key==4)		//检测减键是否按下
			{
			led3=0;
			delay(20000);
			led3=1;
				Delay10ms();	//消除抖动
				if(key==4)
				{
				led3=0;
			    delay(20000);
			    led3=1;
			    if(TIME[SetPlace]==0x00)
				{
				    count=1;
				}
				else if((TIME[SetPlace]&0x0f)==0x00)
				{
				   	   TIME[SetPlace]=TIME[SetPlace]-6;
				}
					TIME[SetPlace]--;
					//if(TIME[SetPlace]<0)					 //换成BCD码。
					//{
					//	TIME[SetPlace]=TIME[SetPlace]+10;
					//}
					if((count==1)&&(SetPlace<2))		//分秒只能到59
					{
						TIME[SetPlace]=0x59;
					}
					if((count==1)&&(SetPlace==2))		//小时只能到h
					{
						TIME[SetPlace]=h;
						if(APM==1)
					    {
					        APM=2;
					    }
					    else if(APM==2)
					    {
					    APM=1;
					    }
					}
					if((TIME[SetPlace]<=0x00)&&(SetPlace==3))		//日只能到31
					{
						TIME[SetPlace]=0x31;	
					}
					if((TIME[SetPlace]<=0x00)&&(SetPlace==4))		//月只能到12
					{
						TIME[SetPlace]=0x12;
					}	
					if((TIME[SetPlace]<=0x00)&&(SetPlace==5))		//周只能到7
					{
						TIME[SetPlace]=0x07;
					}		
//					if(SetPlace==5)		//月只能到12
//					{
//						TIME[SetPlace]=;
//					}	
				}

				
				while((i<50)&&(key==4))	 //检测按键是否松开
				{
					Delay10ms();
					i++;
				}
				i=0;	
			} 
								
	}
	LcdDisplay();	
}


/*******************************************************************************
* 函数名         : LcdDisplay()
* 函数功能		   : 显示函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/

void LcdDisplay()
{
	LcdWriteCom(0x80+0X40);
	LcdWriteData('0'+TIME[2]/16);				//时
	LcdWriteData('0'+(TIME[2]&0x0f));				 
	LcdWriteData('-');
	LcdWriteData('0'+TIME[1]/16);				//分
	LcdWriteData('0'+(TIME[1]&0x0f));	
	LcdWriteData('-');
	LcdWriteData('0'+TIME[0]/16);				//秒
	LcdWriteData('0'+(TIME[0]&0x0f));

	LcdWriteCom(0x80);
	LcdWriteData('2');
	LcdWriteData('0');
	LcdWriteData('0'+TIME[6]/16);			//年
	LcdWriteData('0'+(TIME[6]&0x0f));
	LcdWriteData('-');
	LcdWriteData('0'+TIME[4]/16);			//月
	LcdWriteData('0'+(TIME[4]&0x0f));
	LcdWriteData('-');
	LcdWriteData('0'+TIME[3]/16);			//日
	LcdWriteData('0'+(TIME[3]&0x0f));
	LcdWriteCom(0x8D);
	LcdWriteData('0'+(TIME[5]&0x07));	//星期			 
}
/*******************************************************************************
* 函数名         : Int0Configuration()
* 函数功能		   : 配置外部中断0
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/

void Int0Configuration()
{
	//设置INT0
	IT0=1;//跳变沿出发方式(下降沿)
	EX0=1;//打开INT0的中断允许。
	EA=1;//打开总中断	
}
/*******************************************************************************
* 函数名         : Int0() 
* 函数功能		   : 外部中断0 中断函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/

void Int0() interrupt 0		 
{
	Delay10ms();
	//keynum();
	if(K3==0)
	{
	    led3=0;
		delay(20000);
		led3=1;
		SetState=~SetState;
		SetPlace=0;
		Ds1302Init();	
	}
}
/*******************************************************************************
* 函数名         : Delay10ms
* 函数功能		   : 延时函数,延时10ms
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void Delay10ms(void)   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

2、led.c

#include"lcd.h"

/*******************************************************************************
* 函 数 名         : Lcd1602_Delay1ms
* 函数功能		   : 延时函数,延时1ms
* 输    入         : c
* 输    出         : 无
* 说    明         : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/

void Lcd1602_Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}

/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能		   : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/
#ifndef 	LCD1602_4PINS	 //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
#else 
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;	 //使能清零
	LCD1602_RS = 0;	 //选择写入命令
	LCD1602_RW = 0;	 //选择写入

	LCD1602_DATAPINS = com;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

//	Lcd1602_Delay1ms(1);
	LCD1602_DATAPINS = com << 4; //发送低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能		   : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/		   
#ifndef 	LCD1602_4PINS		   
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	  //使能清零
	LCD1602_RS = 1;	  //选择写入数据
	LCD1602_RW = 0;	  //选择写入

	LCD1602_DATAPINS = dat;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

	LCD1602_DATAPINS = dat << 4; //写入低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能		 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/		   
#ifndef		LCD1602_4PINS
void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#else
void LcdInit()						  //LCD初始化子程序
{
	LcdWriteCom(0x32);	 //将8位总线转为4位总线
	LcdWriteCom(0x28);	 //在四位线下的初始化
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#endif

3、ds1302.c

#include"ds1302.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0x55, 0, 0x12, 0x23, 0x03, 0x02, 0x21};

/*******************************************************************************
* 函 数 名         : Ds1302Write
* 函数功能		   : 向DS1302命令(地址+数据)
* 输    入         : addr,dat
* 输    出         : 无
*******************************************************************************/

void Ds1302Write(uchar addr, uchar dat)
{
	uchar n;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1; //然后将RST(CE)置高电平。
	_nop_();

	for (n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();
	}
	for (n=0; n<8; n++)//写入8位数据
	{
		DSIO = dat & 0x01;
		dat >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();	
	}	
		 
	RST = 0;//传送数据结束
	_nop_();
}

/*******************************************************************************
* 函 数 名         : Ds1302Read
* 函数功能		   : 读取一个地址的数据
* 输    入         : addr
* 输    出         : dat
*******************************************************************************/

uchar Ds1302Read(uchar addr)
{
	uchar n,dat,dat1;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1;//然后将RST(CE)置高电平。
	_nop_();

	for(n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}
	_nop_();
	for(n=0; n<8; n++)//读取8位数据
	{
		dat1 = DSIO;//从最低位开始接收
		dat = (dat>>1) | (dat1<<7);
		SCLK = 1;
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}

	RST = 0;
	_nop_();	//以下为DS1302复位的稳定时间,必须的。
	SCLK = 1;
	_nop_();
	DSIO = 0;
	_nop_();
	DSIO = 1;
	_nop_();
	return dat;	
}

/*******************************************************************************
* 函 数 名         : Ds1302Init
* 函数功能		   : 初始化DS1302.
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302Init()
{
	uchar n;
	Ds1302Write(0x8E,0X00);		 //禁止写保护,就是关闭写保护功能
	for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
	{
		Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);	
	}
	Ds1302Write(0x8E,0x80);		 //打开写保护功能
}

/*******************************************************************************
* 函 数 名         : Ds1302ReadTime
* 函数功能		   : 读取时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302ReadTime()
{
	uchar n;
	for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
	{
		TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
	}
		
}

4.DS1302.H

#ifndef __DS1302_H_
#define __DS1302_H_

//---包含头文件---//
#include<reg51.h>
#include<intrins.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;

//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();

//---加入全局变量--//
extern uchar TIME[7];	//加入全局变量

#endif

5、LCD.H

#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS

/**********************************
包含头文件
**********************************/
#include<reg51.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;

/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/	
void LcdWriteData(uchar dat);
/*LCD1602初始化子程序*/		
void LcdInit();						  

#endif

  • 3
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@小高同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值