通信协议与传感器1 |SPI协议-DS1302

一、模块功能

DS1302 是一款实时时钟(RTC)芯片,广泛应用于嵌入式系统中,核心功能如下:

  • 精准计时:可记录年、月、日、时、分、秒,支持闰年自动修正,兼容 12/24 小时制切换
  • 掉电保持:内置后备电池供电电路,主电源断电后仍能持续计时,时间数据不丢失
  • 涓流充电:支持对备用电池进行涓流充电,延长断电续航时间
  • 数据存储:内置 31 字节静态 RAM,可存储少量用户自定义数据
  • 简化通信:采用三线制串行接口(CE、SCLK、IO),与 SPI 时序兼容,减少硬件引脚占用

二、工作原理

  • 核心实现原理

1. 核心控制位

  • CH 位(时钟启停位)
    • 位置:秒寄存器(80H/81H)第 7 位
    • 功能:CH=1 晶振停止(时间冻结),CH=0 晶振启动(开始计时),上电默认 CH=1
    • 关键:初始化后必须置 0,否则芯片不计时
  • WP 位(写保护位)
    • 位置:写保护寄存器(8EH/8FH)第 7 位
    • 功能:WP=1 禁止写入(防误改),WP=0 允许写入
    • 关键:写入前必须解除保护,写入后必须恢复保护

2. 编码与时序规则

  • BCD 编码:用 4 位二进制表示 1 位十进制数(如 25 → 0x25),读写时需完成十进制 ↔ BCD 转换,不可直接写入十进制数。
  • 通信时序:RST 拉高激活芯片,SCLK 上升沿发送数据、下降沿接收数据,通信结束后 RST 拉低,时序不匹配会导致通信失败。
  • 小时模式:支持 12/24 小时制,第 7 位 = 1 为 12 小时制(带 AM/PM),第 7 位 = 0 为 24 小时制,初始化时需明确选择。

3. 硬件要求

  • 晶振必须为 32.768kHz,焊接可靠;后备电池电压需充足,否则断电后时间丢失。
  • 寄存器未使用的高位必须写 0,否则可能引发功能异常。

1.初始化时间

  1. 解除写保护:向 8EH 寄存器写入 0x00,将 WP 位置 0。
  2. 写入时间数据:将十进制时间转换为 BCD 码,依次写入秒(80H)、分(82H)、时(84H)、日(86H)、月(88H)、周(8AH)、年(8CH)寄存器,写入秒寄存器时将 CH 位置 0
  3. 开启写保护:向 8EH 寄存器写入 0x80,将 WP 位置 1。

2. 读取时间

  1. (可选)临时解除写保护:向 8EH 写入 0x00
  2. 依次读取秒(81H)、分(83H)、时(85H)等寄存器。
  3. 将寄存器中的 BCD 码转换为十进制(如 0x25 → 25),用于显示或计算。
  4. 恢复写保护:向 8EH 写入 0x80

三、硬件配置

  • 晶振:32.768kHz 晶振连接 X1、X2 引脚,搭配电容后接地。
  • 电源:VCC2 接单片机 3.3V/5V 主电源,VCC1 接 3V 纽扣电池。
  • 通信:RST(P13)、SCLK(P17)、I/O(P23)分别连接单片机 GPIO。

四、完整代码实现

  • 可直接运行的示例代码
/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include <reg52.h>
#include <intrins.h>

sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位												

void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK=0;
		SDA=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}

时间设置函数:Set_Rtc

void Set_Rtc(unsigned char* ucRtc)
{
	unsigned char i;
	Write_Ds1302_Byte(0x8e, 0x00);  // 向8EH(写保护寄存器)写0x00,解除写保护(WP=0)
	for (i=0; i<3; i++)             // 循环写入时、分、秒(共3个时间字段)
	{
		// 0x84-2*i:地址计算逻辑
		// i=0 → 0x84(时寄存器写地址),i=1 → 0x82(分),i=2 → 0x80(秒)
		Write_Ds1302_Byte(0x84-2*i, ucRtc[i]);
	}
	Write_Ds1302_Byte(0x8e, 0x80);  // 向8EH写0x80,开启写保护(WP=1)
}
  • 参数说明ucRtc是字符数组指针,数组顺序为[时, 分, 秒](均为 BCD 码)。
  • 地址计算:利用0x84-2*i实现地址递减(84H→82H→80H),对应时、分、秒的写地址。
  • 保护机制:先解除写保护,写入完成后立即恢复,防止数据误改。

5. 时间读取函数:Read_Rtc

void Read_Rtc(unsigned char* ucRtc)
{
	unsigned char i;
	for (i=0; i<3; i++)
	{
		// 0x85-2*i:地址计算逻辑
		// i=0 → 0x85(时寄存器读地址),i=1 → 0x83(分),i=2 → 0x81(秒)
		ucRtc[i] = Read_Ds1302_Byte (0x85-2*i);
	}
}
  • 参数说明ucRtc是输出数组指针,读取后数组存储[时, 分, 秒]的 BCD 码数据。
  • 地址计算:读地址 = 写地址 + 1(如时写地址 84H→读地址 85H),因此用0x85-2*i对应。
  • 无需解除保护:读取操作不受 WP 位限制,直接读取即可。

使用示例

// 主函数示例:设置时间并读取显示
void main()
{
	unsigned char rtc_data[3];
	// 初始化时间:12时30分00秒(BCD码:12→0x12,30→0x30,00→0x00)
	rtc_data[0] = 0x12; // 时
	rtc_data[1] = 0x30; // 分
	rtc_data[2] = 0x00; // 秒(CH位=0,启动计时)
	
	Set_Rtc(rtc_data);  // 设置时间
	
	while(1)
	{
		Read_Rtc(rtc_data); // 循环读取时间
		// 此处可添加数码管显示代码,将rtc_data中的BCD码转为十进制显示
	}
}
Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐