反思:此项目在做的时候我是直接用单片机引脚去驱动数码管(P1口控制段选,P3口控制位选),发现单片机引脚不能直接控制驱动数码管,所以我在思考后加了74HC138和74HC573来驱动,138控制位选,573控制段选。所以我在原来的PCB基础上在洞洞板上焊接了驱动芯片。我在做PCB电路设计的时候,是因为仿真的时候是单片机引脚直接驱动数码管,然而通过此次教训,发现并不能如此去做。
       
 
个人思路:
       在整个工程中只需要去读取DS1302的时间数据,然后再用数码管去显示就行了。
       ①在按键修改时间部分,需要用一个bit标志位来区别是正常读取时间还是修改时间,用一个按键按下对bit标志位取反,进入修改时间的while循环。
       ②定义一个变量:u8 SetPlace = 0;//修改时间顺序:秒 分 时, 用一个按键让SetPlace变量一直累加,而 TIME[SetPlace] 就是当前被修改的时间,例如SetPlace = 0,TIME[SetPlace] 就是TIME数组的第一个数据,就是当前被修改的时间是秒。
       ③然后再用俩个按键去修改 TIME[SetPlace] 的值(时间加的话需要对这个值进行上限幅),就达到了修改TIME数组任意数据值的目的。
       ④然后再用一个按键去退出这个修改时间的while循环,并初始化DS1302,对DS1302写入修改后的时间。
DS1302介绍
       DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
 
DS1302结构
       DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据传送的方法。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc>2.0V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向)。SCLK为时钟输入端。
 
数据流
       在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
 
结论
       DS1302存在时钟精度不高,易受环境影响,出现时钟混乱等缺点。DS1302可以用于数据记录,特别是对某些具有特殊意义的数据点的记录,能实现数据与出现该数据的时间同时记录。这种记录对长时间的连续测控系统结果的分析及对异常数据出现的原因的查找具有重要意义。传统的数据记录方式是隔时采样或定时采样,没有具体的时间记录,因此,只能记录数据而无法准确记录其出现的时间;若采用单片机计时,一方面需要采用计数器,占用硬件资源,另一方面需要设置中断、查询等,同样耗费单片机的资源,而且,某些测控系统可能不允许。但是,如果在系统中采用时钟芯片DS1302,则能很好地解决这个问题。

引脚图

Alt

电路图

在这里插入图片描述

PCB图

在这里插入图片描述

实物图

在这里插入图片描述

在这里插入图片描述

实物演示视频

百度网盘链接  (点击蓝色字体即可跳转)
提取码:fmg1

代码

建议:只参考思路,不要直接复制粘贴,否则无法进步。

主函数

//主函数
void main()
{
//	Ds1302Init();//DS1302初始化  第一次写入后需注释掉再下一遍,否则每次上电都会初始化时间
	Timer0_Init();//定时器0初始化
	while(1)
	{
		Timepros();//时间处理
		SMG_Display();//时间显示
		Key_scan();//按键扫描
	}
}

数码管驱动

//数码管位置及数据显示   w;位置  dat;数据
void SMG_dat(u8 w,u8 dat)
{
	Choose_W(w);//位选
	P1 = smgduan[dat];//段选
	delay_ms(1);//延时
}

//74HC138显示位数选择
void Choose_W(u8 w)
{
	switch(w)	 //位选,选择点亮的数码管
	{
		case(1):
			LSA=0;LSB=0;LSC=0; break;//显示第1位
		case(2):
			LSA=1;LSB=0;LSC=0; break;//显示第2位
		case(3):
			LSA=0;LSB=1;LSC=0; break;//显示第3位
		case(4):
			LSA=1;LSB=1;LSC=0; break;//显示第4位
		case(5):
			LSA=0;LSB=0;LSC=1; break;//显示第5位
		case(6):
			LSA=1;LSB=0;LSC=1; break;//显示第6位
		case(7):
			LSA=0;LSB=1;LSC=1; break;//显示第7位
		case(8):
			LSA=1;LSB=1;LSC=1; break;//显示第8位
	}
}

数码管显示

//数码管显示
void SMG_Display()
{
	SMG_dat(1,TIME[2]/16);	  //时十位
	SMG_dat(2,TIME[2]&0x0f);  //时个位
	SMG_dat(3,10);			  //-
	SMG_dat(4,TIME[1]/16);    //分十位
	SMG_dat(5,TIME[1]&0x0f);  //分个位
	SMG_dat(6,10);			  //-
	SMG_dat(7,TIME[0]/16);    //秒十位
	SMG_dat(8,TIME[0]&0x0f);  //秒个位
	
	if(Flag)//LED 1秒闪烁一次
	{
		LED = 1;
	}
	else
	{
		LED = 0;
	}
}

按键修改时间

//时间处理
void Timepros()
{
	if(keynumber == 1)
	{
		keynumber = 0;
		Flag_1 =~ Flag_1;//修改时间标志位取反
	}
	if(!Flag_1)//0取非为1  正常读取时间
	{
		Ds1302ReadTime();//读取时间
	}
	else
	{
		TR0 = 0;//关闭定时器0
		SetPlace = 0;
		while(1)
		{
			LED = 1;   //LED常亮
			Key_scan();//按键扫描
			if(keynumber == 4)  //按键K4  修改时间顺序:秒 分 时
			{
				keynumber = 0;
				SetPlace++;
				if(SetPlace >= 3) //大于等于3则为0
				{
					SetPlace = 0;
				}
			}
			if(keynumber == 2)  //时间加
			{
				keynumber = 0;
				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]>=0x24)&&(SetPlace==2))		//小时只能到23
				{
					TIME[SetPlace]=0;
				}
			}
			if(keynumber == 3)  //时间减
			{
				keynumber = 0;
				TIME[SetPlace]--;//时间减
				if((TIME[SetPlace]&0x0f)>9)					 //换成BCD码
				{
					TIME[SetPlace]=TIME[SetPlace]-6;
				}
				if((TIME[SetPlace]<=0x00)&&(SetPlace<2))		//分秒只能到59
				{
					TIME[SetPlace]=0x59;
				}
				if((TIME[SetPlace]<=0x00)&&(SetPlace==2))		//小时只能到23
				{
					TIME[SetPlace]=0x23;
				}
			}
			if(keynumber == 5)  //写入修改好的时间  退出 
			{
				keynumber = 0;
				SetPlace = 0;
				Ds1302Init(); //DS1302初始化
				Flag_1 = 0;   //开始正常计时
				TR0 = 1;      //打开定时器0
				break;
			}
			if(keynumber == 1)  //不写入修改好的时间  退出 
			{
				keynumber = 0;
				SetPlace = 0;
				Flag_1 = 0;   //开始正常计时
				TR0 = 1;      //打开定时器0
				break;
			}
			SMG_Display();//数码管显示
		}
	}
}

按键扫描

//按键扫描
void Key_scan()
{
	if(K1 == 0)//K1按下
	{
		delay_ms(10);//消抖
		if(K1 == 0)
		{
			keynumber = 1;
			while(K1 == 0);//松手检测
		}
	}
	if(K2 == 0)//K2按下
	{
		delay_ms(10);//消抖
		if(K2 == 0)
		{
			keynumber = 2;
			while(K2 == 0);//松手检测
		}
	}
	if(K3 == 0)//K3按下
	{
		delay_ms(10);//消抖
		if(K3 == 0)
		{
			keynumber = 3;
			while(K3 == 0);//松手检测
		}
	}
	if(K4 == 0)//K4按下
	{
		delay_ms(10);//消抖
		if(K4 == 0)
		{
			keynumber = 4;
			while(K4 == 0);//松手检测
		}
	}
	if(K5 == 0)//K5按下
	{
		delay_ms(10);//消抖
		if(K5 == 0)
		{
			keynumber = 5;
			while(K5 == 0);//松手检测
		}
	}
}