51单片机基础-矩阵按键

第八章 矩阵按键

1. 导入

在第七章中,我们学习了独立按键 的使用,每个按键占用一个I/O口,当按键数量较多时会迅速消耗单片机资源。为解决此问题,本章引入矩阵按键(也称行列式按键),通过"行线+列线"组合识别多个按键,显著节省I/O口。

矩阵按键广泛应用于键盘、遥控器、控制面板等设备中。本章目标:

  • 理解矩阵按键的结构与工作原理;
  • 掌握"行扫描法"和"列扫描法"识别按键;
  • 实现4×4矩阵键盘的按键识别;
  • 编写可靠的按键扫描函数;
  • 为后续实现密码锁、计算器等复杂输入系统打下基础。

2. 硬件设计

2.1 矩阵按键结构

以最常见的4×4矩阵键盘为例,由4条行线(Row)和4条列线(Col)组成,共可连接16个按键。

Col0 Col1 Col2 Col3
Row0 K1 K2 K3 K4
Row1 K5 K6 K7 K8
Row2 K9 K10 K11 K12
Row3 K13 K14 K15 K16

2.2 电路连接

  • 行线(Row0~Row3) :接P1.0 ~ P1.3,配置为输出
  • 列线(Col0~Col3) :接P1.4 ~ P1.7,配置为输入,需内部或外部上拉电阻;
  • 每个按键位于行线与列线交叉点,按下时导通。

实际连接示例:

  • P1.0 → Row0
  • P1.1 → Row1
  • P1.2 → Row2
  • P1.3 → Row3
  • P1.4 → Col0
  • P1.5 → Col1
  • P1.6 → Col2
  • P1.7 → Col3
    注意:P1口有内部上拉,可直接使用;若使用P0口,需外加上拉电阻。

3. 软件设计

3.1 工作原理

矩阵按键识别采用扫描法,基本步骤如下:

  1. 所有行线输出高电平;
  2. 读取列线状态,若某列为低,说明有键按下;
  3. 进入识别阶段:逐行输出低电平,其余行高;
  4. 再读列线,根据哪一行拉低及哪一列读低,确定具体按键;
  5. 软件消抖并返回键值。

3.2 行扫描法实现

c 复制代码
#include <reg52.h>

// 定义行和列
sbit ROW0 = P1^0;
sbit ROW1 = P1^1;
sbit ROW2 = P1^2;
sbit ROW3 = P1^3;

#define COL_PORT (P1 >> 4)  // 列线为P1.4~7,右移4位获取低4位

// 按键延时
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 125; j++);
}

// 矩阵按键扫描函数,返回键值(1~16),0表示无按键
unsigned char matrix_key_scan() {
    P1 = 0xF0;  // 行线输出高(P1.0~3=1),列线输入(P1.4~7上拉)

    if ((P1 & 0xF0) != 0xF0) {  // 列线有低电平,说明有键按下
        delay_ms(10);  // 消抖

        if ((P1 & 0xF0) != 0xF0) {
            // 开始逐行扫描
            P1 = 0xFE;  // Row0=0, Row1~3=1
            if ((P1 & 0xF0) != 0xF0) {
                switch (P1 & 0xF0) {
                    case 0xE0: return 1;
                    case 0xD0: return 2;
                    case 0xB0: return 3;
                    case 0x70: return 4;
                }
            }

            P1 = 0xFD;  // Row1=0
            if ((P1 & 0xF0) != 0xF0) {
                switch (P1 & 0xF0) {
                    case 0xE0: return 5;
                    case 0xD0: return 6;
                    case 0xB0: return 7;
                    case 0x70: return 8;
                }
            }

            P1 = 0xFB;  // Row2=0
            if ((P1 & 0xF0) != 0xF0) {
                switch (P1 & 0xF0) {
                    case 0xE0: return 9;
                    case 0xD0: return 10;
                    case 0xB0: return 11;
                    case 0x70: return 12;
                }
            }

            P1 = 0xF7;  // Row3=0
            if ((P1 & 0xF0) != 0xF0) {
                switch (P1 & 0xF0) {
                    case 0xE0: return 13;
                    case 0xD0: return 14;
                    case 0xB0: return 15;
                    case 0x70: return 16;
                }
            }
        }
    }
    return 0;  // 无按键
}

3.3 键值映射优化

为便于使用,可定义键值数组:

c 复制代码
unsigned char code key_table[4][4] = {
    {1,  2,  3,  4},
    {5,  6,  7,  8},
    {9,  10, 11, 12},
    {13, 14, 15, 16}
};

扫描时通过行列索引查表:

c 复制代码
unsigned char matrix_key_scan_simple() {
    unsigned char row, col;

    // 设置行为输出,列为输入
    P1 = 0xF0;
    if ((P1 & 0xF0) != 0xF0) {
        delay_ms(10);
        if ((P1 & 0xF0) != 0xF0) {

            // 扫描每一行
            for (row = 0; row < 4; row++) {
                P1 = (P1 & 0xF0) | (0x0F & ~(1 << row));  // 第row行输出0

                col = (P1 >> 4) & 0x0F;  // 读取列
                if (col != 0x0F) {
                    while((P1 >> 4) != 0x0F);  // 等待释放
                    return key_table[row][7 - col];  // 查表(需根据实际连接调整)
                }
            }
        }
    }
    return 0;
}

实际中需根据硬件连接调整行列对应关系。


3.4 应用示例:按键控制数码管显示

目标:按下矩阵键1~9,数码管显示对应数字。

c 复制代码
void main() {
    unsigned char key;
    unsigned char code seg_code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

    while(1) {
        key = matrix_key_scan();
        if (key >= 1 && key <= 9) {
            P0 = seg_code[key];        // 段码输出
            P2 = 0x0E;                 // 选中第一位
            delay_ms(5);
        }
    }
}

3.5 支持多按键识别(扩展)

上述方法仅支持单键识别。若需支持多键,需加入更复杂的逻辑或使用专用芯片。


3.6 编译与下载

  • Keil中创建工程;
  • 确保矩阵按键焊接或连接正确;
  • 编译生成HEX;
  • 下载至单片机;
  • 按下按键,观察数码管或串口是否返回正确键值。

若无响应:

  • 检查行列线是否接反;
  • 测量按下时是否真正导通;
  • 确认P1口方向控制正确。

##4. 小结

本章通过实现矩阵按键识别,掌握了高效输入系统的设计方法,主要内容包括:

  • 硬件结构:理解4×4矩阵键盘的行列布局与I/O节省优势;
  • 扫描原理:掌握行扫描法识别具体按键位置;
  • 软件实现:编写可靠的按键扫描函数,支持消抖与等待释放;
  • 应用扩展:实现按键控制数码管显示;
  • 开发能力:为复杂人机交互系统奠定基础。

4.1 常见问题与解决

问题 原因 解决方法
无法识别按键 行列接反、方向错误 检查I/O配置,确认输出/输入
误识别 抖动未消除 增加消抖延时或改进逻辑
只能识别部分键 扫描顺序错误 逐行测试,用万用表测量电平
重影 未等待释放 加入while等待松手
亮度闪烁 扫描时间过长 将按键扫描放入定时中断或优化循环

4.2 下一步学习建议

  • 学习外部中断结合矩阵键盘实现快速响应;
  • 使用定时器中断周期性扫描键盘,解放主程序;
  • 实现计算器密码锁综合项目;
  • 引入LCD1602显示更多信息。

本章标志着你已掌握高效的多键输入技术,下一章将进入定时器/计数器模块的深入学习,实现精准延时与中断控制。


相关推荐
一支闲人4 小时前
带你了解STM32:SPI通信(硬件部分)
stm32·单片机·嵌入式硬件·基础知识
我先去打把游戏先7 小时前
VSCode通过SSH连接到Ubuntu虚拟机失败“找不到ssh安装”问题解决
笔记·vscode·单片机·嵌入式硬件·学习·ubuntu·ssh
小欣加油9 小时前
leetcode 329 矩阵中的最长递增路径
c++·算法·leetcode·矩阵·深度优先·剪枝
学工科的皮皮志^_^9 小时前
电压源和电流源学习理解
单片机·嵌入式硬件·学习
linweidong11 小时前
跨平台驱动开发:打造兼容多款MCU的硬核方案
驱动开发·单片机·嵌入式硬件·bsp·rtos·spi驱动·hal设计
易享电子11 小时前
基于单片机大棚浇水灌溉控制系统Proteus仿真(含全部资料)
单片机·嵌入式硬件·fpga开发·51单片机·proteus
星辰pid14 小时前
STM32基于can总线通信控制多个舵机/电机原理及代码
stm32·单片机·嵌入式硬件
武文斌7714 小时前
项目学习总结:CAN总线、摄像头、STM32概述
linux·arm开发·stm32·单片机·嵌入式硬件·学习·c#
墨染天姬21 小时前
【AI】数学基础之矩阵
人工智能·线性代数·矩阵