1.0 DS1302-外部RTC

一、综述

  DS1302是美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片,因为应用非常广泛,结果就导致了大量的国产仿制品,GC1302是一款国产DS1302仿制芯片,使用方法和DS1302完全相同。

二、应用

1、电路原理

在这里插入图片描述
  上图是一个典型的应用图,MCU通过CE、I/O、SCLK三个引脚控制GC1302工作,GC1302有两种供电方式:备用电源Vcc1和主电源Vcc2,GC1302工作在两者较大者,Vcc2>Vcc1+0.2v,Vcc2供电,Vcc1>Vcc2,Vcc1供电。故当Vcc2失效时,由Vcc1接替工作。
  一般情况下,Vcc2由MCU供电,Vcc1外接备用电源,通过设计的充电电路,可以为可充放纽扣电池、大电容等充电。当Vcc2供电时,可以控制是否对备用电源充电,但是使用不可充电的纽扣电池时,不要使用充电功能。
  图中的备用电源是外接电容,但是没有设计充电电路。假设加入充电电路给电容充电,经实际测量,如果Vcc2是3.3V,电容充满时为3V左右,大概工作3天,降到1.6V左右,此时已经基本无法维持GC1302正常计时。

2、命令字格式

  命令字用来启动数据传输,它的格式如下所示
在这里插入图片描述
  第7位:必须是1,如果是0,禁止对GC1302写入。
  第6位:0表示访问时钟/日历数据,1访问RAM数据。GC1320不仅可以保存时钟,可以RAM中保存一些用户数据。
  第5~1位:GC1302寄存器地址。
  第0位:0表示写操作,1表示读操作。
  下图是读写RTC数据的具体命令字,每一行给出了读写某个寄存器的命令字以及寄存器的存储内容。在这里插入图片描述
  例如第三行,读命令字为0x85,写命令字为0x86,该寄存器保存小时信息,并且数据范围1-12或0-23。该命令字的二进制为0b1000 0101,则第7位1,使能操作,第6位0,RTC访问,第5~1位,寄存器地址0x02,第0位1,表示写操作。
  注意,寄存器中保存的数据是BCD格式,例如要保存秒数是54s,实际保存时转化为16进制并不是0x36,而是0x54。
  有几组寄存器需要特殊的说明:
  0x81、0x80,当CH为1时,时钟暂停,为0时,时钟开启。
  0x8F、0x8E,当WP为0时,允许修改时钟寄存器,为1时,禁止修改。
  0x91、0x90,充电使能及充电参数配置,TCS,位4~位7是1010才使能充电,DS是二极管选择位,用来表示在Vcc2和Vcc1之间连接了1个还是2个二极管,RS是电阻选择,表示Vcc2和Vcc1之间的电阻是多大。具体的配置如下图所示
在这里插入图片描述
  例如,充电电路为1二极管,2k欧电阻,如要开始充电,该寄存器需要配置为10100101,即0xA3。

3、通讯波形

  数据传输需要三条线,CE、SCLK和IO,空闲时,CE,SCLK为低电平,IO随意,也可以为低电平。
  CE为1时,才允许读写,否则不允许读写。同时在CE置1时,SCLK必须为0。
  SCLK的频率根据Vcc电压决定。例如当Vcc=5V,最大频率可达2MHz。手动拉高拉低对应的GPIO,并在拉高拉低中间加入一定的延时,即可产生SCLK。
在这里插入图片描述
  数据通讯时,掌握一个关键原则,RTC在SCLK上升沿采集IO数据,MCU在SCLK下降沿采集IO数据。

1、写字节

在这里插入图片描述
  首先写待读取寄存器的地址,然后再写要写入的字节。
  写寄存器地址时,把IO设置为输出模式,在SCLK低电平期间,把IO拉高或拉低,GC1302会在SCLK上升沿读取IO数据,即可读到发送的地址。MCU发送完地址后,还是同样的操作方式,继续写字节即可。
  简单来讲,写操作时,MCU在SCLK低电平期间把IO数据准备好,只要保证在SCLK上升沿之前准备好即可,然后把SCLK拉高,RTC就会采集IO上的数据。

2、读字节

在这里插入图片描述
  首先要写待读取寄存器的地址,然后再读RTC发送的字节。
  写寄存器地址时,把IO设置为输出模式,在SCLK上升沿到来之前,准备好IO的数据,GC1302在SCLK上升沿读取地址。
  时段1,这是一段SCLK的高电平,它是读字节的关键时段。在该期间,RTC已经在刚过去的上升沿读取完命令字的最后一位,会马上输出寄存器的数据,在紧接的下降沿,MCU需要采集RTC输出的数据。故在时段1内,MCU需要把IO由输出切换为输入。
  后续RTC会在SCLK的下降沿到来之前,把IO输出数据准备好,等SCLK的下降沿到来时,MCU采集IO数据。
  如果在时段1内,没有及时的切换IO为输入模式,很有可能因为GPIO的输出推挽模式,导致IO的电平无法被GC1302控制,从而丢失数据。

三、源码

  如下代码基于STMF411芯片,仅供参考,主要是提供一种思路

#define DS1302_STOP 	        0x80 
 
#define DS1302_READ_BURST 		0xBF
#define DS1302_WRITE_BURST 		0xBE
#define DS1302_WRITE_SEC 		0x80
#define DS1302_READ_SEC 		0x81
#define DS1302_WRITE_MINUTE 	0x82
#define DS1302_READ_MINUTE 		0x83
#define DS1302_WRITE_HOUR 		0x84
#define DS1302_READ_HOUR 		0x85
#define DS1302_WRITE_DATE 		0x86
#define DS1302_READ_DATE 		0x87

#define DS1302_WRITE_CHARGE 	0x90
#define DS1302_READ_CHARGE 		0x91

void delay_200us(void)
{
	uint16_t a = 0;
	for(uint16_t i=0; i<30; i++)
		a++;
}

void delay_100us(void)
{
	uint16_t a = 0;
	for(uint16_t i=0; i<15; i++)
		a++;
}

void DS1302_Start()    // 传输开始,拉高CE
{
	HAL_GPIO_WritePin(DS1302_CE_PORT, DS1302_CE_PIN, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET);
	delay_200us();
	HAL_GPIO_WritePin(DS1302_CE_PORT, DS1302_CE_PIN, GPIO_PIN_SET);
	delay_200us();
}

void DS1302_Over()    // 传输结束,拉低CE
{
   HAL_GPIO_WritePin(DS1302_CE_PORT, DS1302_CE_PIN, GPIO_PIN_RESET);
   HAL_GPIO_WritePin(DS1302_IO_PORT, DS1302_IO_PIN, GPIO_PIN_RESET);
   HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET);
}

void DS1302_ClearWriteProtection()// 清除写保护
{
	DS1302_Start();
	DS1302_WriteByte(0x8E);
	DS1302_WriteByte(0x00);
	DS1302_Over();
}
 
void DS1302_SetWriteProtection()  // 设置写保护
{
	DS1302_Start();
	DS1302_WriteByte(0x8E);
	DS1302_WriteByte(0x80);
	DS1302_Over();
}

void set_out(void)    // data IO设置为输出模式
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = DS1302_IO_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
	HAL_GPIO_Init(DS1302_IO_PORT, &GPIO_InitStruct);
}

void set_in(void)   // data IO设置为输入模式
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = DS1302_IO_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
	HAL_GPIO_Init(DS1302_IO_PORT, &GPIO_InitStruct);
}

uint8_t gc1302_read_byte(uint8_t cmd)  // 读相应的寄存器数据
{
	DS1302_Start();
	uint8_t i = 0;
	// write cmd
	for(i=0;i<8;i++)
	{
		HAL_GPIO_WritePin(DS1302_IO_PORT, DS1302_IO_PIN, (GPIO_PinState)(cmd&0x01));
		cmd >>= 1;
		delay_100us();
		HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_SET);
        if(i == 7)   // 注意,当命令字的第7位在上升沿结束后,需要在下降沿之前马上把该IO设置为输入模式
			set_in();
			delay_200us(); 
		else
            // 在上升沿和下降沿之间延时200us,即周期为400us,频率为2.5KHz左右
            // 该频率可以随意设置,只要不超过最大值即可
			delay_200us();  
		HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET);
		delay_100us();
	}
	
	// read data
	uint8_t data = 0;
	for(i=0;i<8;i++)
	{      
		data >>= 1;
		if(HAL_GPIO_ReadPin(DS1302_IO_PORT, DS1302_IO_PIN))
		{
			data |= 0x80;
		}
		delay_100us();
		HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_SET);
		delay_200us();
		HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET);
		delay_100us();
	}
	set_out();
	DS1302_Over();
	return data;
}

void gc1302_send_byte(uint8_t data_byte)   // 写一个字节的时序
{
	for(uint8_t i=0;i<8;i++)
	{
		HAL_GPIO_WritePin(DS1302_IO_PORT, DS1302_IO_PIN, (GPIO_PinState)(data_byte&0x01));
		data_byte >>= 1;
		delay_100us();
		HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_SET);
		delay_200us();
		HAL_GPIO_WritePin(DS1302_SCLK_PORT, DS1302_SCLK_PIN, GPIO_PIN_RESET);
		delay_100us();
		//delay_200us();
	}
}

void gc1302_write_byte(uint8_t cmd, uint8_t data)  // 写相应的寄存器数据
{
	DS1302_Start();
	gc1302_send_byte(cmd);
	gc1302_send_byte(data);
	DS1302_Over();
}

void gc1302_test()
{
    uint8_t write_data[4] = {0x30,0x12,0x18,0x04};  //BCD格式,该时间为4号18时12分30秒
    uint8_t read_data[4] = {0};
    DS1302_ClearWriteProtection();    // 清除写保护
	gc1302_write_byte(DS1302_WRITE_SEC, DS1302_STOP);	// 停止计时
	gc1302_write_byte(DS1302_WRITE_MINUTE, write_data[1]);  // 设置分
	gc1302_write_byte(DS1302_WRITE_HOUR, write_data[2]);    // 设置时
	gc1302_write_byte(DS1302_WRITE_DATE, write_data[3]);    // 设置天
	gc1302_write_byte(DS1302_WRITE_SEC, write_data[0]);     // 设置秒,并开始计时
    
    gc1302_write_byte(DS1302_WRITE_CHARGE, 0xA5);      // 使能充电
    
    read_data[0] = gc1302_read_byte(DS1302_READ_SEC);
    read_data[1] = gc1302_read_byte(DS1302_READ_MINUTE);
    read_data[2] = gc1302_read_byte(DS1302_READ_HOUR);
    read_data[3] = gc1302_read_byte(DS1302_READ_DATE);
    
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值