基于51单片机的矩阵键盘设计

描述

独立按键,一个按键需要占用一个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)对同一个功能可以写成函数,需要时进行函数调用,看代码时更有逻辑性。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分