【完美解决】ds1302外置时钟模块重复初始化时间问题(单片机掉电,模块电池供电)

芯片介绍:

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。【完美解决】ds1302外置时钟模块重复初始化时间问题(单片机掉电,模块电池供电)_第1张图片
模块实物图:
淘宝购买的模块,物美价廉。
【完美解决】ds1302外置时钟模块重复初始化时间问题(单片机掉电,模块电池供电)_第2张图片

一、问题描述

DS1302时钟模块,通过单片机设置好时间后,由纽扣电池供电应当一直正常工作。但是单片机掉电再重新上电后,会导致模块重复初始化,使时间回到起点,与实际需求不符。单片机单纯上电直接初始化时间,有些不妥。

二、解决方法

方案一:
1.先烧录正常初始化时间的代码。
2.注释初始化时间的代码再次烧录。
点评:此方案可以解决问题,需要重复烧录两次,不够方便,故不作重点讨论。

方案二:
每次设置时间后,使用一个eeprom或者flash等掉电不丢失数据的记忆芯片,写入一个标记,表明已经初始化时间。系统重启只需读取是否这个标记,若有,则不需初始化。反之,则初始化时间。
点评:
此方案可以解决问题,需要额外芯片,有一定的局限性,故也不推荐。

仔细翻阅ds1302手册,发现它本身是支持31字节的ram。在方案二的思路上,使用这些ram做标记就很方便了。
在这里插入图片描述
【完美解决】ds1302外置时钟模块重复初始化时间问题(单片机掉电,模块电池供电)_第3张图片
地址C0到FC,读地址是写地址+1,储存数值00~ff之间的任意值、
写地址:c0 c2 c4 … fc
读地址:c1 c3 c5 … fd
如:在c0地址写入3a数值,读c1地址若为3a,则说明上次已经标记。

方案三:
在方案二思路上,使用内部ram空间做标记。单片机重启时,读取有无标记,若有,则不需初始化。反之,则初始化时间。
点评:推荐方案,方便快捷。缺点是代码稍复杂。

笔者使用stm32f1系列单片机亲测,切实可行。

关键代码:

ds1302头文件:

#define WRITE_FLAG_ADDR  0xc0 
#define READ_FLAG_ADDR   0xc1 
#define FLAG_VAL         0x3a 

解释:
定义三个宏,分别是写地址,读地址,和标记数值。
注意:读地址为写地址+1。(数据手册有图)
ds1302头文件:

设置时间函数

void ds1032_set_time(u16 year,u8 mon,u8 day,u8 hour,u8 min,u8 sec)
{
	year -= 2000; //年默认2000开始
	if(year > 100) year = 0; 
	
	// 10转为bdc码
	year = ((year /10) << 4) + year %10;
	mon  = ((mon  /10) << 4) + mon  %10;
	day  = ((day  /10) << 4) + day  %10;
	hour = ((hour /10) << 4) + hour %10;
	min  = ((min  /10) << 4) + min  %10;
	sec  = ((sec  /10) << 4) + sec  %10;
	
	// 写入寄存器,同时标记一个地址
	ds1302_wirte_rig(0x8e,0x00);//关闭写保护
	ds1302_wirte_rig(WRITE_FLAG_ADDR,FLAG_VAL);//写入已经设置时间标记
	ds1302_wirte_rig(0x80,sec);//seconds秒
	ds1302_wirte_rig(0x82,min);//minutes分
	ds1302_wirte_rig(0x84,hour);//hours时
	ds1302_wirte_rig(0x86,day);//date日
	ds1302_wirte_rig(0x88,mon);//months月
	ds1302_wirte_rig(0x8c,(u8) year);//year年
	// ds1302_wirte_rig(0x8a,7);// 星期日
	ds1302_wirte_rig(0x8e,0x80);//开启写保护
}

初始化时间函数:

void ds1032_init_time(void)
{
	if(ds1302_read_rig(READ_FLAG_ADDR)!= FLAG_VAL) // 如果未标记,执行初始化时间
    {
		ds1032_set_time(2020,12,31,23,59,30);// 2020年12月31日,23:59:30
		printf("Y时间初始化完成,标记:%x\r\n",ds1302_read_rig(READ_FLAG_ADDR));
	}
	else
	{
		printf("N时间不用重复初始化,标记:%x\r\n",ds1302_read_rig(READ_FLAG_ADDR));
	}
	
}

解释:
先判断有无标记,有则执行ds1032_set_time,否则不执行。

main源文件:
使用示例
【完美解决】ds1302外置时钟模块重复初始化时间问题(单片机掉电,模块电池供电)_第4张图片
实物效果图:
【完美解决】ds1302外置时钟模块重复初始化时间问题(单片机掉电,模块电池供电)_第5张图片

你可能感兴趣的:(c,keil,stm32,单片机,stm32,嵌入式)