# 自制按键计数器

# 思路

独立按键按下一次代表一次数据 主函数不断循环 每一次循环都会检测按键是否被按下 (原来想尝试外部中断 0 的方法 也就是没隔一段时间检测一次键盘是否被按下 但是如果使用 P32 短接 GND 的话 就太麻烦了 软件控制电平来触发外部中断的话 还不如学到计时器的时候用终端 1 要简单的多) 如果被按下 计数器加一 并且在数码管上面显示出来 当位数多起来时 就用动态显示来实现

# 遇到的问题

这过程中遇到很多问题 最多的问题就是数码管的残影问题和代码逻辑问题😂

# 数码管残影

残影最开始出现的时候 我一度认为是我的代码写错了 (当然 代码写错的确有可能导致显示错误) 所以就一直把代码改来改去 但是并没有什么明显的效果 后来上网搜了一下才发现是数码管存在残影的问题

一开始想的很简单 以为就根据普遍做法

1
2
3
4
5
6
7
8
9
P0 = 0xff;		//清除段选对位选的影响  也就是让数码管全部关闭
wela = 1; //打开位选
P0 = location[j];
wela = 0; //关闭位选

P0 = 0; //清除位选对段选的影响 也就是让数码管的数字都不亮
dula = 1; //打开段选
P0 = table[a[j]];
dula = 0; //关闭段选

但是仍然没有效果 (可能是因为指令执行的还是太快了)

所以通过 delay 函数来控制扫描的速率 来解决这个问题 但是这个方式会有一个小隐患 扫描速率不好调整 扫描快了 (delay 函数定时短) 会有残影 扫描慢了 (delay 函数定时长) 达不到效果

其实后面键盘倒是没有什么难度 独立键盘的话直接检测就好了 只是要注意一个按键防抖 因为当按下按键的过程中 电路的导通状态并不只是一个正常的开断 而是以下这个情况

1

矩阵键盘的话 可以类似于坐标轴找点 视频里面说的 “线与” 关系 其实就是 只知道 X 轴或者 Y 轴坐标 定位不了具体的点 所以要在很快的时间内 (手松开按键之前) 连续检测行和列的电压值从而得出是哪一个键被按下了

# 成品代码如下 :

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
/***********单按键版本***************/

#include<reg52.h>

sbit key_s2 = P3^0;
sbit dula = P2^6;
sbit wela = P2^7;

char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
char code location[] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};

void delay(int z)
{
int x,y;

for (x = 114; x; x--)
{
for (y = z; y; y--);
}
}

void display(int num)
{
int i,j,temp,a[8];

for (i = 0, temp = num; temp; i++, temp /= 10)
{
a[i] = temp % 10;
}

for (j = 0; j < i; j++)
{
P0 = 0xff;
wela = 1;
P0 = location[j];
wela = 0;

P0 = 0;
dula = 1;
P0 = table[a[j]];
dula = 0;
delay(0);
}

if (num == 0)
{
P0 = 0xff;
wela = 1;
P0 = location[0];
wela = 0;

P0 = 0;
dula = 1;
P0 = table[0];
dula = 0;
delay(0);
}
}

int num = 0;

void main()
{
EA = 1; //中断总开关
ET1 = 1; //T1中断开关
TR1 = 1; //T1运行开关
TMOD = 0x10; //模式选择
TH1 = 0x4b;
TL1 = 0xfc;

while (1)
{
display(num);
}
}

void timer1() interrupt 3
{
TH1 = 0x4b;
TL1 = 0xfc; //定时5ms

if (!key_s2)
{
delay(10);

if (!key_s2)
{
num++;
while (!key_s2); //判断手是否松开 没有松开的话就一直循环
}
}
}

矩阵键盘版本 :

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
/***********矩阵键盘版**********/

#include<reg52.h>

sbit dula = P2^6;
sbit wela = P2^7;

char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
char code location[] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};

void delay(int z)
{
int x,y;

for (x = 114; x; x--)
{
for (y = z; y; y--);
}
}

void display(int num)
{
int i,j,temp,a[8];

for (i = 0, temp = num; temp; temp /= 10, i++)
{
a[i] = temp % 10;
}

for (j = 0; j < i; j++)
{
P0 = 0xff;
wela = 1;
P0 = location[j];
wela = 0;

P0 = 0;
dula = 1;
P0 = table[a[j]];
dula = 0;
delay(0);
}

if (!num)
{
P0 = 0xff;
wela = 1;
P0 = location[0];
wela = 0;

P0 = 0;
dula = 1;
P0 = table[0];
dula = 0;
delay(0);
}
}

int num = 0;

void main()
{
EA = 1;
TR0 = 1;
ET0 = 1;
TH0 = 0x4b;
TL0 = 0xfc;
TMOD = 0x01;

while (1)
{
display(num);
}
}

void keyscan() interrupt 1
{
TH0 = 0x4b;
TL0 = 0xfc;

P3 = 0xf0;

if (P3 != 0xf0)
{
delay(10);

if (P3 != 0xf0)
{
switch (P3)
{
case 0xe0 : num = 1;break;
case 0xd0 : num = 2;break;
case 0xb0 : num = 3;break;
case 0x70 : num = 4;break;
}

P3 = 0x0f;

if (P3 != 0x0f)
{
switch (P3)
{
case 0x0e : num += 0;break;
case 0x0d : num += 4;break;
case 0x0b : num += 8;break;
case 0x07 : num += 12;break;
}
}
}

P3 = 0xf0;

while (P3 != 0xf0);
}
}
更新于 阅读次数