独立按键,一个按键需要占用一个I/O口,如果需要16个按键,那么就会 占用16个I/O口,占据MCS-51系列单片机一半的I/O口。
理论基础
为了解决I/O这个问题,设计出了矩阵键盘,下图是一个4*4的矩阵键盘原理图。
按键按照4*4的格局进行摆放,组成4行4列,将按键的同行或同列连接在一起,分别连接到P1口。
怎么才能识别是哪个按键被按下呢?
以上图的S1为例,当按键被按下S1导通,P17与P13导通,可以通过判断P17与P13端口的电平是否一致,判断按键是否被按下。
可以先设置P13(检测端口)电平为高电平,假设P17(驱动端口)为低电平,当按键按下,按键导通,读取P13的电平可以读到低电平。
(1)设置驱动端口电平为高电平(1)或者低电平(0);
(2)判断检测端口电平是否与驱动端口的电平一致;
实践演练
P2口连接8个LED(如下图所示),P1口连接为4*4的矩阵键盘(如前面的矩阵键盘所示),当按键被按下时,P2口的LED点亮,点亮的LED与按键的键值一致。
写代码逻辑代码先确定S1功能的实现,然后以S1写其他的按键的代码。
假设设置P17为驱动端口,设置P13为检测端口。初始化时P17口与P13检测口初始状态均为0,然后设置P17口为1,检测P13是否变为高电平,当变为高电平时,说明有按键被按下,代码如下。
#include "reg52.h"
sbit driver_key1 = P1^7;
sbit snesor_key1 = P1^3;
void main() {
P2=0xff; //初始化P2口,P2口原有的数据影响
P1=0; //清空P1口,防止原有数据影响
while(1) {
char num=0; //设置键值
driver_key1 = 1; //驱动端口电平为1,驱动开始
if(snesor_key1==1) //判断检测端口是否为1,如果为1则按键被按下。
num = 1; //设置键值
driver_key1 = 0; //驱动端口电平为0,驱动结束
P2 =~num;
//由于I/O为低电平时,才可以被点亮。
//1的值换成二进制00000001,其余七个led被点亮第一个不亮,
//需要第一个led被点亮需要将1取反,二进制数变为1111 1110,第一个led亮。
}
}
使用上述代码,烧录程序后。LED灯不亮,按下按键S1,LED1也没有亮。这是由于按键按下时,P17驱动端的高电平,会被P13检测端的低电平拉成低电平,检测端口检测不到高电平。
将代码修改为初始化时P17口与P13检测口初始状态均为1,然后设置P17口为0,检测P13是否变为低电平,当变为低电平时,说明有按键被按下,修改代码如下。
void main() {
P2=0xff; //初始化P2口,P2口原有的数据影响
P1=0xff; //P1口置1,防止原有数据影响
while(1) {
char num=0; //设置键值
driver_key1 = 0; //驱动端口电平为0,驱动开始
if(snesor_key1==0) //判断检测端口是否为1,如果为1则按键被按下。
num = 1; //设置键值
driver_key1 = 1; //驱动端口电平为0,驱动结束
P2 =~num;
//由于I/O为低电平时,才可以被点亮。
//1的值换成二进制00000001,其余七个led被点亮第一个不亮,
//需要第一个led被点亮需要将1取反,二进制数变为1111 1110,第一个led亮。
}
}
编译烧录程序,当按下S1时,可以实现LED1被点亮。
将按键检测代码独立拉出来写成函数,实现16个按键,按压时对应的led被点亮,代码如下。
#include "reg52.h"
sbit driver_key1 = P1^7;
sbit driver_key2 = P1^6;
sbit driver_key3 = P1^5;
sbit driver_key4 = P1^4;
sbit snesor_key1 = P1^3;
sbit snesor_key2 = P1^2;
sbit snesor_key3 = P1^1;
sbit snesor_key4 = P1^0;
char key_scan() {
char num =0;
driver_key1 = 0;
if(snesor_key1==0)
num = 1;
if(snesor_key2==0)
num = 2;
if(snesor_key3==0)
num = 3;
if(snesor_key4==0)
num = 4;
driver_key1 = 1;
driver_key2 = 0;
if(snesor_key1==0)
num = 5;
if(snesor_key2==0)
num = 6;
if(snesor_key3==0)
num = 7;
if(snesor_key4==0)
num = 8;
driver_key2 = 1;
driver_key3 = 0;
if(snesor_key1==0)
num = 9;
if(snesor_key2==0)
num = 10;
if(snesor_key3==0)
num = 11;
if(snesor_key4==0)
num = 12;
driver_key3 = 1;
driver_key4 = 0;
if(snesor_key1==0)
num = 13;
if(snesor_key2==0)
num = 14;
if(snesor_key3==0)
num = 15;
if(snesor_key4==0)
num = 16;
driver_key4 = 1;
return num;
}
void main() {
P2=0xff; //初始化P2口,P2口原有的数据影响
P1=0xff; //清空P1口,防止原有数据影响
while(1) {
char num =0;
num = key_scan();
P2 =~num;
//由于I/O为低电平时,才可以被点亮。
//1的值换成二进制00000001,其余七个led被点亮第一个不亮,
//需要第一个led被点亮需要将1取反,二进制数变为1111 1110,第一个led亮。
}
}
总结:
(1)独立按键使用简单,如果项目中需要多个独立按键就会很浪费I/O资源;
(2)矩阵键盘通过判断按键两端的I/O是否一致,判断按键是否被按下;
(3)按键按下时,驱动端口的高电平会被检测端口的低电平拉低;
(4)对同一个功能可以写成函数,需要时进行函数调用,看代码时更有逻辑性。
上一篇:C51编程4-输入电平(独立按键)
下一篇:C51编程6-双向I/O口与准双向I/O口
推荐阅读最新更新时间:2024-11-20 10:50