DS1302 RTC驱动仿真
1、DS1302介绍
DS1302 涓流充电计时芯片包含一个实时时钟/日历和 31 字节的静态 RAM。它通过一个简单的串行接口与微处理器通信。实时时钟/日历提供秒、分、小时、日、日、月和年信息。对于少于 31 天的月份,月末日期会自动调整,包括闰年的更正。时钟以 24 小时或 12 小时格式运行,带有 AM/PM 指示器。
通过使用同步串行通信简化了 DS1302 与微处理器的接口。与时钟/RAM 通信只需要三根线:CE(
R
S
T
\over RST
RST?)、I/O(数据线)和 SCLK(串行时钟)。数据可以一次 1 个字节或最多 31 个字节的突发传输到时钟/RAM 或从时钟/RAM 传输。 DS1302 旨在以极低的功耗运行,并以低于 1μW 的功率保留数据和时钟信息。 DS1302 是 DS1202 的后继产品。除了 DS1202 的基本计时功能外,DS1302 还具有用于主电源和备用电源的双电源引脚、用于 VCC1 的可编程涓流充电器和七个额外字节的暂存器存储器的附加功能。
1)DS1302的命令组成
- Bit7 必须始终为逻辑 1。否则写入 DS1302 将被禁用。
- Bit6 指定时钟/日历或 RAM 选择。 如果它是 logic0 我们与时钟交谈,或者如果它是 logic1 我们与 RAM 交谈。
- 位 5 至 1 指定要输入或输出的指定寄存器。 (地址)
- Bit0 指定对 DS1302 的写或读操作。 如果是逻辑 0 则执行写操作,如果是逻辑 1 则执行读操作。
- 命令字节总是从 LSB 开始(Bit0)。
2)DS1302数据传输过程
-
在开始传输任何内容之前,必须将 CE 引脚拉高,以便与芯片通话。 (选择) -
之后,发送命令字节,通知 DS1302 将进行的操作。 (无论是读还是写,对时钟还是 RAM。) -
然后,如果执行写操作,则将要写入的数据发送到 RAM 或时钟中,或者如果执行读操作,则可以 从时钟或 RAM 中读取数据。
如果从 DS1302 读取数据,则在写入命令字节的最后一位后的第一个下降沿上,数据将可用。相反,写入 DS1302 发生在命令字节传输后的低电平到高电平转换。要记住的四个注意事项,是所有发送和接收字节都是 LSB 优先,在命令字节和数据字节之后的写操作中发送到 DS1302 的附加 SCLK 脉冲将被忽略。
读取操作后立即发送的附加 SCLK 脉冲,数据将再次可供读取。最后,当与 DS1302 通信时,微控制器的时钟应处于 2MHZ 的最大速度,如下面的数据表所示。如果使用不同的速度,那么必须校准频率以满足 DS1302 的需要,并将其重新校准为之前的频率。
3)DS1302设置
DS1302的寄存器如下:
从左边开始,前两列是指命令字节。 是否要读取或写入 RTC 或 RAM。从 (bit7 到 bit0) 的列是指它将在 RTC 或 RAM 中传输的数据字节。
2、仿真电路原理图
3、仿真代码实现
1)发送数据
void ds1302_send(unsigned char byte_t) {
unsigned char mask = 0x01;
IO_OUT(DS1302_DDR, DS1302_SIO);
do {
IO_CLR(DS1302_PORT, DS1302_SCK);
if (byte_t & mask) IO_SET(DS1302_PORT, DS1302_SIO);
else IO_CLR(DS1302_PORT, DS1302_SIO);
IO_SET(DS1302_PORT, DS1302_SCK);
mask = mask << 1;
} while (mask);
IO_CLR(DS1302_PORT, DS1302_SCK);
}
void ds1302_write(unsigned char ch, unsigned char byte_t) {
ds1302_select(DS1302_CS);
ds1302_send(ch | DS1302_CMD_WRITE);
ds1302_send(byte_t);
ds1302_deselect(DS1302_CS);
}
2)读数据
unsigned char ds1302_get(void) {
unsigned char mask = 0x01;
unsigned char tmp = 0x00;
IO_IN(DS1302_DDR, DS1302_SIO);
do {
IO_CLR(DS1302_PORT, DS1302_SCK);
NOP(); NOP();
if (DS1302_PORT_IN & DS1302_SIO) tmp |= mask;
else tmp |= 0x00;
IO_SET(DS1302_PORT, DS1302_SCK);
mask = mask << 1;
} while (mask);
IO_CLR(DS1302_PORT, DS1302_SCK);
return tmp;
}
unsigned char ds1302_read(unsigned char ch) {
unsigned char tmp;
ds1302_select(DS1302_CS);
ds1302_send(ch | DS1302_CMD_READ);
tmp = ds1302_get();
ds1302_deselect(DS1302_CS);
return tmp;
}
3)年、月、日、时、分秒设置与读取
#define ds1302_sec_write(n) ds1302_write(DS1302_SEC, (n))
#define ds1302_sec_read() ds1302_read(DS1302_SEC)
#define ds1302_min_write(n) ds1302_write(DS1302_MIN, (n))
#define ds1302_min_read() ds1302_read(DS1302_MIN)
#define ds1302_hour_write(n) ds1302_write(DS1302_HOUR, (n))
#define ds1302_hour_read() ds1302_read(DS1302_HOUR)
#define ds1302_mdat_write(n) ds1302_write(DS1302_MDAT, (n))
#define ds1302_mdat_read() ds1302_read(DS1302_MDAT)
#define ds1302_mon_write(n) ds1302_write(DS1302_MON, (n))
#define ds1302_mon_read() ds1302_read(DS1302_MON)
#define ds1302_wday_write(n) ds1302_write(DS1302_WDAY, (n))
#define ds1302_wday_read() ds1302_read(DS1302_WDAY)
#define ds1302_year_write(n) ds1302_write(DS1302_YEAR, (n))
#define ds1302_year_read() ds1302_read(DS1302_YEAR)
4)主程序
#include "gpio.h"
#include "delay.h"
#include "ds1302.h"
#include "uart.h"
#include "i2c_sw.h"
#include <stdio.h>
unsigned int year,month,day,hours,minutes,seconds;
void mcu_init(void) {
uart_init();
ds1302_init();
year = ds1302_year_read();
month = ds1302_mon_read();
day = ds1302_mdat_read();
hours = ds1302_hour_read();
minutes = ds1302_min_read();
seconds = ds1302_sec_read();
}
int main(void) {
mcu_init();
uart_send_str("****DS1302****\r\n");
while (1) {
year = ds1302_year_read();
month = ds1302_mon_read();
day = ds1302_mdat_read();
hours = ds1302_hour_read();
minutes = ds1302_min_read();
seconds = ds1302_sec_read();
printf("%d-%d-%d %d:%d:%d\r\n",BCD2DEC(year),BCD2DEC(month),BCD2DEC(day),BCD2DEC(hours),BCD2DEC(minutes),BCD2DEC(seconds));
delay_ms(1000);
}
}
4、仿真结果
|