DS1302的底层解释

DS1302 是一款专门用来计时的芯片,你可以把它想象成一个**“住在小房子里的时间管家”**。

你的单片机(MCU)就是**“主人”**。主人想知道现在几点了,或者想调整时间,就要通过三根线跟管家交流。

为了让你听懂,我们给这三根线起个外号:

  1. RST (1.3引脚)“大门”。RST=1 时,门打开,管家才听你说话;RST=0 时,门锁死,管家去睡觉。

  2. SCK (1.7引脚)“闹钟”。每叮嘱一声(电平从低变高),管家就收发一个动作。

  3. SDA (2.3引脚)“小纸条”。数据(0或1)就是通过这张纸条传给管家或者由管家传给你。


第一部分:基本的传话方式(写一个字节)

C

void Write_Ds1302(unsigned char temp) 
{
    unsigned char i;
    for (i=0;i<8;i++) // 传8张小纸条
    { 
        SCK = 0;      // 闹钟按下去(准备)
        SDA = temp&0x01; // 把数字最后一位写在纸条上
        temp>>=1;     // 把下一位数字挪到最后
        SCK=1;        // 闹钟响一声(管家:收到了!)
    }
}

大白话解释:管家很笨,一次只能看一个数字(0或1)。所以你要发一个 8 位的数字,得重复 8 次:按闹钟 → 贴纸条 → 移位 → 响闹钟。


第二部分:向管家下达命令(写寄存器)

C

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
    RST=0; _nop_();
    SCK=0; _nop_();
    RST=1; _nop_();  // 第一步:推开管家的门(RST=1)
    Write_Ds1302(address); // 第二步:告诉管家,我要动哪个抽屉(地址)
    Write_Ds1302(dat);     // 第三步:把要存的东西放进去(数据)
    RST=0; // 第四步:关上门,管家去干活了
}

大白话解释:你要管家办事,得先推门进去(RST=1),告诉他去哪个抽屉(比如“时钟抽屉”),然后把东西丢给他,最后关门走人。


第三部分:问管家要答案(读寄存器)

C

unsigned char Read_Ds1302_Byte ( unsigned char address )
{
    unsigned char i,temp=0x00;
    RST=1; // 开门
    Write_Ds1302(address); // 问管家:几号抽屉里的东西给我看看?
    for (i=0;i<8;i++)      // 管家一张一张递纸条出来
    {        
        SCK=0;             // 闹钟按下去
        temp>>=1;          // 准备接下一张纸条
        if(SDA) temp|=0x80; // 如果纸条上是1,就记下来
        SCK=1;             // 响一声闹钟(管家:拿稳了,下一张!)
    } 
    RST=0; // 关门
    return (temp); // 拿到完整的答案
}

大白话解释:你想知道时间,得先开门进去,告诉管家你想看哪个抽屉。管家会根据你的闹钟节奏,一张纸条(位)一张纸条地把答案递给你。


第四部分:设置和读取“时间全家桶”

C

void Set_Rtc(unsigned char* ucRtc)
{
    Write_Ds1302_Byte(0x8e,0x00); // 1. 先把管家的“写保护锁”打开
    for(i=0;i<3;i++)
        Write_Ds1302_Byte(0x84-2*i,ucRtc[i]); // 2. 依次把时、分、秒塞进抽屉
    Write_Ds1302_Byte(0x8e,0x80); // 3. 重新把锁锁上,防止被乱改
}

  • 0x8e:这就是管家的“保险柜锁”。不打开它(写0x00),你改不了时间。

  • 0x84, 0x82, 0x80:分别是“小时”、“分钟”、“秒”的抽屉号码。

C

void Read_Rtc(unsigned char* ucRtc)
{
    unsigned char i;
    for(i=0;i<3;i++)
        ucRtc[i] = Read_Ds1302_Byte(0x85-2*i); // 依次找管家要时、分、秒
}

  • 0x85, 0x83, 0x81:这是对应的“读取”抽屉号。

:warning: 最重要的“弱智”知识点:

  1. BCD码(特殊暗号)

    管家不认识普通的数字。如果你想存 15 分钟,你不能直接传 15。你要传 0x15

    • 普通的 15 是 0000 1111

    • BCD码的 15 是 0001 0101(就像是把 1 和 5 强行拼在一起)。

    • 所以你在外面用的时候,一定要记得转换!

  2. 为什么要 _nop_()

    单片机跑得太快了,管家反应慢。_nop_() 就是让单片机稍微等管家一下,别把管家累坏了。

  3. SCK 闹钟的节奏

    写数据时,管家是在闹钟**响的那一下(上升沿)看纸条;读数据时,管家是在闹钟按下去的那一下(下降沿)**递纸条给你。

总结:这套代码就是一套**“开门 → 摇铃铛 → 塞/拿纸条 → 关门”**的动作流程。只要流程对了,时间管家就能帮你把时间记好。