DS1302介绍
- DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有润年补偿等多种功能
- RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片
引脚定义和应用电路

|-------|-------------|
| 引脚名 | 作用 |
| VCC2 | 主电源 |
| VCC1 | 备用电源 |
| GND | 电源地 |
| X1、X2 | 32.768KHz晶振 |
| CE | 芯片使能 |
| IO | 数据输入/输出 |
| SCLK | 串行时钟 |

我们在使用单片机进行计时,假如断电了,下次再开机就会重新计时。但是DS1302有备用的电源,就算单片机断电了,依然可以正常计时。下次单片机通电后再读取数据就可以了。
晶振使用32.768KHZ和我们使用11.0592HZ进行串口通信是一个道理,在某些方面精度会更高。
DS1302内部结构框图

DS1302寄存器定义

我们只需要对这些寄存器进行读写,就可以读时间,和修改时间了。
时序定义

时钟写入和读取的代码

只需要按照上面的时序图,读写开始的时候把CE置1,然后给SCLK一个上升沿读写数据。然后恢复到低电平。读写结束后把CE置0,SCLK置0,我们可以看原理图,使用sbit和sfr关键字,对P36和P34和P35重新定义下。方便我们后续使用
bash
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
单片机在通电后会把寄存器都置为1.所以我们也要写一个初始化函数。让SCLK寄存器和CE寄存器初始状态为0.
bash
void DS1302_Init()
{
DS1302_SCLK=0;
DS1302_CE=0;
}
然后我们就可以写写入数据的函数了。写入之前先把CE寄存器置1。然后使用一个for循环把控制命令发送过去。每次在IO写入一位。然后给SCLK一个上升沿把数据法出去。控制命令写完后用一样的方式把数据给发送过去。发送结束后把CE置0.
bash
void DS1302_WriteByte(unsigned char Command,unsigned char Data)
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
读取数据的函数也是很类似的,但是根据时序图我们就可以发现。读取时15个周期。写入是16个周期。所以我们在写入命令的时候先让SCLK置0再置1,在读取数据的时候先置1再置0,等于最后就会少一个周期。然后在中间和结束我们要让IO置0.释放总线。避免后续出现问题。
bash
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char Data=0x00;
unsigned char i=0;
Command|=0x01;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=0;
DS1302_SCLK=1;
}
DS1302_IO=0;
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO)
{
Data=Data|(0x01<<i);
}
}
DS1302_CE=0;
DS1302_IO=0;
return Data;
}
然后我们可以再写一个默认的写入数据的函数。根据DS1302写入的时候的命令定义一些变量。方便操作。然后DS1302_Time数组存储的是年月日,时分秒。和星期。至于为什么在写入的时候要对数据进行处理,是因为DS1302在传输的时候数据是采用的BCD码。所以我们要把正常的十六进制进行一些转换。包括读取的时候也是需要进行转换的。
bash
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
unsigned char DS1302_Time[]={25,11,29,18,29,30,6};
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
读取数据的函数如下:
bash
void DS1302_ReadTime(void)
{
unsigned char temp;
temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=temp/16*10+temp%16;
}
最后。完整的代码:
首先是main.c文件:
bash
#include <REGX52.H>
#include "LCD1602.H"
#include "DS1302.H"
#include <INTRINS.H>
void Delay(unsigned char x) //@11.0592MHz
{
unsigned char data i, j;
while(x--)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
unsigned char Hour;
unsigned char Minute;
unsigned char Second;
void main()
{
LCD_Init();
DS1302_Init();
DS1302_SetTime();
LCD_ShowNum(1,1,20,2);
LCD_ShowChar(1,5,'-');
LCD_ShowChar(1,8,'-');
LCD_ShowChar(2,4,':');
LCD_ShowChar(2,7,':');
while(1)
{
DS1302_ReadTime();
LCD_ShowNum(1,3,DS1302_Time[0],2);
LCD_ShowNum(1,6,DS1302_Time[1],2);
LCD_ShowNum(1,9,DS1302_Time[2],2);
LCD_ShowNum(2,2,DS1302_Time[3],2);
LCD_ShowNum(2,5,DS1302_Time[4],2);
LCD_ShowNum(2,8,DS1302_Time[5],2);
Delay(50);
}
}
其次是DS1302.c文件和DS1302.h文件:
bash
#include <REGX52.H>
#include "DS1302.H"
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
unsigned char DS1302_Time[]={25,11,29,18,29,30,6};
void DS1302_Init()
{
DS1302_SCLK=0;
DS1302_CE=0;
}
void DS1302_WriteByte(unsigned char Command,unsigned char Data)
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char Data=0x00;
unsigned char i=0;
Command|=0x01;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=0;
DS1302_SCLK=1;
}
DS1302_IO=0;
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO)
{
Data=Data|(0x01<<i);
}
}
DS1302_CE=0;
DS1302_IO=0;
return Data;
}
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
void DS1302_ReadTime(void)
{
unsigned char temp;
temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=temp/16*10+temp%16;
temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=temp/16*10+temp%16;
}
bash
#ifndef __DS1302_H__
#define __DS1302_H__
extern unsigned char DS1302_Time[];
void DS1302_Init();
void DS1302_ReadTime(void);
void DS1302_SetTime(void);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_WriteByte(unsigned char Command,unsigned char Data);
#endif
LCD1602屏显示的代码之前的文章有写.并且代码比较长,.在此省略.
