前述
- 在闲暇的时候逛B站发现某UP使用了移位寄存器实现1*N矩阵键盘,就想着蛮简单的自己也动手弄一弄才发现踩的坑还挺多的。
- 今天就从图的设计到程序的编写来实现
- 今天所使用的单片机型号是MCU51,至于为什么不用STM32等其他主流主控芯片。因为懒的配置GPIO。直接修改寄存器就好了。但是其他单片机也是一样的方法
需要准备的工具
- Proteus主要用于仿真
- Keil5主要用于开发编写程序
- 74HC165芯片手册
芯片手册分析
打开芯片手册就可以直接的看到芯片的基本功能
该芯片工作电压在2v ~ 6v
并行输入转串行输出
主要应用在 视频的驱动,输出扩展,和今天要做的矩阵键盘
内部逻辑图
从图中可以看出使用的是RS锁存器进行数据的存储
前面的了解一下即可,重要的还是芯片的管脚
可以从下图看到每个管脚对应的作用
A-G:并行输入端
SER:串行输入端
Qh:串行输出端
Vcc:电源
GND:地线
CLK:时钟信号
- 芯片的真值表也是很重要的
- 真值表可以让我们编写程序来操作芯片工作
仿真部分
仿真使用的是Proteus,从芯片手册可以看到如果需要使用时钟上升沿当作移位信号那么
CLK INH
就直接接地即可。下面是Proteus的连接画叉叉的地方就是一个多输出端的电阻
这里我将两个芯片级联了,达到扩展16个输入端。还可以不断级联扩展并且还是只需要3根线也就是说不管级联多少都只需要3个IO口读取数据
上面那个芯片的Qh连接到了
P10
口,P10
就是数据的输入主要用来扫描寄存器里的数据根据真值表,两个
INH
连接地线即可,用于配合工作SH/LD非
是用来控制输入还是移位,连接到了P12
CLK
用于控制操作芯片工作,连接到了P11
最上面的示波器只是为了方便我们分析程序找出问题
程序编写
引入头文件和定义宏用于后面方便移植
1
2
3
4
5
6
7
8
typedef unsigned int u16;
typedef unsigned char u8;主要部分,扫描键盘输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
u16 KEY_Scan(void){
u8 i;
u16 key;
key = 0;
CLK = 1; //Set clock to 1
SH_LD = 0; //Read input
SH_LD = 1; // Stop reead input
key |= OUT;
for(i=0;i<15;i++){
CLK = 0; // Set clock to 0 to read data
CLK = 1; // Set clock to 1 to prefer next scan for data
key <<= 1;
key |= OUT;
}
CLK = 0;
return key;
}代码逻辑
- 置时钟为高电平
- 根据真值表设置SH/LD非获取用户输入的数据
- 将数据锁起来,停止用户输入
- 获取最高位数据存放到key中
- 循环依次获取每个寄存器的值放到key中,每循环一次左移1是为了不让后面的数据把当前数据替换掉。
CLK = 0,CLK = 1
是为了产生一个上升沿的信号 - 最后停止芯片的时钟
- 返回key,key存放的就是用户输入键盘的状态每一个比特位为一个按键的状态
这里key我使用了一个
u16
的数据类型是因为刚好有16个按键,每个按键的状态刚好对应了每一位比特位如果是要扩展32个按键可以使用unsigned long要是64个按键或更多按键可以使用一个unsigned long的数组存放
主函数,对按键状态取反是因为由于按键是低电平有效,反转后变成到高电平有效方便后期处理
1
2
3
4
5
6
7
8
9
10
11
12int main(void){
while(1){
u16 key = ~KEY_Scan();
u8 num = KeyToNum(key);
if (num != -1)
LED_ShowNum(num);
Delayms(10);
}
}完整代码
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
typedef unsigned int u16;
typedef unsigned char u8;
void Delayms(unsigned char x) //@12.000MHz
{
unsigned char i, j;
do{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
} while(--x);
}
void LED_ShowNum(u8 num){
u8 i,j;
i = num / 10;
j = num % 10;
P2 &= 0;
P2 |= j;
P2 <<= 4;
P2 |= i;
}
u16 KEY_Scan(void){
u8 i;
u16 key;
key = 0;
CLK = 1; //Set clock to 1
SH_LD = 0; //Read input
SH_LD = 1; // Stop reead input
key |= OUT;
for(i=0;i<15;i++){
CLK = 0; // Set clock to 0 to read data
CLK = 1; // Set clock to 1 to prefer next scan for data
key <<= 1;
key |= OUT;
}
CLK = 0;
return key;
}
u8 KeyToNum(u16 key){
u8 i;
for(i=0;i<16;i++)
if (((key >> i) & 0x01) == 0x01)
return i+1;
return -1;
}
int main(void){
while(1){
u16 key = ~KEY_Scan();
u8 num = KeyToNum(key);
if (num != -1)
LED_ShowNum(num);
Delayms(10);
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Jamie793’ S Blog!
评论