一、DS1302介绍:
实时时钟芯片,可对年,月,日,周,时,分,秒计时,是一种集成电路。
二、DS1302原理:
1.寄存器定义:
Command:操作模式,决定要进行的操作是读/写,以及读写内容(秒、分、时。。。)
如下图,其中最左侧的值即为进行对应操作的Command的值。
例:对小时进行读取,Command = 0x85;
2.引脚定义与电路:
其中Vcc1/2是电源,X1/X2是晶振。重点在于后三个。
后三个的作用为输入和读取数据。
其中后三个的原理与_74HC595_完全类似,均为1位1位输入,详细过程见上一节。
CE:总开关,置1时开始工作;
I/O:传入的数据,0/1;
SCLK:来回置01,由0到1时依次传入I/O中的数据。
3.时序:
怎么看?--- 低为0高为1,画一条竖线,在同一竖线上的事是同时发生的。
例:下图中读操作:
将CE = 1,随后使SCLK在01切换,每次上升沿(0到1)依次将I/O口的数据传给R/W、A0等。
(注:R/W-1的8位即为Command)
8次上升后,确定Command,在下降沿(1到0)读取数据给I/O口。
(其中具体8位,每一位代表什么,详见上面的RTC图)
三、集成DS1302:
.h文件:
//时钟初始化
void DS1302_Init();
//数组:储存时钟的时间:年月日时分秒周(0-6)
unsigned char DS1302_Time[];
//用于设置和读取时钟数据,设置会将数组中的时间传入,读取会将时钟数据导出存在上面数组中
void DS1302_SetTime();
void DS1302_ReadTime();
.c文件:
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[] = { 19,11,16,12,59,55,6 };
//时钟初始化
void DS1302_Init()
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
//写入数据,参数:Command,Data
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;
}
//读取数据,参数:Command,返回值:Data
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i;
unsigned char Data = 0x00;
DS1302_CE = 1;
Command |= 0x01;
for (i = 0; i < 8; i++)
{
DS1302_IO = Command & (0x01 << i);
DS1302_SCLK = 0;
DS1302_SCLK = 1;
}
for (i = 0; i < 8; i++)
{
DS1302_SCLK = 1;
DS1302_SCLK = 0;
if (DS1302_IO) { Data |= (0x01<<i); }
}
DS1302_CE = 0;
DS1302_IO = 0;
return Data;
}
//用于设置和读取时钟数据
void DS1302_SetTime()
{
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()
{
DS1302_Time[0] = DS1302_ReadByte(DS1302_YEAR) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
DS1302_Time[1] = DS1302_ReadByte(DS1302_MONTH) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
DS1302_Time[2] = DS1302_ReadByte(DS1302_DATE) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
DS1302_Time[3] = DS1302_ReadByte(DS1302_HOUR) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
DS1302_Time[4] = DS1302_ReadByte(DS1302_MINUTE) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
DS1302_Time[5] = DS1302_ReadByte(DS1302_SECOND) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
DS1302_Time[6] = DS1302_ReadByte(DS1302_DAY) / 16 * 10 + DS1302_ReadByte(DS1302_YEAR) % 16;
}
四、实战:显示秒:
利用LCD1602调试:
unsigned char Second;
void main()
{
LCD_Init();
DS1302_Init();
LCD_ShowString(1, 1, "RTC");
DS1302_WriteByte(0x80, 0x03);
while (1)
{
Second = DS1302_ReadByte(0x81);
LCD_ShowNum(2, 1, Second, 3);
}
}
问题:此时调试会出现问题,由9直接变为16。
原因:DS1302不是以正常的2进制转10进制表示的,而是用BCD码。(详见:寄存器定义)
BCD码:用4位二进制数表示一位10进制数:
例:0001 0011 = 13 ; 1000 0101 = 85 ; 即 0x85 = 85 ;
解决方法:利用LCD1602中显示16进制的函数即可:LCD_ShowHexNum
正确版:
unsigned char Second;
void main()
{
LCD_Init();
DS1302_Init();
LCD_ShowString(1, 1, "RTC");
DS1302_WriteByte(0x80, 0x03);
while (1)
{
Second = DS1302_ReadByte(0x81);
LCD_ShowHexNum(2, 1, Second, 3);
}
}
五:实战:实时时钟:
void main()
{
LCD_Init();
DS1302_Init();
LCD_Showstring(1, 1, " - - ");
LCD_Showstring(2, 1, " : : ");
DS1302_SetTime();
while (1)
{
DS1302_ReadTime();
LCD_ShowNum(1, 1, DS1302_Time[0], 2);
LCD_ShowNum(1, 4, DS1302_Time[1], 2);
LCD_ShowNum(1, 7, DS1302_Time[2], 2);
LCD_ShowNum(2, 1, DS1302_Time[3], 2);
LCD_ShowNum(2, 4, DS1302_Time[4], 2);
LCD_ShowNum(2, 7, DS1302_Time[5], 2);
}
}