【51单片机】矩阵按键快速上手

51单片机矩阵按键是一种在单片机应用系统中广泛使用的按键排列方式,特别适用于需要多个按键但I/O口资源有限的情况。以下是对51单片机矩阵按键的详细介绍:

一、矩阵按键的基本概念

  • 定义‌:矩阵按键,又称行列键盘,是用多条行线和列线交叉组成的键盘。在行线和列线的每个交叉点上设置一个按键,从而实现用较少的I/O口控制多个按键。
  • 优势‌:矩阵按键能够有效地提高单片机系统中I/O口的利用率。例如,一个4x4的矩阵键盘只需8个I/O口就可以实现16个按键的功能。

二、矩阵按键的工作原理

  • 行列扫描法‌:这是最常用的矩阵按键检测方法。首先,单片机通过程序控制将某一列线置为低电平,其余列线置为高电平,然后检测各行线是否有低电平信号。如果有,说明该行线与置为低电平的列线交叉点上的按键被按下。接着,轮流将各列线置为低电平,并检测各行线,直到找出被按下的按键。
  • 线翻转法‌:另一种检测方法是线翻转法。首先,将所有行线置为低电平,检测所有列线是否有低电平信号。如果有,记录列线值。然后,将所有列线置为低电平,检测所有行线的值。由于有按键按下,行线的值也会有变化,记录行线的值。通过这种方法,可以检测到所有被按下的按键。

三、矩阵按键的编程实现

  • 初始化‌:在程序中,首先需要初始化与矩阵键盘连接的I/O口,设置它们的初始状态。
  • 扫描与检测‌:然后,通过循环或中断的方式不断扫描矩阵键盘。在扫描过程中,根据行列扫描法或线翻转法的原理,检测按键是否被按下。
  • 消抖处理‌:由于机械按键在按下和松开时会产生抖动,因此需要在程序中加入消抖处理。常用的消抖方法有软件消抖和硬件消抖。在单片机应用中,软件消抖更为常见。
  • 按键功能实现‌:当检测到按键被按下时,根据按键的位置执行相应的功能。例如,在计算器程序中,按键的位置可能对应不同的数字或运算符。

四、矩阵按键的应用实例

  • 计算器‌:矩阵按键常用于计算器的键盘设计。通过4x4或更大规模的矩阵键盘,可以实现数字输入、运算符选择和功能键等操作。
  • 电子密码锁‌:在电子密码锁中,矩阵按键用于输入密码。用户可以通过按下矩阵键盘上的按键来输入数字或字母密码。
  • 游戏控制器‌:在一些简单的游戏控制器中,矩阵按键也常被用于实现方向键、功能键等操作。

当我们按下某一个按键时,该按键对应的那一行和那一列的引脚为0,其他的引脚为1

硬件原理图

代码实现

分别检测

cpp 复制代码
#include "Int_MatrixKey.h"
#include <STC89C5xRC.H>

u8 Int_MatrixKey_CheckKey()
{

    //    P24 P25 P26 P27
    // P20 +---+---+---+
    // P21 +---+---+---+
    // P22 +---+---+---+
    // P23 +---+---+---+

    // 扫描第一行,将P20置0,其余置1;P27-P20依次为:1111 1110
    P2 = 0xFE;

    // 检测第SW5是否被按下,若被按下,P24会被拉低,P27-P20依次为:1110 1110
    if (P2 == 0xEE) {
        Delay1ms(10);
        if (P2 == 0xEE) {
            while (P2 == 0xEE);
            return 5;
        }
    }

    // 检测第SW6是否被按下,若被按下,P25会被拉低,P27-P20依次为:1101 1110
    if (P2 == 0xDE) {
        Delay1ms(10);
        if (P2 == 0xDE) {
            while (P2 == 0xDE);
            return 6;
        }
    }

    // 检测第SW7是否被按下,若被按下,P26会被拉低,P27-P20依次为:1011 1110
    if (P2 == 0xBE) {
        Delay1ms(10);
        if (P2 == 0xBE) {
            while (P2 == 0xBE);
            return 7;
        }
    }

    // 检测第SW8是否被按下,若被按下,P28会被拉低,P27-P20依次为:0111 1110
    if (P2 == 0x7E) {
        Delay1ms(10);
        if (P2 == 0x7E) {
            while (P2 == 0x7E);
            return 8;
        }
    }

    // 扫描第二行,将P22置0,其余置1;P27-P20依次为:1111 1101
    P2 = 0xFD;
    // 检测第SW9是否被按下,若被按下,P24会被拉低,P27-P20依次为:1110 1101
    if (P2 == 0xED) {
        Delay1ms(10);
        if (P2 == 0xED) {
            while (P2 == 0xED);
            return 9;
        }
    }

    // 检测第SW10是否被按下,若被按下,P25会被拉低,P27-P20依次为:1101 1101
    if (P2 == 0xDD) {
        Delay1ms(10);
        if (P2 == 0xDD) {
            while (P2 == 0xDD);
            return 10;
        }
    }

    // 检测第SW11是否被按下,若被按下,P26会被拉低,P27-P20依次为:1011 1101
    if (P2 == 0xBD) {
        Delay1ms(10);
        if (P2 == 0xBD) {
            while (P2 == 0xBD);
            return 11;
        }
    }

    // 检测第SW12是否被按下,若被按下,P28会被拉低,P27-P20依次为:0111 1101
    if (P2 == 0x7D) {
        Delay1ms(10);
        if (P2 == 0x7D) {
            while (P2 == 0x7D);
            return 12;
        }
    }

    // 扫描第三行,将P22置0,其余置1;P27-P20依次为:1111 1011
    P2 = 0xFB;
    // 检测第SW13是否被按下,若被按下,P24会被拉低,P27-P20依次为:1110 1011
    if (P2 == 0xEB) {
        Delay1ms(10);
        if (P2 == 0xEB) {
            while (P2 == 0xEB);
            return 13;
        }
    }

    // 检测第SW14是否被按下,若被按下,P25会被拉低,P27-P20依次为:1101 1011
    if (P2 == 0xDB) {
        Delay1ms(10);
        if (P2 == 0xDB) {
            while (P2 == 0xDB);
            return 14;
        }
    }

    // 检测第SW15是否被按下,若被按下,P26会被拉低,P27-P20依次为:1011 1011
    if (P2 == 0xBB) {
        Delay1ms(10);
        if (P2 == 0xBB) {
            while (P2 == 0xBB);
            return 15;
        }
    }

    // 检测第SW16是否被按下,若被按下,P28会被拉低,P27-P20依次为:0111 1011
    if (P2 == 0x7B) {
        Delay1ms(10);
        if (P2 == 0x7B) {
            while (P2 == 0x7B);
            return 16;
        }
    }

    // 扫描第四行,将P23置0,其余置1;P27-P20依次为:1111 0111
    P2 = 0xF7;
    // 检测第SW17是否被按下,若被按下,P24会被拉低,P27-P20依次为:1110 0111
    if (P2 == 0xE7) {
        Delay1ms(10);
        if (P2 == 0xE7) {
            while (P2 == 0xE7);
            return 17;
        }
    }

    // 检测第SW18是否被按下,若被按下,P25会被拉低,P27-P20依次为:1101 0111
    if (P2 == 0xD7) {
        Delay1ms(10);
        if (P2 == 0xD7) {
            while (P2 == 0xD7);
            return 18;
        }
    }

    // 检测第SW19是否被按下,若被按下,P26会被拉低,P27-P20依次为:1011 0111
    if (P2 == 0xB7) {
        Delay1ms(10);
        if (P2 == 0xB7) {
            while (P2 == 0xB7);
            return 18;
        }
    }

    // 检测第SW20是否被按下,若被按下,P28会被拉低,P27-P20依次为:0111 0111
    if (P2 == 0x77) {
        Delay1ms(10);
        if (P2 == 0x77) {
            while (P2 == 0x77);
            return 20;
        }
    }

    return 0;
}

循环方式

cpp 复制代码
u8 Int_KeyMatrix_CheckKey()
{
    u8 i, j;
    u8 lines[4]   = {0xFE, 0xFD, 0xFB, 0xF7};
    u8 columns[4] = {0x10, 0x20, 0x40, 0x80};
    for (i = 0; i < 4; i++) {
        P2 = lines[i];
        for (j = 0; j < 4; j++) {
            if ((P2 & columns[j]) == 0x00) {
                Com_Util_Delay1ms(10);
                if ((P2 & columns[j]) == 0x00) {
                    while ((P2 & columns[j]) == 0x00);
                    return 5 + j + 4 * i;
                }
            }
        }
    }
    return 0;
}

通过这个函数就可以获取到每个矩阵对应的数字了

cpp 复制代码
int main(){
    u8 key;
    while(1){
        key = Int_KeyMatrix_CheckKey();
        if(key){
            //对应逻辑
        }
    }
}
相关推荐
掂过碌蔗呀10 分钟前
Java调用C/C++那些事(JNI)
java·c语言·c++
安冬的码畜日常31 分钟前
【Vim Masterclass 笔记19】S08L36 + L37:第八章 Vim 可视化模式同步练习(含点评课内容)
笔记·vim·自学笔记·vim可视化模式·visual mode·vim visual mode·vim同步练习
爱小黄1 小时前
c语言编程求一个函数的极限
c语言·开发语言
生活很暖很治愈1 小时前
《C 语言与冒泡排序算法的碰撞》
c语言·算法
小志biubiu1 小时前
技术洞察:C++在后端开发中的前沿趋势与社会影响
开发语言·c++·笔记·学习·区块链·c11
安冬的码畜日常1 小时前
【Vim Masterclass 笔记20】第九章:Vim 的个性化设置 + S09L38:Vim 设置与 vimrc 文件的用法示例(一)
笔记·vim·自学笔记·vimrc·vim设置·vim定制
mit6.8242 小时前
[实现Rpc] 环境搭建 | JsonCpp | Mudou库 | callBack()
网络·c++·笔记·网络协议·rpc
灰勒塔德2 小时前
Linux-----线程同步(条件变量)
linux·运维·服务器·c语言
doubt。2 小时前
【BUUCTF】[NCTF2019]SQLi
网络·笔记·sql·安全·web安全
张小妍的博客3 小时前
STL简述
c语言·开发语言·c++