芯片简介
DS1302是Dallas Semiconductor(现为Maxim Integrated)推出的涓流充电实时时钟芯片,主要特点:
-
实时时钟功能:秒、分、时、日、月、星期、年(2000年闰年补偿)
-
31字节RAM:用于数据存储
-
串行接口:三线SPI兼容接口
-
双电源供电:主电源和备用电池
-
涓流充电:可编程充电电路
-
低功耗:工作电流<300nA(典型值@2.0V)
-
宽电压范围:2.0V-5.5V
管脚定义
| 引脚 | 名称 | 功能描述 |
|---|---|---|
| 1 | VCC2 | 主电源,接+5V |
| 2 | X1 | 32.768kHz晶振输入 |
| 3 | X2 | 32.768kHz晶振输出 |
| 4 | GND | 地 |
| 5 | CE (RST) | 片选/复位,高电平有效 |
| 6 | I/O | 数据输入/输出 |
| 7 | SCLK | 串行时钟输入 |
| 8 | VCC1 | 备用电源,接3V电池 |
内部寄存器
1. 时间寄存器(12个)
| 地址(写) | 地址(读) | 寄存器 | 范围 | 位7 | 位6-位0 |
|---|---|---|---|---|---|
| 0x80 | 0x81 | 秒 | 00-59 | CH | 秒(BCD) |
| 0x82 | 0x83 | 分 | 00-59 | 0 | 分(BCD) |
| 0x84 | 0x85 | 时 | 01-12或00-23 | 12/24 | 时(BCD) |
| 0x86 | 0x87 | 日 | 01-31 | 0 | 日(BCD) |
| 0x88 | 0x89 | 月 | 01-12 | 0 | 月(BCD) |
| 0x8A | 0x8B | 星期 | 01-07 | 0 | 星期(BCD) |
| 0x8C | 0x8D | 年 | 00-99 | 0 | 年(BCD) |
| 0x8E | 0x8F | 控制 | - | WP | 0 |
| 0x90 | 0x91 | 涓流充电 | - | TCS | DS/RS |
| 0x92 | 0x93 | 时钟突发 | - | - | - |
| 0xC0 | 0xC1 | RAM 0 | - | - | - |
| ... | ... | ... | ... | ... | ... |
| 0xFC | 0xFD | RAM 30 | - | - | - |
| 0xBE | 0xBF | 时钟突发 | - | - | - |
| 0xFE | 0xFF | RAM突发 | - | - | - |
2. 特殊寄存器说明
控制寄存器(0x8E/0x8F):
位7:WP(写保护位),1=禁止写入,0=允许写入
涓流充电寄存器(0x90/0x91):
位4-7:TCS(涓流充电选择)
● 1010:使能涓流充电
● 其他:禁止充电
位2-3:DS(二极管选择)
● 01:1个二极管
● 10:2个二极管
位0-1:RS(电阻选择)
● 01:2kΩ
● 10:4kΩ
● 11:8kΩ
示例代码
ds1302.h
#ifndef _DS1302_H_
#define _DS1302_H_
#include <reg51.h>
#include <intrins.h>
// 管脚定义
sbit DS1302_CE = P3^5; // 片选/复位
sbit DS1302_IO = P3^4; // 数据线
sbit DS1302_SCLK = P3^6; // 时钟线
// 寄存器写地址
#define DS1302_SECOND_W 0x80
#define DS1302_MINUTE_W 0x82
#define DS1302_HOUR_W 0x84
#define DS1302_DATE_W 0x86
#define DS1302_MONTH_W 0x88
#define DS1302_DAY_W 0x8A
#define DS1302_YEAR_W 0x8C
#define DS1302_CONTROL_W 0x8E
// 寄存器读地址
#define DS1302_SECOND_R 0x81
#define DS1302_MINUTE_R 0x83
#define DS1302_HOUR_R 0x85
#define DS1302_DATE_R 0x87
#define DS1302_MONTH_R 0x89
#define DS1302_DAY_R 0x8B
#define DS1302_YEAR_R 0x8D
// 时间结构体
typedef struct {
unsigned char second;
unsigned char minute;
unsigned char hour;
unsigned char date;
unsigned char month;
unsigned char day;
unsigned char year;
} Time_Type;
// 函数声明
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char addr, unsigned char dat);
unsigned char DS1302_ReadByte(unsigned char addr);
void DS1302_SetTime(Time_Type *time);
void DS1302_GetTime(Time_Type *time);
#endif
ds1302.c
#include "ds1302.h"
// 读取和写入的地址数组
unsigned char READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8B, 0x8D};
unsigned char WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C};
// BCD转十进制
unsigned char BCD2Dec(unsigned char bcd) {
return ((bcd >> 4) * 10) + (bcd & 0x0F);
}
// 十进制转BCD
unsigned char Dec2BCD(unsigned char dec) {
if(dec > 99) dec = 99;
return ((dec / 10) << 4) | (dec % 10);
}
// 写入一个字节
void DS1302_WriteByte(unsigned char addr, unsigned char dat) {
unsigned char i;
DS1302_CE = 0;
_nop_();
DS1302_SCLK = 0;
_nop_();
DS1302_CE = 1;
_nop_();
// 写入地址
for(i = 0; i < 8; i++) {
DS1302_IO = addr & 0x01;
addr >>= 1;
DS1302_SCLK = 1;
_nop_();
DS1302_SCLK = 0;
_nop_();
}
// 写入数据
for(i = 0; i < 8; i++) {
DS1302_IO = dat & 0x01;
dat >>= 1;
DS1302_SCLK = 1;
_nop_();
DS1302_SCLK = 0;
_nop_();
}
DS1302_CE = 0;
_nop_();
}
// 读取一个字节
unsigned char DS1302_ReadByte(unsigned char addr) {
unsigned char i, temp, value = 0;
DS1302_CE = 0;
_nop_();
DS1302_SCLK = 0;
_nop_();
DS1302_CE = 1;
_nop_();
// 写入地址
for(i = 0; i < 8; i++) {
DS1302_IO = addr & 0x01;
addr >>= 1;
DS1302_SCLK = 1;
_nop_();
DS1302_SCLK = 0;
_nop_();
}
// 读取数据
for(i = 0; i < 8; i++) {
temp = DS1302_IO;
value = (temp << 7) | (value >> 1);
DS1302_SCLK = 1;
_nop_();
DS1302_SCLK = 0;
_nop_();
}
DS1302_CE = 0;
_nop_();
// 参考代码中的特殊操作,确保IO口状态正确
DS1302_SCLK = 1;
_nop_();
DS1302_IO = 0;
_nop_();
DS1302_IO = 1;
_nop_();
return value;
}
// DS1302初始化
void DS1302_Init(void) {
unsigned char temp; // 将变量声明移到函数开头
// 先关闭写保护
DS1302_WriteByte(0x8E, 0x00);
// 检查并启动时钟
temp = DS1302_ReadByte(0x81);
if(temp & 0x80) {
DS1302_WriteByte(0x80, temp & 0x7F);
}
// 重新开启写保护
DS1302_WriteByte(0x8E, 0x80);
}
// 设置时间
void DS1302_SetTime(Time_Type *time) {
unsigned char time_buf[7];
unsigned char i; // 将变量声明移到函数开头
// 转换为BCD码
time_buf[0] = Dec2BCD(time->second);
time_buf[1] = Dec2BCD(time->minute);
time_buf[2] = Dec2BCD(time->hour);
time_buf[3] = Dec2BCD(time->date);
time_buf[4] = Dec2BCD(time->month);
time_buf[5] = Dec2BCD(time->day);
time_buf[6] = Dec2BCD(time->year);
// 关闭写保护
DS1302_WriteByte(0x8E, 0x00);
// 写入时间
DS1302_WriteByte(WRITE_RTC_ADDR[0], time_buf[0]);
DS1302_WriteByte(WRITE_RTC_ADDR[1], time_buf[1]);
DS1302_WriteByte(WRITE_RTC_ADDR[2], time_buf[2]);
DS1302_WriteByte(WRITE_RTC_ADDR[3], time_buf[3]);
DS1302_WriteByte(WRITE_RTC_ADDR[4], time_buf[4]);
DS1302_WriteByte(WRITE_RTC_ADDR[5], time_buf[5]);
DS1302_WriteByte(WRITE_RTC_ADDR[6], time_buf[6]);
// 开启写保护
DS1302_WriteByte(0x8E, 0x80);
}
// 读取时间
void DS1302_GetTime(Time_Type *time) {
unsigned char time_buf[7];
unsigned char i; // 将变量声明移到函数开头
// 读取所有时间寄存器
for(i = 0; i < 7; i++) {
time_buf[i] = DS1302_ReadByte(READ_RTC_ADDR[i]);
}
// 转换为十进制
time->second = BCD2Dec(time_buf[0] & 0x7F); // 清除时钟停止位
time->minute = BCD2Dec(time_buf[1] & 0x7F);
// 处理小时(24小时制)
if(time_buf[2] & 0x80) {
// 12小时制
time->hour = BCD2Dec(time_buf[2] & 0x1F);
if(time_buf[2] & 0x20) {
// PM
if(time->hour != 12) time->hour += 12;
} else {
// AM
if(time->hour == 12) time->hour = 0;
}
} else {
// 24小时制
time->hour = BCD2Dec(time_buf[2] & 0x3F);
}
time->date = BCD2Dec(time_buf[3] & 0x3F);
time->month = BCD2Dec(time_buf[4] & 0x1F);
time->day = BCD2Dec(time_buf[5] & 0x07);
time->year = BCD2Dec(time_buf[6]);
}
main.c
#include <reg51.h>
#include "ds1302.h"
// 串口初始化
void UART_Init(void) {
SCON = 0x50;
TMOD = 0x20;
TH1 = 0xFD;
TL1 = 0xFD;
PCON &= 0x7F;
TR1 = 1;
}
// 发送字符
void UART_SendChar(char ch) {
SBUF = ch;
while(!TI);
TI = 0;
}
// 发送字符串
void UART_SendString(const char *str) {
while(*str) {
UART_SendChar(*str++);
}
}
// 发送两位数字
void UART_Send2Digit(unsigned char num) {
if(num > 99) num = 99;
UART_SendChar((num / 10) + '0');
UART_SendChar((num % 10) + '0');
}
// 简单延时
void DelayMs(unsigned int ms) {
unsigned int i, j;
for(i = 0; i < ms; i++) {
for(j = 0; j < 110; j++);
}
}
// 延时1秒
void Delay1s(void) {
DelayMs(1000);
}
// 主函数
void main(void) {
Time_Type set_time, current_time;
// 初始化串口
UART_Init();
DelayMs(100);
UART_SendString("\r\nDS1302 Real-Time Clock\r\n");
UART_SendString("=======================\r\n");
// 初始化DS1302
DS1302_Init();
// 设置初始时间:2023-12-29 14:30:00 星期四
set_time.second = 0;
set_time.minute = 30;
set_time.hour = 14;
set_time.date = 29;
set_time.month = 12;
set_time.day = 5; // 5=星期四
set_time.year = 23;
DS1302_SetTime(&set_time);
UART_SendString("Time set to: 2023-12-29 14:30:00 Thu\r\n\r\n");
while(1) {
// 读取时间
DS1302_GetTime(¤t_time);
// 显示日期
UART_SendString("20");
UART_Send2Digit(current_time.year);
UART_SendChar('-');
UART_Send2Digit(current_time.month);
UART_SendChar('-');
UART_Send2Digit(current_time.date);
// 显示时间
UART_SendChar(' ');
UART_Send2Digit(current_time.hour);
UART_SendChar(':');
UART_Send2Digit(current_time.minute);
UART_SendChar(':');
UART_Send2Digit(current_time.second);
// 显示星期
UART_SendString(" Week:");
switch(current_time.day) {
case 1: UART_SendString("Sun"); break;
case 2: UART_SendString("Mon"); break;
case 3: UART_SendString("Tue"); break;
case 4: UART_SendString("Wed"); break;
case 5: UART_SendString("Thu"); break;
case 6: UART_SendString("Fri"); break;
case 7: UART_SendString("Sat"); break;
default: UART_SendString("---"); break;
}
UART_SendString("\r\n");
Delay1s();
}
}
实验结果

完结,撒花~~~