51单片机(六) --- DS1302 实时时钟芯片
·
一、DS1302 是什么?
DS1302 是美国 Dallas 公司推出的一款低功耗、带 RAM 的实时时钟芯片。它的核心功能是为嵌入式系统提供秒、分、时、日、月、周、年的时间信息,并且可以通过备用电池供电,在主电源断电的情况下依然能持续计时。
核心参数与特性
- 工作电压:2.0V ~ 5.5V,低功耗设计,适合电池供电场景。
- 通信方式:三线同步串行接口(
CE使能、SCLK时钟、I/O数据),无需 I2C 或 SPI,占用资源少。 - 数据格式:所有时间数据均为 BCD 码 格式(例如 59 秒表示为
0x59)。 - 内置 RAM:31 字节静态 RAM,可存储用户自定义数据。
- 单字节传输:每次读写一个字节,不支持突发模式,但可通过连续操作模拟。
二、硬件连接与引脚定义
DS1302 采用三线制通信,原理图如下:

引脚功能说明:

三、核心寄存器配置
DS1302 通过一组专用寄存器来存储和控制时间,所有寄存器均为 8 位,地址分为读地址和写地址。
1. 时间寄存器地址
| 功能 | 读地址 | 写地址 | 数据格式 | 取值范围 |
|---|---|---|---|---|
| 秒 | 0x81 |
0x80 |
BCD | 00-59 |
| 分 | 0x83 |
0x82 |
BCD | 00-59 |
| 时 | 0x85 |
0x84 |
BCD | 1-12/0-23 |
| 日 | 0x87 |
0x86 |
BCD | 1-31 |
| 月 | 0x89 |
0x88 |
BCD | 1-12 |
| 周 | 0x8B |
0x8A |
BCD | 1-7 |
| 年 | 0x8D |
0x8C |
BCD | 00-99 |
2. 写保护寄存器(0x8E)
- 该寄存器的第 7 位(
WP位)控制写保护功能:WP=1:开启写保护,禁止向时间寄存器写入数据。WP=0:关闭写保护,允许写入数据。
- 初始化时必须先关闭写保护,设置完成后再开启,防止意外修改。
四、通信时序
DS1302 的通信分为写操作和读操作,两者时序不同,是驱动编写的关键。
1. 写操作时序

写操作的流程是:拉高 CE → 发送命令字节(先传低位) → 发送数据字节(先传低位) → 拉低 CE。
关键规则:
- SCLK 下降沿写入数据:在 SCLK 由高变低时,DS1302 会锁存 I/O 线上的数据。
- 先传最低位(LSB First):无论是命令还是数据,都必须从最低位开始发送。
2. 读操作时序

读操作的流程是:拉高 CE → 发送命令字节(先传低位) → 读取数据字节(先传高位) → 拉低 CE。
关键规则:
- SCLK 上升沿读取数据:在 SCLK 由低变高时,DS1302 会将数据输出到 I/O 线上。
- 数据位先出最高位(MSB First):读取数据时,数据是从最高位开始输出的,这一点和写操作相反,需要特别注意。
五、DS1302驱动代码
1. 引脚定义与全局变量
#include "ds1302.h"
#include "public.h"
#include <intrins.h>
// 引脚定义(根据实际电路修改)
sbit DS1302_RST = P3^5; // CE/复位引脚
sbit DS1302_CLK = P3^4; // SCLK时钟引脚
sbit DS1302_IO = P3^6; // I/O数据引脚
// DS1302读/写地址命令(秒、分、时、日、周、月、年)
u8 gREAD_RTC_ADDR[7] = {0x81,0x83,0x85,0x87,0x89,0x8B,0x8D};
u8 gWRITE_RTC_ADDR[7] = {0x80,0x82,0x84,0x86,0x88,0x8A,0x8C};
// 初始时间:2026年3月18日 周三 14:10:06(BCD格式:秒分时日周月年)
u8 gDS1302_TIME[7] = {0x06,0x10,0x14,0x18,0x03,0x03,0x26};
2. 写一个字节函数
/*********************************************************
函数名:ds1302_write_byte
功能:向DS1302写入一个字节(命令或数据)
*********************************************************/
void ds1302_write_byte(u8 addr, u8 dat)
{
u8 i = 0;
DS1302_RST = 0; // CE拉低,默认不使能
_nop_();
DS1302_CLK = 0; // SCLK拉低,默认时钟低电平
_nop_();
DS1302_RST = 1; // CE拉高,开始通信
// 1. 写地址/命令(LSB先行,下降沿写入)
for(i = 0; i < 8; i++)
{
DS1302_IO = addr & 0x01; // 先取最低位
addr >>= 1; // 右移取下一位
// 产生SCLK下降沿
DS1302_CLK = 1;
_nop_();
DS1302_CLK = 0;
_nop_();
}
// 2. 写数据(LSB先行,下降沿写入)
for(i = 0; i < 8; i++)
{
DS1302_IO = dat & 0x01; // 先取最低位
dat >>= 1;
DS1302_CLK = 1;
_nop_();
DS1302_CLK = 0;
_nop_();
}
DS1302_RST = 0; // CE拉低,结束传输
_nop_();
}
3. 读一个字节函数
/*********************************************************
函数名:ds1302_read_byte
功能:从DS1302读取一个字节数据
*********************************************************/
u8 ds1302_read_byte(u8 addr)
{
u8 i = 0;
u8 value = 0;
u8 temp = 0;
DS1302_RST = 0; // CE拉低
_nop_();
DS1302_CLK = 0; // SCLK拉低
_nop_();
DS1302_RST = 1; // CE拉高,开始通信
_nop_();
// 1. 写地址/命令(LSB先行,下降沿写入)
for(i = 0; i < 8; i++)
{
DS1302_IO = addr & 0x01;
addr >>= 1;
DS1302_CLK = 1;
_nop_();
DS1302_CLK = 0;
_nop_();
}
// 2. 读数据(MSB先行,上升沿读取)
for(i = 0; i < 8; i++)
{
temp = DS1302_IO; // 读取1位数据
value = (temp << 7) | (value >> 1); // 高位优先存入value
DS1302_CLK = 1; // 上升沿触发读取
_nop_();
DS1302_CLK = 0;
_nop_();
}
// 总线恢复
DS1302_CLK = 1;
_nop_();
DS1302_IO = 0;
_nop_();
DS1302_IO = 1;
_nop_();
return value;
}
4. 初始化函数(设置时间)
/*********************************************************
函数名:ds1302_init
功能:初始化DS1302,设置初始时间并开启写保护
*********************************************************/
void ds1302_init(void)
{
u8 i = 0;
ds1302_write_byte(0x8E, 0x00); // 第一步:关闭写保护
// 第二步:循环写入秒、分、时、日、周、月、年数据
for(i = 0; i < 7; i++)
{
ds1302_write_byte(gWRITE_RTC_ADDR[i], gDS1302_TIME[i]);
}
ds1302_write_byte(0x8E, 0x80); // 第三步:开启写保护,防止误写
}
5. 读取时间函数
/*********************************************************
函数名:ds1302_read_time
功能:读取当前时间并存入全局数组gDS1302_TIME
*********************************************************/
void ds1302_read_time(void)
{
int i = 0;
// 循环读取7个时间数据
for(i = 0; i < 7; ++i)
{
gDS1302_TIME[i] = ds1302_read_byte(gREAD_RTC_ADDR[i]);
}
}
六、总结
6.1 通信时序
-
使能脚 CE (RST) 必须先拉高通信开始前
CE=1,结束后CE=0,只有 CE 拉高通信才有效。 -
写数据:下降沿写入,先传低位(LSB 先行)
- 时钟线 SCLK 下降沿 写入数据
- 命令 / 数据 从最低位开始发
-
读数据:上升沿读取,先出高位(MSB 先行)
- 时钟线 SCLK 上升沿 读取数据
- DS1302 输出数据 从最高位开始出→ 读写位序相反,这是最容易错的点!
-
必须加空操作
_nop_()保证时序稳定,满足芯片最小脉冲宽度。
6.2 寄存器关键
-
写保护寄存器 0x8E
- 写时间前:必须写入
0x00关闭写保护 - 写完时间:必须写入
0x80打开写保护→ 不关闭写保护,根本写不进时间。
- 写时间前:必须写入
-
时间数据格式:BCD 码例如 25 分 → 存
0x25,不是 25。显示时必须转十进制:
十进制 = (BCD码 >>4)*10 + (BCD码 & 0x0F)
3. 7 个时间寄存器顺序固定: 秒 → 分 → 时 → 日 → 周 → 月 → 年
6.3 代码编写注意事项
-
IO 口是双向的读数据前要释放总线,避免单片机引脚电平干扰。
-
读写地址成对出现写:0x80 秒 / 读:0x81 秒写地址最低位 = 0,读地址最低位 = 1。
-
初始化只执行一次不要每次上电都重新设时间,否则断电记忆失效。
-
通信时尽量关闭中断中断会打乱时序,导致读写出错。
6.4 硬件注意点
- 必须接 32.768kHz 晶振,否则不走时。
- 必须接 备用电池(3V),才能断电走时。
- 工作电压 2.0~5.5V,3.3V/5V 单片机都能用。
DS1302 是三线制 RTC,驱动关键是 CE 使能、SCLK 沿触发、读写位序相反、必须关闭写保护、数据是 BCD 码,时序必须严格遵守。
更多推荐


所有评论(0)