前言:

DS1302时钟芯片是常用的时钟芯片,在我们使用时,常会遇到一个问题:小时寄存器到底该怎么设置?如何通过这个寄存器实现12/24小时制状态查询和切换、上下午状态的查询和切换呢?就让我们来深入讨论一下这个信息量有点多的“小时寄存器”吧!

一、我遇到的问题:

当我就想做一个功能较完善的时钟:有12/24小时制切换,在12小时制模式时可以显示上午、下午的状态、有闹铃功能等等......

当我在实现“12/24小时制切换,在12小时制模式时可以显示上午、下午的状态”这个需求时,遇到了问题:在切换到12小时制的时候,时间设置、显示变得紊乱,不符合预期

这个时候,就需要好好研究一下DS1302中的这个时间寄存器了,它的结构见下图:

这个小时寄存器,共有三个关键信息:

        BIT7:12/24小时制信息,0代表24小时制,也是默认状态;

        BIT5:这个位又分为两个用途

                用途一:在12小时制的模式,代表上下午状态,0代表上午,1代表下午。

                用途二:在24小时制的模式,代表小时十位的“2”。

        BIT5-BIT0:时间信息

现在。回头来看当时我遇到的问题的原因有两点:

  •  问题一:将设置DS1302的小时寄存器的时间信息、12/24小时制工作模式、上下午状态分开操作并且操作逻辑混乱;
  • 问题二:读取DS1302小时寄存器的时间数据后没有正确处理:没有将12/24小时制工作模式、上下午状态和时间信息进行剥离。

接下来,我们就将这两个问题展开。

二、问题的解决

问题一,这个问题的根源是寄存器的时间信息、12/24小时制工作模式、上下午状态三个独立的信息写到寄存器中,在写一个信息的同时要保证不影响其它信息。我的方案是:先将信息合并到一起,再调用写入函数一次写入。部分代码如下:

//创建时钟结构体
struct Clock_time
{
	unsigned char DS1302_Time[7];	//ds1302芯片内读取到的时间(年月日时分秒),存储BCD码
	unsigned char Clock_Time[7];	//时钟时间(年月日时分秒),存储转换后的十进制码
	unsigned char Clock_12H_24H;	//12/24小时制,0代表24小时制,1代表12小时制
	unsigned char Clock_AM_PM;		//上下午状态,0代表上午,1代表下午
}Clock;


//设置12/24小时制信息
if (Clock.Clock_12H_24H == 0)//24小时制
{
	Clock.DS1302_Time[3] &= 0x7f;//Clock.DS1302_Time[3]数组的第四个元素存储的是小时寄存器的数据,将BIT7设置为0
}
if (Clock.Clock_12H_24H == 1)//12小时制
{
	Clock.DS1302_Time[3] |= 0x80;//将BIT7设置为1
}
//设置上下午信息
if (Clock.Clock_AM_PM == 0)//上午
{
	Clock.DS1302_Time[3] &= 0xdf; //将BIT5设置为0
}
if (Clock.Clock_AM_PM == 1)//下午
{
	Clock.DS1302_Time[3] |= 0x20; //将BIT5设置为0
}

经过上述代码的处理后,就将12/24小时制信息、上下午信息、时间信息合并到一起了,在此之后调用写入函数将信息写入到芯片中即可完成对小时寄存器的设置。

问题二:时间显示错误的根源是读取小时寄存器的数据后,没有将12/24小时制、上下午信息剔除,导致小时位显示81、35这样离谱的数字。

我的解决方案是:单独写了两个获取12/24小时工作模式信息和上下午信息的函数,并将读取到的小时寄存器内的时间信息进行正确的修剪,部分代码如下:

void Clock_Read_Time(void)
{
	unsigned char i = 0;
	DS1302_Read_Time(Clock.DS1302_Time);
	Clock.Clock_12H_24H = DS1302_Read_12_24_State();//获取12/24小时工作模式信息
	Clock.Clock_AM_PM = DS1302_Read_AM_PM_State();//获取上下午信息
    if(Clock.Clock_12H_24H == 0)//24小时制
    {
        Clock.DS1302_Time[3] &= 0x3f;//时寄存器,将12/24小时制信息剔除
    }
    else//12小时制
    {
        Clock.DS1302_Time[3] &= 0x1f;//时寄存器,将12/24小时制、上下午信息剔除
    }
	
}

三、BCD码

最后,我们聊聊这个BCD码。

BCD码,是使用二进制直接表示十进制的编码方式,核心规则是:用4位二进制数对应十进制的1位数(1-9)。

举例:

        十进制数:10

        二进制数:0001 0000

这和我们之前了解的二进制数和十进制数的转换是有区别的;

如果是转换,十进制的10应该对应二进制的1010

再说回小时寄存器,如果是12小时制,下午1点,寄存器的数值应该是:1010  0001,对于这个值,我们处理的时候也必须按照BCD码格式去处理,否则就会出错。

这就是我在使用DS1302做一个时钟的时候遇到的问题,现在分享出来,希望能帮助大家避坑。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐