DS1302时钟
# DS1302时钟
# 1、DS1302介绍
- DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能
- RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片
- 我们51单片机的就是这样一个DS1302芯片。
# 2、引脚定义和应用电路
- 这边是DS1302与CPU之间的一个关系,我先列一个表格来介绍一下各个部分的功能。
# 3、寄存器定义
- DS1302的寄存器比较多,我们来一一介绍一下:
从上往下,依次是秒,分,时,天,月,星期几(1~7),年。之后的WP是写入保护,置1则写入无效哎,但还可以读数。再下面一行,就是涓流充电模式,也就是内置电源,51单片机没有,我们就先不写这个。
注:CH是时钟停止引脚
# 4、命令字
命令字要解决的问题就是,我要去哪操作,以及,我要读出还是写入这两个问题。第一位,就是看是读出还是写入,当为0时,是写入,为1是读出;2~6位是地址,7位是操控的地方是时钟还是RAM;8位都是1。命令字其实都已经在前两列表示出来了。
# 5、时序
- 注意这里的读时序和写时序他们的 SCLK 上下沿有区别
首先,我们需要写好刚刚介绍的命令字部分,每一个上升沿就是一次写入,而下降沿就是输出,所以输入输出主要的区别就是后面部分,从D0~D7,就是我们要操作的数据。
# 6、代码
- DS1302.c
#include <REGX52.H>
// 根据原理图,应该可以写出下面几个引脚定义
sbit DS1302_SCLK = P3^6;
sbit DS1302_CE = P3^5;
sbit DS1302_IO = P3^4;
//寄存器写入地址/指令定义
#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
//时间数组,索引0~6分别为年、月、日、时、分、秒、星期
unsigned char DS1302_Time[]={23,3,1,11,57,55,3};
// 初始化函数,因为单片机接电后默认为1
/**
* @brief DS1302初始化
* @param 无
* @retval 无
*/
void DS1302_Init()
{
DS1302_CE=0;
DS1302_SCLK=0;
}
// 写入函数
/**
* @brief DS1302写一个字节
* @param Command 命令字/地址
* @param Data 要写入的数据
* @retval 无
*/
void DS1302_WriteByte(unsigned char Command,Date)
{
unsigned char i;
DS1302_CE=1;
//读取低位
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
//可能需要加延时函数,因为切换太快了,但是51可以不加
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Date&(0x01<<i);
// 可能需要加延时函数,因为切换太快了,但是51可以不加
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
// 读取的话,周期是15个,与写入的16个周期不同,所以才有下面代码的转变
/**
* @brief DS1302读一个字节
* @param Command 命令字/地址
* @retval 读出的数据
*/
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned int i,Date=0x00;
//为了统一数据,因为读的时候,末尾一定是1
Command|=0x01;//写Command++也可以
DS1302_CE=1;
//读取地位
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
// 这么做的原因就是在第8个脉冲下降沿的时候,数据已经读出了
DS1302_SCLK=0;
DS1302_SCLK=1;
}
//读取下降沿
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO)
{
Date|=(0x01<<i);
}
}
// 返回前先将IO口置为0(这个操作必须加)
DS1302_IO=0;
DS1302_CE=0;
return Date;
}
/**
* @brief DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
* @param 无
* @retval 无
*/
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//十进制转BCD码后写入
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);
}
/**
* @brief DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
* @param 无
* @retval 无
*/
void DS1302_ReadTime(void)
{
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
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;
}
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
- main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
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);//显示秒
}
}
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
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
编辑 (opens new window)
上次更新: 2023/09/13, 12:29:52