DS1302时钟芯片介绍
DS1302简介
DS1302 是 DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和 31 字节静态 RAM,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式。DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:
- RES复位
- I/O数据线
- SCLK串行时钟。时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信。DS1302 工作时功耗很低保持数据和时钟信息时功率小于1mW。
DS1302 由 DS1202 改进而来增加了以下的特性:双电源管脚用于主电源和备份电源供应,Vcc1 为可编程涓流充电电源,附加七个字节存储器。它广泛应用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域下面。
主要的性能指标:
- 实时时钟具有能计算 2100 年之前的秒、分、时、日、星期、月、年的能力,还有闰年调整的能力;
- 31个8位暂存数据存储RAM;
- 串行I/O口方式使得管脚数量最少;
- 宽范围工作电压2.0~5.5V
- 工作在2.0V时,电流小于300nA;
- 读/写时钟或RAM数据时有两种传送方式单字节传送和多字节传送字符组方式;
- 8脚DIP封装或可选的8脚SOIC封装根据表面装配;
- 简单3线接口;
- 与TTL兼容Vcc=5V;
- 可选工业级温度范围-40~+85;
DS1302芯片的管脚
- VCC2 : 主电源引脚
- X1、X2 : DS1302 外部晶振引脚,通常需外接32.768K晶振
- GND : 电源地
- CE : 使能引脚,也是复位引脚(新版本功能变)。
- I/O : 串行数据引脚,数据输出或者输入都从这个引脚
- SCLK : 串行时钟引脚
- VCC1 : 备用电源
DS1302使用
操作 DS1302 的大致过程,就是将各种数据写入 DS1302 的寄存器,以设置它当前的时间的格式。然后使 DS1302 开始运作,DS1302 时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出。再用液晶显示,就是我们常说的简易电子钟。所以总的来说 DS1302 的操作分2步(显示部分属于液晶显示的内容,不属于DS1302 本身的内容),但是在讲述操作时序之前,我们要先看看寄存器,DS1302 有一个控制寄存器、12个日历、时钟寄存器和31个RAM。
控制寄存器
控制寄存器用于存放DS1302的控制命令字,DS1302的RST引脚回到高电平后写入的第一个字节就为控制命令。它用于对DS1302读写过程进行控制,格式如下:
- 第7位永远都是1
- 第6位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器
- 第5到第1位,为RAM或者寄存器的地址
- 最低位,高电平表示RD,即下一步操作将要“读”;低电平表示W,即下一步操作将要“写”。(与AT24C02寄存器类似,这点要理解好)。
比如要读秒寄存器则命令为 1000 0001,反之写为 1000 0000,要注意其含义。
日历/时钟寄存器
DS1302 共有12个寄存器,其中有7个与日历、时钟相关,存放的数据为BCD码形式。格式如下:
- 秒寄存器 : 低四位为秒的个位,高的次三位为秒的十位。最高位 CH 为DS1302 的运行标志,当 CH=0 时,DS1302 内部时钟运行,反之 CH=1 时停止;
- 小时寄存器 :时寄存器。最高位为 12/24 小时的格式选择位,该位为 1 时表示 12 小时格式。当设置为 12 小时显示格式时,第 5 位的高电平表示下午(PM);而当设置为 24 小时格式时,第5 位位具体的时间数据。
- 写保护寄存器 : 当该寄存器最高位 WP 为 1 时,DS1302 只读不写,所以要在往 DS1302 写数据之前确保 WP 为 0。
- 慢充电寄存器(涓细电流充电)寄存器 : 当 DS1302 掉电时,可以马上调用外部电源保护时间数据。该寄存器就是配置备用电源的充电选项的。其中高四位(4 个 TCS)只有在 1010 的情况下才能使用充电选项;低四位的情况与 DS1302 内部电路有关
BCD码是通过4位二进制码来表示1位十进制中的0~9这10个数码。如下所示:
|
|
|
|
0 |
0000 |
5 |
0101 |
1 |
0001 |
6 |
0110 |
2 |
0010 |
7 |
0111 |
3 |
0011 |
8 |
1000 |
4 |
0100 |
9 |
1001 |
DS1302的读写时序
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位(位0)开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。其时序图如下所示
上图就是DS1302的三个时序:复位时序,单字节写时序,单字节读时序;
- CE(RST) : 复位时序,即在RST引脚产生一个正脉冲,在整个读写器件,RST 要保持高电平,一次字节读写完毕之后,要注意把RST返回低电平准备下次读写周期;
- 单字节读时序 : 注意读之前还是要先对寄存器写命令,从最低位开始写;可以看到,写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现。所以,在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了!这个就是DS1302操作中最特别的地方。当然读出来的数据也是最低位开始。
- 单字节写时序 :两个字节的数据配合16个上升沿将数据写入即可。
程序注意事项
- 要记得在操作DS1302之前关闭写保护
- 注意用延时来降低单片机的速度以配合器件时序;
- DS1302 读出来的数据是BCD码形式,要转换成我们习惯的10进制
- 读取字节之前,将IO设置为输入口,读取完之后,要将其改回输出口;
- 在写程序的时候,建议实现开辟数组(内存空间)来集中放置DS1302的一系列数据,方便以后扩展键盘输入
硬件设计
本实验使用到的硬件资源如下:
- 动态数码管
- DS1302
DS1302时钟模块电路
软件设计
本实验要实现的功能时:数码管商显示电子时钟时分秒,格式为“XX-XX-XX”
程序框架如下:
- 编写数码管显示功能
- 编写DS1302时钟读写功能
- 主函数
实物接线图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
#include "public.h" #include "smg.h" #include "ds1302.h"
void main() { u8 time_buf[8]; ds1302_init();
while(1) { ds1302_read_time(); time_buf[0]=gsmg_code[gDS1302_TIME[2]/16]; time_buf[1]=gsmg_code[gDS1302_TIME[2]&0x0f]; time_buf[2]=0x40; time_buf[3]=gsmg_code[gDS1302_TIME[1]/16]; time_buf[4]=gsmg_code[gDS1302_TIME[1]&0x0f]; time_buf[5]=0x40; time_buf[6]=gsmg_code[gDS1302_TIME[0]/16]; time_buf[7]=gsmg_code[gDS1302_TIME[0]&0x0f]; smg_display(time_buf,1); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| #include "ds1302.h" #include "intrins.h"
u8 gREAD_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
u8 gDS1302_TIME[7] = {0x47, 0x51, 0x13, 0x20, 0x04, 0x05, 0x21};
void ds1302_write_byte(u8 addr,u8 dat) { u8 i=0; DS1302_RST=0; _nop_(); DS1302_CLK=0; _nop_(); DS1302_RST=1; _nop_();
for(i=0;i<8;i++) { DS1302_IO=addr&0x01; addr>>=1; DS1302_CLK=1; _nop_(); DS1302_CLK=0; _nop_(); } for(i=0;i<8;i++) { DS1302_IO=dat&0x01; dat>>=1; DS1302_CLK=1; _nop_(); DS1302_CLK=0; _nop_(); } DS1302_RST=0; _nop_(); }
u8 ds1302_read_byte(u8 addr) { u8 i=0; u8 temp=0; u8 value=0;
DS1302_RST=0; _nop_(); DS1302_CLK=0; _nop_(); DS1302_RST=1; _nop_(); for(i=0;i<8;i++) { DS1302_IO=addr&0x01; addr>>=1; DS1302_CLK=1; _nop_(); DS1302_CLK=0; _nop_(); } for(i=0;i<8;i++) { temp=DS1302_IO; value=(temp<<7)|(value>>1); DS1302_CLK=1; _nop_(); DS1302_CLK=0; _nop_(); } DS1302_RST=0; _nop_(); DS1302_CLK=1; _nop_(); DS1302_IO = 0; _nop_(); DS1302_IO = 1; _nop_(); return value; }
void ds1302_init(void) { u8 i=0; ds1302_write_byte(0x8E,0X00); for(i=0;i<7;i++) { ds1302_write_byte(gWRITE_RTC_ADDR[i],gDS1302_TIME[i]); } ds1302_write_byte(0x8E,0X80); }
void ds1302_read_time(void) { u8 i=0; for(i=0;i<7;i++) { gDS1302_TIME[i]=ds1302_read_byte(gREAD_RTC_ADDR[i]); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include "smg.h"
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void smg_display(u8 dat[],u8 pos) { u8 i=0; u8 pos_temp=pos-1;
for(i=pos_temp;i<8;i++) { switch(7-i) { case 0: LSC=1;LSB=1;LSA=1;break; case 1: LSC=1;LSB=1;LSA=0;break; case 2: LSC=1;LSB=0;LSA=1;break; case 3: LSC=1;LSB=0;LSA=0;break; case 4: LSC=0;LSB=1;LSA=1;break; case 5: LSC=0;LSB=1;LSA=0;break; case 6: LSC=0;LSB=0;LSA=1;break; case 7: LSC=0;LSB=0;LSA=0;break; } SMG_A_DP_PORT=dat[i-pos_temp]; delay_10us(100); SMG_A_DP_PORT=0x00; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include "public.h"
void delay_10us(u16 ten_us) { while(ten_us--); }
void delay_ms(u16 ms) { u16 i,j; for(i=ms;i>0;i--) for(j=110;j>0;j--); }
|
相关头文件