51单片机 DS1302时钟演示+Proteus仿真

51单片机 DS1302时钟演示+Proteus仿真


在这里插入图片描述

程序代码

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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/\*
功能:数码管时钟显示。
(1)8位数码管显示设定的时间与日期。
(2)通过按键切换时间与日期的显示。
\*/

#include <reg52.h>

sbit LE_DUAN = P2^0; //定义573锁存使能端口 数码管段锁存
sbit LE_WEI = P2^1; //定义573锁存使能端口 数码管位锁存
#define SEGPORT P0 //定义数码管连接端口

sbit SCK = P1^6; // DS1302时钟线
sbit SDA = P1^7; // DS1302数据线
sbit RST = P1^5; // DS1302复位线

//DS1302 复位重定义
#define RST\_CLR RST=0 //电平置低
#define RST\_SET RST=1 //电平置高

//DS1302 数据
#define SDA\_CLR SDA=0 //电平置低
#define SDA\_SET SDA=1 //电平置高
#define SDA\_RD SDA //电平读取

//DS1302 时钟
#define SCK\_CLR SCK=0 //时钟信号
#define SCK\_SET SCK=1 //电平置高

#define DS1302\_SEC 0x80 //秒数据地址
#define DS1302\_MIN 0x82 //分数据地址
#define DS1302\_HOUR 0x84 //时数据地址
#define DS1302\_DATE 0x86 //日数据地址
#define DS1302\_MON 0x88 //月数据地址
#define DS1302\_DAY 0x8a //星期数据地址
#define DS1302\_YEAR 0x8c //年数据地址
#define DS1302\_CTRL 0x8e //控制数据地址
#define DS1302\_CHARGE 0x90 //涓流充电

bit ReadRTC_Flag; //读DS1302标志。1为读 0为不读。
unsigned char TimeMode; //日期与时间切换标志。

unsigned char time_buf1[8] = {40,21,11,6,17,30,50,7}; // -年月日时分秒周 2021-11-6 10:59:50 7周
unsigned char time_buf[8] ; // -年月日时分秒周
unsigned char TempData[8] ;

unsigned char code Seg_Wei[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //数码管的位码,低电平有效。
unsigned char code Seg_Duan[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //共阴数码管显示段码值 0~9,-

void DS1302\_Init(void);
void DS1302\_Write\_Byte(unsigned char addr, unsigned char d);
unsigned char DS1302\_Read\_Byte(unsigned char addr) ;
void DS1302\_Read\_Time(void);
void DS1302\_Write\_Time(void);

void Seg\_Disp(unsigned char FirstBit,unsigned char Num);
void InitTIMER0(void);//inital timer0
void Delay\_1ms(unsigned int i);
unsigned char GetKey(void);

void main(void)
{
unsigned char Key;
InitTIMER0();
DS1302\_Init();
DS1302\_Write\_Time();
P2=0xff; //51默认为输入
while(1)
{
Key = GetKey();
if(Key&0x01)
{
TimeMode = ~TimeMode; //有按键后,模式取反,改变当前显示模式
}
if(ReadRTC_Flag==1)
{
ReadRTC_Flag=0;
DS1302\_Read\_Time();
if(TimeMode)
{
TempData[0]=Seg_Duan[time_buf1[1]/10]; //年 数据的转换,
TempData[1]=Seg_Duan[time_buf1[1]%10]; //因我们采用数码管0~9的显示,将数据分开
TempData[2]=0x40; //加入"-"
TempData[3]=Seg_Duan[time_buf1[2]/10]; //月
TempData[4]=Seg_Duan[time_buf1[2]%10];
TempData[5]=0x40;
TempData[6]=Seg_Duan[time_buf1[3]/10]; //日
TempData[7]=Seg_Duan[time_buf1[3]%10];
}
else
{
TempData[0]=Seg_Duan[time_buf1[4]/10]; //时 数据的转换,
TempData[1]=Seg_Duan[time_buf1[4]%10]; //因我们采用数码管0~9的显示,将数据分开
TempData[2]=0x40; //加入"-"
TempData[3]=Seg_Duan[time_buf1[5]/10]; //分
TempData[4]=Seg_Duan[time_buf1[5]%10];
TempData[5]=0x40;
TempData[6]=Seg_Duan[time_buf1[6]/10]; //秒
TempData[7]=Seg_Duan[time_buf1[6]%10];
}
}
}
}

/\*------------------------------------------------
DS1302初始化
------------------------------------------------\*/
void DS1302\_Init(void)
{
RST_CLR; //RST脚置低
SCK_CLR; //SCK脚置低
DS1302\_Write\_Byte(DS1302_SEC,0x00);
}

/\*------------------------------------------------
向DS1302写入一字节数据
------------------------------------------------\*/
void DS1302\_Write\_Byte(unsigned char addr, unsigned char dat)
{
unsigned char i;
RST_SET;
addr = addr & 0xFE; //写地址 最低位为W写,低电平
for (i = 0; i < 8; i++)
{
if (addr & 0x01)
{
SDA_SET;
}
else
{
SDA_CLR;
}
SCK_SET;
SCK_CLR;
addr = addr >> 1;
}

//写入数据:dat
for (i = 0; i < 8; i ++)
{
if (dat & 0x01)
{
SDA_SET;
}
else
{
SDA_CLR;
}
SCK_SET;
SCK_CLR;
dat = dat >> 1;
}
RST_CLR; //停止DS1302总线
}


/\*------------------------------------------------
从DS1302读出一字节数据
------------------------------------------------\*/

unsigned char DS1302\_Read\_Byte(unsigned char addr)
{
unsigned char i;
unsigned char temp;
RST_SET;

addr = addr | 0x01; //最低RD,有效为高电平
for (i = 0; i < 8; i ++)
{
if (addr & 0x01)
{
SDA_SET;
}
else
{
SDA_CLR;
}
SCK_SET;
SCK_CLR;
addr = addr >> 1;
}

//输出数据:temp
for (i = 0; i < 8; i ++)
{
temp = temp >> 1;
if (SDA_RD)
{
temp |= 0x80;
}
else
{
temp &= 0x7F;
}
SCK_SET;
SCK_CLR;
}
SDA_CLR;//将读1个字节函数最后加上I/O=0即可消除85显示
RST_CLR; //停止DS1302总线
return temp;
}


/\*------------------------------------------------
从DS1302读出时钟数据
------------------------------------------------\*/
void DS1302\_Read\_Time(void)
{
unsigned char i,tmp;
time_buf[1]=DS1302\_Read\_Byte(DS1302_YEAR); //年
time_buf[2]=DS1302\_Read\_Byte(DS1302_MON); //月
time_buf[3]=DS1302\_Read\_Byte(DS1302_DATE); //日
time_buf[4]=DS1302\_Read\_Byte(DS1302_HOUR); //时
time_buf[5]=DS1302\_Read\_Byte(DS1302_MIN); //分
time_buf[6]=(DS1302\_Read\_Byte(DS1302_SEC))&0x7F;//秒
time_buf[7]=DS1302\_Read\_Byte(DS1302_DAY); //周

for(i=0;i<8;i++)
{ //BCD处理
tmp=time_buf[i]/16;
time_buf1[i]=time_buf[i]%16;
time_buf1[i]=time_buf1[i]+tmp\*10;
}
}


/\*------------------------------------------------
向DS1302写入时钟数据
------------------------------------------------\*/
void DS1302\_Write\_Time(void)
{

unsigned char i,tmp;
for(i=0;i<8;i++)
{ //BCD处理
tmp=time_buf1[i]/10;
time_buf[i]=time_buf1[i]%10;
time_buf[i]=time_buf[i]+tmp\*16;
}
DS1302\_Write\_Byte(DS1302_CTRL,0x00); //关闭写保护
DS1302\_Write\_Byte(DS1302_SEC,0x80); //暂停
//DS1302\_Write\_Byte(DS1302\_CHARGE,0xa9); //涓流充电
DS1302\_Write\_Byte(DS1302_YEAR,time_buf[1]); //年
DS1302\_Write\_Byte(DS1302_MON,time_buf[2]); //月
DS1302\_Write\_Byte(DS1302_DATE,time_buf[3]); //日
DS1302\_Write\_Byte(DS1302_HOUR,time_buf[4]); //时
DS1302\_Write\_Byte(DS1302_MIN,time_buf[5]); //分
DS1302\_Write\_Byte(DS1302_SEC,time_buf[6]); //秒
DS1302\_Write\_Byte(DS1302_DAY,time_buf[7]); //周
DS1302\_Write\_Byte(DS1302_CTRL,0x80); //打开写保护
}

/\*------------------------------------------------
数码管显示, pos为起始位
------------------------------------------------\*/
void Seg\_Disp(unsigned char pos,unsigned char Num)
{
static unsigned char i=0;

SEGPORT=0; //清空数据,防止有交替重影
LE_DUAN=1; //段锁存
LE_DUAN=0;

SEGPORT=Seg_Wei[i+pos]; //取位码
LE_WEI=1; //位锁存
LE_WEI=0;

SEGPORT=TempData[i]; //取显示数据,段码
LE_DUAN=1; //段锁存
LE_DUAN=0;

i++;
if(i==Num)
i=0;
}


/\*------------------------------------------------
Timer0 初始化,开中断,2ms定时
------------------------------------------------\*/
void InitTIMER0(void)
{
TMOD|=0x01; //定时器设置 16位
TH0=(65536-2000)/256; //定时时间 2ms
TL0=(65536-2000)%256;
EA=1;
ET0=1;
TR0=1;
}


/\*------------------------------------------------
简单延时程序:约1ms
------------------------------------------------\*/
void delay\_1ms(unsigned int i)
{
unsigned char j;
while(i--)
for(j=0;j<125; j++);
}


/\*------------------------------------------------
按键扫描 这里按键接在 P2.2
------------------------------------------------\*/
unsigned char GetKey(void)
{
unsigned char KeyTemp,CheckValue,Key=0x00;
CheckValue = P2&0x04;
if(CheckValue==0x04)
return 0x00;
delay\_1ms(10);
KeyTemp = P2&0x04;
if(KeyTemp == CheckValue)
return 0x00;
if(!(CheckValue&0x04))
Key = 0x01;
return Key;
}

void tim0\_isr(void) interrupt 1//中断,用于数码管扫描
{
static unsigned char num;
TH0=(65536-2000)/256; //重新赋值 2ms
TL0=(65536-2000)%256;

Seg\_Disp(0,8);
num++;

if(num==50) //大致100ms
{
num=0;
ReadRTC_Flag=1; //读标志位置1
}
}


仿真资源和程序源码

1
2
3
链接:https://pan.baidu.com/s/14uIUcheu9LcOXl\_W7HhuEA 
提取码:li0j