一、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 通信时序

  1. 使能脚 CE (RST) 必须先拉高通信开始前 CE=1,结束后 CE=0只有 CE 拉高通信才有效

  2. 写数据:下降沿写入,先传低位(LSB 先行)

    • 时钟线 SCLK 下降沿 写入数据
    • 命令 / 数据 从最低位开始发
  3. 读数据:上升沿读取,先出高位(MSB 先行)

    • 时钟线 SCLK 上升沿 读取数据
    • DS1302 输出数据 从最高位开始出读写位序相反,这是最容易错的点!
  4. 必须加空操作 _nop_()保证时序稳定,满足芯片最小脉冲宽度。

6.2 寄存器关键

  1. 写保护寄存器 0x8E

    • 写时间前:必须写入 0x00 关闭写保护
    • 写完时间:必须写入 0x80 打开写保护→ 不关闭写保护,根本写不进时间
  2. 时间数据格式:BCD 码例如 25 分 → 存 0x25,不是 25。显示时必须转十进制:

十进制 = (BCD码 >>4)*10 + (BCD码 & 0x0F)

      3. 7 个时间寄存器顺序固定:  秒 → 分 → 时 → 日 → 周 → 月 → 年

6.3 代码编写注意事项

  1. IO 口是双向的读数据前要释放总线,避免单片机引脚电平干扰。

  2. 读写地址成对出现写:0x80 秒 / 读:0x81 秒写地址最低位 = 0,读地址最低位 = 1。

  3. 初始化只执行一次不要每次上电都重新设时间,否则断电记忆失效。

  4. 通信时尽量关闭中断中断会打乱时序,导致读写出错。

6.4 硬件注意点

  1. 必须接 32.768kHz 晶振,否则不走时。
  2. 必须接 备用电池(3V),才能断电走时。
  3. 工作电压 2.0~5.5V,3.3V/5V 单片机都能用。

DS1302 是三线制 RTC,驱动关键是 CE 使能、SCLK 沿触发、读写位序相反、必须关闭写保护、数据是 BCD 码,时序必须严格遵守。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐