基于89C51的电子时钟设计

电子系统设计实验课–电子钟

代码是用C写的,写的很烂,基本没有考虑优化的问题。因为只有一个周的时间,我还要上蛋疼的雅思课,所以忽略函数的胡乱调用与变量的命名吧。
这个电子钟实现了如下功能:
- 时间的精确走动 - 时分秒年月日都可以通过键盘调节 - 秒表功能

做好的效果图是这样的:

硬件设计

整体来说用了一块89C51,用hc165来读键盘的信息,hc164来将输入的串行数据转并行输出,送LCD显示。读键值的原理图如下:
(乱码是什么鬼)
下面这张是hc164送显示的原理图:
(乱码又是什么鬼)

软件设计

大体上来说整个程序有两个部分:直接控制硬件的驱动层和我们实现电子钟功能的函数应用层。我们把它们分别放在DRI文件夹下和USR文件夹下。
#### 驱动层设计 (°_°)我要放源代码了:
##### hc165的底层控制代码

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
#include<reg52.h>
sbit hc165_sdo=P1^5;
sbit hc165_sclk=P1^6;
sbit hc165_pl=P1^7;
unsigned char key=0x3e;
void hc165_init(){
hc165_sdo=1;
hc165_sclk=0;
hc165_pl=1;
}
unsigned char hc165_re(void){
unsigned i,x=0;
hc165_pl=0;
x=x+0;
hc165_pl=1;
if( hc165_sdo == 1 )
x = x + 1;
for( i = 0;i < 7;i ++){
hc165_sclk=1;
x = x << 1;
hc165_sclk=0;
if( hc165_sdo == 1 )
x = x + 1;
}
return x;
}
hc164(LCD显示的底层控制代码)
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
#include<reg52.h>
#include<clock.h>
extern int data second[3];
unsigned char timedisplay[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
sbit LCD_E = P1^2;
sbit LCD_RW = P1^1;
sbit LCD_RS = P1^0;
sbit HC164_SDAT = P1^3;
sbit HC164_SCLK = P1^4;
extern clockTypeDef clock;
char position = 0;
unsigned char flash = 0;
unsigned char j = 0;
unsigned char code ascii[]={"0123456789"};
void send_data(unsigned char dat) {
unsigned char i;
for(i = 0; i < 8; i++){
HC164_SCLK = 0;
if(dat & 0x80){
HC164_SDAT = 1;
}
else{
HC164_SDAT = 0;
}
HC164_SCLK = 1;
dat = dat << 1;
}
}
void Delay1ms(unsigned int c) {
unsigned char a,b;
for(; c>0; c--) {
for(b = 199; b > 0; b--) {
for(a = 1; a > 0; a--);
}
}
}
void LcdWrCmd(unsigned char com) {
unsigned char x;
LCD_E = 0;
LCD_RS = 0;
LCD_RW = 0;
send_data(com);
x++;
LCD_E = 1;
x++;
LCD_E = 0;
Delay1ms(1);
}
void LcdWrData(unsigned char dat) {
unsigned char x;
LCD_E = 0;
LCD_RS = 1;
LCD_RW = 0;
send_data(dat);
x++;
LCD_E = 1;
x++;
LCD_E = 0;
Delay1ms(1);
}
void disp_line(unsigned char line) {
if(line == 0){
LcdWrCmd(0x80 + 0x00);
}
else{
LcdWrCmd(0x80 + 0x40);
}
}
void LcdInit(){
LcdWrCmd(0x38);
LcdWrCmd(0x0c);
LcdWrCmd(0x06);
LcdWrCmd(0x01);
}
void second_display() {
LcdWrCmd(0x01);
disp_line(0);
LcdWrData(ascii[second[0]/10]);
LcdWrData(ascii[second[0]%10]);
LcdWrData(0x27);
LcdWrData(ascii[second[1]/10]);
LcdWrData(ascii[second[1]%10]);
LcdWrData('"');
LcdWrData(ascii[second[2]/10]);
LcdWrData(ascii[second[2]%10]);
}
void time_display(){
unsigned char i;
timedisplay[0] = clock.Year/1000;
timedisplay[1] = clock.Year/100%10;
timedisplay[2] = clock.Year/10%10;
timedisplay[3] = clock.Year%10;
timedisplay[4] = clock.Month/10;
timedisplay[5] = clock.Month%10;
timedisplay[6] = clock.Day/10;
timedisplay[7] = clock.Day%10;
timedisplay[8] = clock.Hour/10;
timedisplay[9] = clock.Hour%10;
timedisplay[10] = clock.Minute/10;
timedisplay[11] = clock.Minute%10;
timedisplay[12] = clock.Second/10;
timedisplay[13] = clock.Second%10;
for(i = 0; i < 14; i ++){
if(i == 0)
disp_line(0);
if((i == 4)||(i == 6))
LcdWrData('-');
if(i == 8)
disp_line(1);
if((i == 10)||(i == 12))
LcdWrData(':');
if((i == position)&&(flash == 1)){
if(j >= 25){
if(j >= 50){
j = 0;
}
LcdWrData(' ');
}
else{
LcdWrData(ascii[timedisplay[i]]);
}
}
else{
LcdWrData(ascii[timedisplay[i]]);
}
}
}

用户层设计

用户层主要是一个计算时间的函数,时间的计算是通过定时器中断实现的,中断时间是10ms一次。因为我们添加了秒表功能。 ##### 时间计算

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
#include<reg52.h>
#include<clock.h>
int data time[6] = {1970,1,1,0,0,0};
int data second[3] ={0,0,0};
unsigned char timeMs10 = 0;
unsigned char secMs10 = 0;
clockTypeDef clock;
void timeCalc(void){
timeMs10++;
if(timeMs10 == 100) {
timeMs10 = 0;
time[5]++;
if(time[5] == 60) {
time[4]++;
time[5] = 0;
if(time[4] == 60) {
time[3]++;
time[4] = 0;
if(time[3] == 24) {
time[2]++;
time[3] = 0;
if(time[1] == 1 || time[1] == 3 || time[1] == 5 || time[1] == 7 || time[1] == 8 || time[1] == 10 || time[1] == 12) {
if(time[2] == 31) {
time[1]++;
time[2] = 0;
if(time[1] == 12) {
time[0]++;
}
}
}
if(time[1] == 4 || time[1] == 6 || time[1] == 9 || time[1] == 11) {
if(time[2] == 30) {
time[1]++;
time[2] = 0;
}
}
if(time[1] >= 2) {
if(time[0]%4 == 0) {
if(time[2] == 29) {
time[1]++;
time[2] = 0;
}
}
else
if(time[2] == 28) {
time[1]++;
time[2] = 0;
}
}
}
}
}
}
clock.Year = time[0];
clock.Month = time[1];
clock.Day = time[2];
clock.Hour = time[3];
clock.Minute = time[4];
clock.Second = time[5];
}
void secondCalc(void) {
secMs10++;
if(secMs10 == 1) {
second[2] += 1;
secMs10 = 0;
if(second[2] == 99) {
second[2] = 0;
second[1]++;
if(second[1] == 60) {
second[1] = 0;
second[0]++;
}
}
}
}

键盘处理
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
#include<reg51.h>
#include<key.h>
#include<hc165.h>
#include<lcd.h>
unsigned char flag;
extern unsigned char flash;
extern char position;
extern int data time[6];
unsigned char mode = 1;
unsigned char clearFlag = 1;
unsigned char startFlag = 1;
void keyControl(void) {
flag = hc165_re();
Delay1ms(100);
flag = hc165_re();
if(flag == 0xfe) {
mode = 0;
}
if(flag == 0xfd) {
if(startFlag == 0)
startFlag = 1;
else
startFlag = 0;
}
if(flag == 0xfb) {
flash = 1;
clearFlag = 0;
}
if(flag == 0x7f) {
flash = 0;
position = 0;
mode = 1;
}
if(flag == 0xf7) {
Delay1ms(100);
position = position - 1;
if(position < 0)
position = 13;
}
if(flag == 0xef) {
Delay1ms(100);
position = position + 1;
if(position > 13)
position = 0;
}
if(flag == 0xdf && flash == 1) {
Delay1ms(100);
if(position == 0) {
if(time[0]/1000 > 8)
time[0] = 0;
else
time[0] += 1000;
}
if(position == 1) {
if(time[0]/100%10 > 8)
time[0] = 0;
else
time[0] += 100;
}
if(position == 2) {
if(time[0]/10%10 > 8)
time[0] = 0;
else
time[0] += 10;
}
if(position == 3) {
if(time[0]%10 > 8)
time[0] = 0;
else
time[0] += 1;
}
if(position == 4) {
if(time[1]/10%10 > 0)
time[1] = 0;
else
time[1] += 10;
}
if(position == 5) {
if(time[1]%10 > 8)
time[1] = 0;
else
time[1] += 1;
}
if(position == 6) {
if(time[2]/10 > 2)
time[2] = 0;
else
time[2] += 10;
}
if(position == 7) {
if(time[2]%10 > 8)
time[2] = 0;
else
time[2] += 1;
}
if(position == 8) {
if(time[3]/10 > 1)
time[3] = 0;
else
time[3] += 10;
}
if(position == 9) {
if(time[3]%10 > 8)
time[3] = 0;
else
time[3] += 1;
}
if(position == 10) {
if(time[4]/10 > 4)
time[4] = 0;
else
time[4] += 10;
}
if(position == 11) {
if(time[4]%10 > 8)
time[4] = 0;
else
time[4] += 1;
}
if(position == 12) {
if(time[5]/10 > 4)
time[5] = 0;
else
time[5] += 10;
}
if(position == 13) {
if(time[5]%10 > 8)
time[5] = 0;
else
time[5] += 1;
}
}
if(flag == 0xbf && flash == 1) {
Delay1ms(100);
if(position == 0) {
if(time[0]/1000 < 1)
time[0] = 0;
else
time[0] -= 1000;
}
if(position == 1) {
if(time[0]/100%10 < 1)
time[0] = 0;
else
time[0] -= 100;
}
if(position == 2) {
if(time[0]/10%10 < 1)
time[0] = 0;
else
time[0] -= 10;
}
if(position == 3) {
if(time[0]%10 < 1)
time[0] = 0;
else
time[0] -= 1;
}
if(position == 4) {
if(time[1]/10%10 < 1)
time[1] = 0;
else
time[1] -= 10;
}
if(position == 5) {
if(time[1]%10 < 1)
time[1] = 0;
else
time[1] -= 1;
}
if(position == 6) {
if(time[2]/10 < 1)
time[2] = 0;
else
time[2] -= 10;
}
if(position == 7) {
if(time[2]%10 < 1)
time[2] = 0;
else
time[2] -= 1;
}
if(position == 8) {
if(time[3]/10 < 1)
time[3] = 0;
else
time[3] -= 10;
}
if(position == 9) {
if(time[3]%10 < 1)
time[3] = 0;
else
time[3] -= 1;
}
if(position == 10) {
if(time[4]/10 < 1)
time[4] = 0;
else
time[4] -= 10;
}
if(position == 11) {
if(time[4]%10 < 1)
time[4] = 0;
else
time[4] -= 1;
}
if(position == 12) {
if(time[5]/10 < 1)
time[5] = 0;
else
time[5] -= 10;
}
if(position == 13) {
if(time[5]%10 < 1)
time[5] = 0;
else
time[5] -= 1;
}
}
}

主函数和中断

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
#include<reg52.h>
#include<lcd.h>
#include<hc165.h>
#include<clock.h>
#include<key.h>
extern unsigned char j;
extern clockTypeDef clock;
extern unsigned char mode;
extern int data second[3];
extern unsigned char clearFlag;
extern unsigned char startFlag;
void main(){
TH0 = 0xd8;
TL0 = 0xf0;
TMOD = 0x01;
ET0 = 1;
TR0 = 1;
EA = 1;
hc165_init();
LcdInit();
while(1){
if(mode == 0)
second_display();
else
time_display();
keyControl();
}
}
void time_int0(void) interrupt 1 {
unsigned char i;
ET0 = 0;
TR0 = 0;
TH0 = 0xd8;//0x3c;
TL0 = 0xf0;//0xb0;
TR0 = 1;
timeCalc();
if(mode == 0 && startFlag == 0)
secondCalc();
if(mode == 0 && clearFlag == 0) {
for(i = 0; i < 3; i++){
second[i] = 0;
}
startFlag = 1;
clearFlag = 1;
}
j = j + 1;
ET0 = 1;
}

小结

从时间的计算上来说这个程序貌似并没有特别麻烦,有很多种实现的方法。这个程序的蛋疼之处在于我们计算出时间后必须将算出的时间逐位取出才能显示,所以增加了很多的工作量。还有就是关于修改时间的问题。通过按键来修改时间再简单不过,问题在于老师要求修改时间时被修改的数要实现闪烁,原来的6位数组不得不拆分成14位,增加了很多代码量。总的来说,因为开始做之前没有提前做好项目的整体规划,导致后期变量很乱,函数的调用函数值的传递也不是很合理。