DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用三线接口与CPU进行同步
通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。工作电压宽达2.5~5.5V。采用双
电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后背电源进行涓细电流充电的能力。DS1302的外部引脚分配如下图所示。DS1302用于数据记录,特别是对某些具有特殊意义的数据点的记录上,能实现数据与出现该数据的时间同时记录,因此广泛应用于测量系统中。
1
、芯片介绍;
2
、查看引脚定义;
4
、分析时序图;
5
、模仿着编写驱动程序,然后自己动手写驱动。
6
、实现功能。
一、芯片介绍
DS1302是DALLAS(达拉斯)公司出的一款涓流充电时钟芯片,2001年DALLAS被MAXIM(美信)收购,因此我们看到的DS1302的数据手册既有DALLAS的标志,又有MAXIM的标志;
DS1302实时时钟芯片广泛应用于电话、传真、便携式仪器等产品领域,他的主要性能指标如下:
1、DS1302是一个实时时钟芯片,可以提供秒、分、小时、日期、月、年等信息,并且还有软年自动调整的能力,可以通过配置AM/PM来决定采用24小时格式还是12小时格式。
2、拥有31字节数据存储RAM。
3、串行I/O通信方式,相对并行来说比较节省IO口的使用。
4、DS1302的工作电压比较宽,大概是2.0V~5.5V都可以正常工作。采用双电源供电,当主电源比备用电源高0.2V时,由主电源供电,否则采用备用电源,一般是一个纽扣电池。
5、DS1302这种时钟芯片功耗一般都很低,它在工作电压2.0V的时候,工作电流小于300nA。
6、DS1302共有8个引脚,有两种封装形式,一种是DIP-8封装,芯片宽度(不含引脚)是300mil,一种是SOP-8封装,有两种宽度,一种是150mil,一种是208mil。
二、引脚定义
三、外围电路
一般与
单片机IO口相连时要加上拉电阻,提高 IO 口的驱动能力,这样信号比较稳定,计时也比较准确。
四、分析时序图
这是单字节写入的时序图,可见,先拉高使能端,进行使能选择,然后在时钟上升沿写入一个字节。
DS1302在进行读写操作时最少读写两个字节,第一个是控制字节,就是一个命令,说明是读还是写操作,第二个时需要读写的数据。
对于单字节写,只有在SCLK为低电平时才能将 CE 置高电平,所以刚开始将SCLK 置低,CE置高,然后把需要写入的字节送入 IO口,然后跳变SCLK,在SCLK下降沿时,写入数据
读取写入操作CE必须为高,写入时,应该在SCLK低电平时完成,SCLK上升沿芯片采样data引脚上的数据。
读取时,芯片在下降沿之后将数据写入date总线上,高电平是数据不变。
由此,写入过程:SCLK低电平延时等待电平稳定写入数据到sclk上升沿,芯片采样延时2us等待芯片重新回到0写入下一个数据;读出过程 :下降沿芯片将数据放在date总线上,低电平时读取。
DS1302有下列几组寄存器:
DS1302 ①有关日历、时间的寄存器共有12个,其中有7个寄存器
(读时81h~8Dh,写时80h~8Ch),存放的数据格式为BCD码形式,我们读取之后需要修改为acsii码模式,如下
小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时
模式还是24小时模式。当为高时,选择12小时模式。在12小时模式时,
位5是 ,当为1时,表示PM。在24小时模式时,位5是第二个10小时
位。
秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。当该
位置为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位置为
0时,时钟开始运行。
控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置
为0。在任何的对时钟和RAM的写操作之前,WP位必须为0。当
WP位为1时,写保护位防止对任一寄存器的写操作。
DS1302中附加31字节静态RAM的地址如图
所谓突发模式是指一次传送多个字节的时钟信号和RAM数据。
突发模式寄存器如图
- #ifndef __DS13022_H
- #define __DS13022_H
- #include "pbdata.h"
- extern u8 ascii_time[7]; //保存ascii格式数据
- extern u8 bcd_time[7]; //保存bcd码数据
- typedef struct DS1302DATA
- {
- u8 year; //年
- u8 month; //月
- u8 day; //日
- u8 hour; //时
- u8 min; //分
- u8 sec; //秒
- u8 week; //周
- }DS1302DATA;
- extern struct DS1302DATA ds1302Data;
- #define DS1302_RST PCout(0)
- #define DS1302_CLK PAout(5)
- #define DS1302_DATIN PAin(8)
- #define DS1302_DATOUT PAout(8)
- #define DS1302_DAT_INPUT() {GPIOA->CRH &= 0XFFFFFFF0;GPIOA->CRH|=8<<0;}
- #define DS1302_DAT_OUTPUT() {GPIOA->CRH &= 0XFFFFFFF0;GPIOA->CRH|=3<<0;}
- //????????? ??????,???+1
- #define DS1302_SEC_REG 0x80 //写秒数据地址
- #define DS1302_MIN_REG 0x82 //写分数据地址
- #define DS1302_HR_REG 0x84 //写时数据地址
- #define DS1302_DATE_REG 0x86 //写日数据地址
- #define DS1302_MONTH_REG 0x88 //写月数据地址
- #define DS1302_DAY_REG 0x8a //写星期几数据地址
- #define DS1302_YEAR_REG 0x8c //写年数据地址
- #define DS1302_CONTROL_REG 0x8e //写保护寄存器地址
- #define DS1302_CHARGER_REG 0x90 //涓流充电寄电器
- #define DS1302_CLKBURST_REG 0xbe //脉冲串寄存器
- #define DS1302_RAM_BASE 0X30 //RAM寄存器
- #define CLOCKSTOP 0X80
- #define CLOCKSTART 0X00
- void Ds1302_Gpio_Init(void);
- u8 Ds1302_Read(u8 address);
- static u8 AsciiToBcd(u8 asciiData);
- static u8 BcdToAscii(u8 bcdData);
- void Ds1302_WriteByte(u8 dat);
- void Ds1302_Write(u8 address,u8 dat);
- void Ds1302_Write_Time_Singel(u8 address,u8 dat);
- void Ds1302_Write_Time_All(u8 start);
- u8 Ds1302_ReadByte(void);
- void Ds1302_Readtime(void);
- #endif
- #include "pbdata.h"
- struct DS1302DATA ds1302Data = {0,0,0,0,0,0,0};
- u8 ascii_time[7] = {0}; //保存ascii格式数据
- u8 bcd_time[7] = {0}; //保存bcd码数据
- static u8 AsciiToBcd(u8 asciiData)
- {
- u8 bcdData = 0;
- bcdData = (((asciiData/10)<<4)|((asciiData%10)));
- return bcdData;
- }
- static u8 BcdToAscii(u8 bcdData)
- {
- u8 asciiData = 0;
- asciiData = (((bcdData&0xf0)>>4)*10 + (bcdData&0x0f));
- return asciiData;
- }
- //IO初始化
- void Ds1302_Gpio_Init(void)
- {
- //RST //推挽输出C0
- RCC->APB2ENR|=1<<4;//使能PORTC时钟
- GPIOC->CRL&=0xFFFFFFF0; //C0推挽输出
- GPIOC->CRL|=0x00000003;
- //CLK //推挽输出A5
- RCC->APB2ENR|=1<<2;//使能PORTA时钟
- GPIOA->CRL&=0xFF0FFFFF; //A5推挽输出
- GPIOA->CRL|=0x00300000;
- //IO //推挽输出A8
- RCC->APB2ENR|=1<<2;//使能PORTA时钟
- GPIOA->CRH&=0xFFFFFFF0; //A8推挽输出
- GPIOA->CRH|=0x00000003;
- }
- //读取一个字节的时序,在下降沿进行读
- u8 Ds1302_ReadByte(void)
- {
- u8 i = 0, dat = 0;
- DS1302_DAT_INPUT();
- delay_us(5);
- for(i = 0; i <8; i++)
- {
- dat >>= 1;
- if(DS1302_DATIN == 1)dat |= 0x80;//低电平读取
- DS1302_CLK = 1;//后拉高获得下一字节数据
- delay_us(2);
- DS1302_CLK = 0;
- delay_us(2);
- }
- return dat;
- }
- //写入一个字节的时序,在上升沿进行写
- void Ds1302_WriteByte(u8 dat)
- {
- u8 i = 0, data = dat;
- DS1302_DAT_OUTPUT();
- DS1302_CLK = 0;
- delay_us(2);
- for(i = 0; i < 8; i++)
- {
- DS1302_DATOUT = data&0x01;
- delay_us(2);//延时等待低电平稳定
- DS1302_CLK = 1;//拉高写入
- delay_us(2);
- DS1302_CLK = 0;
- data >>= 1;
- }
- }
- //写入一个寄存器一个字节数据
- void Ds1302_Write(u8 address,u8 dat)
- {
- DS1302_RST = 0;
- DS1302_CLK = 0; //只有在clk低电平时,拉高rst才有用
- DS1302_RST = 1;
- Ds1302_WriteByte(address);
- Ds1302_WriteByte(dat);
- DS1302_CLK = 1;
- DS1302_RST = 0;
- }
- //单个写入时间
- void Ds1302_Write_Time_Singel(u8 address,u8 dat)
- {
- Ds1302_Write(DS1302_CONTROL_REG,0x00); //取消写保护
- Ds1302_Write(address,dat);
- Ds1302_Write(DS1302_CONTROL_REG,0x80); //打开写保护
- }
- //一次完成所有时间的更新
- //start当前时钟运行还是停止
- void Ds1302_Write_Time_All(u8 start)
- {
- Ds1302_Write(DS1302_CONTROL_REG,0x00); //取消写保护
- Ds1302_Write(DS1302_SEC_REG,(AsciiToBcd(ds1302Data.sec)|start));
- Ds1302_Write(DS1302_MIN_REG,AsciiToBcd(ds1302Data.min));
- Ds1302_Write(DS1302_HR_REG,AsciiToBcd(ds1302Data.hour));
- Ds1302_Write(DS1302_DATE_REG,AsciiToBcd(ds1302Data.day));
- Ds1302_Write(DS1302_MONTH_REG,AsciiToBcd(ds1302Data.month));
- Ds1302_Write(DS1302_DAY_REG,AsciiToBcd(ds1302Data.week));
- Ds1302_Write(DS1302_YEAR_REG,AsciiToBcd(ds1302Data.year));
- Ds1302_Write(DS1302_CONTROL_REG,0x80); //打开写保护
- }
- //读取一个字节
- u8 Ds1302_Read(u8 address)
- {
- u8 data = 0;
- DS1302_RST = 0;
- DS1302_CLK = 0; //只有在clk低电平时,拉高rst才有用
- DS1302_RST = 1;
- Ds1302_WriteByte(address|0x01); //读取地址需要与0x01相或,最低为变成1
- data = Ds1302_ReadByte();
- DS1302_CLK = 1;
- DS1302_RST = 0;
- return data;
- }
- //读取实时间的时候默认让时间走起来
- void Ds1302_Readtime(void)
- {
- ds1302Data.sec = BcdToAscii(Ds1302_Read(DS1302_SEC_REG)); //秒
- ds1302Data.min = BcdToAscii(Ds1302_Read(DS1302_MIN_REG)); //分
- ds1302Data.hour = BcdToAscii(Ds1302_Read(DS1302_HR_REG)); //小时
- ds1302Data.day = BcdToAscii(Ds1302_Read(DS1302_DATE_REG)); //日
- ds1302Data.month = BcdToAscii(Ds1302_Read(DS1302_MONTH_REG)); //月
- ds1302Data.week = BcdToAscii(Ds1302_Read(DS1302_DAY_REG)); //星期几
- ds1302Data.year = BcdToAscii(Ds1302_Read(DS1302_YEAR_REG)); //年
- }
复制代码
|