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

17 篇文章 6 订阅
4 篇文章 5 订阅

芯片介绍:

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。在这里插入图片描述
模块实物图:
淘宝购买的模块,物美价廉。
在这里插入图片描述

一、问题描述

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

二、解决方法

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

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

仔细翻阅ds1302手册,发现它本身是支持31字节的ram。在方案二的思路上,使用这些ram做标记就很方便了。
在这里插入图片描述
在这里插入图片描述
地址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源文件:
使用示例
在这里插入图片描述
实物效果图:
在这里插入图片描述

  • 30
    点赞
  • 138
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
以下是一个基于51单片机DS1302时钟模块使用代码示例: ```c #include <REG52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int sbit RST = P3^4; sbit DAT = P3^5; sbit CLK = P3^6; // 延时函数 void Delay(uint i) { while(i--); } // 向DS1302写入一个字节 void DS1302_WriteByte(uchar dat) { uchar i; for (i = 0; i < 8; i++) { DAT = dat & 0x01; CLK = 0; CLK = 1; dat >>= 1; } } // 从DS1302读取一个字节 uchar DS1302_ReadByte() { uchar i, dat = 0; for (i = 0; i < 8; i++) { dat >>= 1; if (DAT) dat |= 0x80; CLK = 0; CLK = 1; } return dat; } // 启动DS1302时钟 void DS1302_Start() { RST = 1; CLK = 1; _nop_(); _nop_(); _nop_(); RST = 0; DS1302_WriteByte(0x8e); DS1302_WriteByte(0x00); RST = 1; } // 停止DS1302时钟 void DS1302_Stop() { RST = 0; CLK = 0; _nop_(); _nop_(); _nop_(); RST = 1; DS1302_WriteByte(0x8e); DS1302_WriteByte(0x80); RST = 1; } // 写入DS1302时间 void DS1302_WriteTime(uchar year, uchar month, uchar day, uchar hour, uchar minute, uchar second) { DS1302_Start(); DS1302_WriteByte(0xbe); DS1302_WriteByte(second); DS1302_WriteByte(minute); DS1302_WriteByte(hour); DS1302_WriteByte(day); DS1302_WriteByte(month); DS1302_WriteByte(year); DS1302_Stop(); } // 读取DS1302时间 void DS1302_ReadTime(uchar *year, uchar *month, uchar *day, uchar *hour, uchar *minute, uchar *second) { DS1302_Start(); DS1302_WriteByte(0xbf); *second = DS1302_ReadByte(); *minute = DS1302_ReadByte(); *hour = DS1302_ReadByte(); *day = DS1302_ReadByte(); *month = DS1302_ReadByte(); *year = DS1302_ReadByte(); DS1302_Stop(); } void main() { uchar year, month, day, hour, minute, second; DS1302_WriteTime(0x21, 0x10, 0x13, 0x10, 0x30, 0x00); while (1) { DS1302_ReadTime(&year, &month, &day, &hour, &minute, &second); printf("20%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second); Delay(1000); } } ``` 在上述代码中,定义了DS1302的RST、DAT、CLK引脚,以及自定义了延时函数`Delay`。然后定义了向DS1302写入一个字节的函数`DS1302_WriteByte`,从DS1302读取一个字节的函数`DS1302_ReadByte`,启动DS1302时钟的函数`DS1302_Start`,停止DS1302时钟的函数`DS1302_Stop`,写入DS1302时间的函数`DS1302_WriteTime`,以及读取DS1302时间的函数`DS1302_ReadTime`。 在`main`函数中,首先调用`DS1302_WriteTime`函数设置初始时间,然后通过`DS1302_ReadTime`函数读取当前时间,并通过串口输出。最后通过`Delay`函数延迟1秒,实现时钟的运行。需要注意的是,DS1302时钟模块时间格式为BCD码,需要进行转换才能得到实际的时间

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值