芯片简介
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); #endifds1302.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(); } }实验结果
完结,撒花~~~