当前位置:首页 > 技术 > 正文内容

51单片机矩阵键盘工作原理与C语言驱动实现

访客 技术 2026年6月23日 1

矩阵键盘的工作原理与硬件设计

在微控制器系统设计中,独立按键虽然逻辑简单,但每个按键都需要独占一个I/O引脚。当系统需要大量按键输入时,独立按键会迅速耗尽宝贵的I/O资源。为了解决这一问题,矩阵键盘应运而生。

矩阵键盘通过将按键排列成行和列的矩阵结构来大幅减少引脚占用。以4x4矩阵键盘为例,16个按键仅需8根控制线(4根行线和4根列线)。硬件连接上,通常将行线连接到单片机端口的高四位(如P1.4-P1.7),列线连接到低四位(如P1.0-P1.3)。

矩阵键盘硬件原理图

检测按键按下的核心在于识别具体是哪一行和哪一列的导线被短接。常用的扫描算法包括行列扫描法和线翻转法。

行列扫描法

行列扫描法通过逐列(或逐行)输出低电平,同时读取行(或列)的状态来判断按键位置。例如,先将第一列拉低,其余列保持高电平,然后读取行线的状态。如果某一行读取到低电平,则说明该行与第一列交叉处的按键被按下。通过循环遍历所有列,即可覆盖整个键盘矩阵。

线翻转法

线翻转法分为两步:首先将所有行线输出低电平,列线设为输入,读取列线状态以获取列坐标;随后将电平翻转,所有列线输出低电平,行线设为输入,读取行线状态以获取行坐标。结合两次读取的结果,即可精确计算出按键的矩阵坐标。这种方法执行效率较高,适合对响应速度要求严格的场景。

C语言驱动代码实现

以下代码示例展示了如何通过重构传统的冗余判断逻辑,使用位运算和循环结构来实现更优雅的矩阵键盘驱动。

1. 基础按键检测与数码管显示

本实例实现了行列扫描与线翻转两种算法,并将检测到的键值(1-16)映射为0-F的十六进制字符,通过共阴极数码管进行显示。


#include <REGX52.H>

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;

#define KEY_PORT P1
#define DIGIT_PORT P0

// 共阴极数码管 0-F 字模映射表
uint8_t code DIGIT_TABLE[16] = {
    0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
    0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71
};

void delay_ms(uint16_t ms) {
    uint16_t i, j;
    for(i = ms; i > 0; i--)
        for(j = 110; j > 0; j--);
}

// 行列扫描法实现
uint8_t scan_matrix_keyboard() {
    uint8_t col, row;
    uint8_t read_val;
    
    for(col = 0; col < 4; col++) {
        KEY_PORT = 0xFF;
        KEY_PORT &= ~(0x08 >> col); // 依次拉低 P1.3 至 P1.0
        
        read_val = KEY_PORT & 0xF0;
        if(read_val != 0xF0) {
            delay_ms(10); // 硬件消抖
            read_val = KEY_PORT & 0xF0;
            if(read_val != 0xF0) {
                for(row = 0; row < 4; row++) {
                    if(!(read_val & (0x80 >> row))) {
                        while((KEY_PORT & 0xF0) != 0xF0); // 等待按键释放
                        return row * 4 + col + 1;
                    }
                }
            }
        }
    }
    return 0;
}

// 线翻转法实现
uint8_t flip_scan_keyboard() {
    uint8_t row_val, col_val;
    uint8_t r = 0, c = 0;
    
    KEY_PORT = 0x0F; // 行线输出0,列线输入
    row_val = KEY_PORT & 0x0F;
    if(row_val != 0x0F) {
        delay_ms(10);
        row_val = KEY_PORT & 0x0F;
        if(row_val != 0x0F) {
            KEY_PORT = 0xF0; // 翻转:列线输出0,行线输入
            col_val = KEY_PORT & 0xF0;
            while((KEY_PORT & 0xF0) != 0xF0); // 等待按键释放
            
            // 解析列坐标
            if(row_val == 0x07) c = 0; 
            else if(row_val == 0x0B) c = 1; 
            else if(row_val == 0x0D) c = 2; 
            else if(row_val == 0x0E) c = 3;
            
            // 解析行坐标
            if(col_val == 0x70) r = 0; 
            else if(col_val == 0xB0) r = 1;
            else if(col_val == 0xD0) r = 2; 
            else if(col_val == 0xE0) r = 3;
            
            return r * 4 + c + 1;
        }
    }
    return 0;
}

void main() {        
    uint8_t key = 0;
    while(1) {
        key = scan_matrix_keyboard();
        if(key > 0) {
            DIGIT_PORT = DIGIT_TABLE[key - 1];
        }                
    }                
}

2. 矩阵键盘密码锁应用

在实际应用中,矩阵键盘常用于密码输入设备。以下代码将键盘驱动封装为独立模块,并结合LCD1602实现了一个四位数字密码锁系统。按键1-10对应数字输入,按键11为确认,按键12为取消。

MatrixKey.h


#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char Read_Matrix_Key(void);

#endif

MatrixKey.c


#include <REGX52.H>
#include "Delay.h"

unsigned char Read_Matrix_Key() {
    unsigned char col, row;
    unsigned char temp;
    
    for(col = 0; col < 4; col++) {
        P1 = 0xFF;
        P1 &= ~(0x08 >> col); // 动态拉低列线
        
        temp = P1 & 0xF0;
        if(temp != 0xF0) {
            Delay(20);
            temp = P1 & 0xF0;
            if(temp != 0xF0) {
                for(row = 0; row < 4; row++) {
                    if(!(temp & (0x80 >> row))) {
                        while((P1 & 0xF0) != 0xF0);
                        return row * 4 + col + 1;
                    }
                }
            }
        }
    }
    return 0;
}

main.c


#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"

unsigned char current_key;
unsigned int input_password;
unsigned char input_count;

void main() {
    LCD_Init();
    LCD_ShowString(1, 1, "Enter Pass:");
    input_password = 0;
    input_count = 0;
    LCD_ShowNum(2, 1, input_password, 4);
    
    while(1) {
        current_key = Read_Matrix_Key();
        if(current_key > 0) {
            // 数字键输入逻辑
            if(current_key <= 10 && input_count < 4) {
                input_password = input_password * 10 + (current_key % 10);
                input_count++;
                LCD_ShowNum(2, 1, input_password, 4);
            } 
            // 确认键逻辑
            else if(current_key == 11) {
                if(input_password == 1234) {
                    LCD_ShowString(1, 13, "Success");
                } else {
                    LCD_ShowString(1, 13, "Failed ");
                }
                input_password = 0;
                input_count = 0;
                LCD_ShowNum(2, 1, input_password, 4);
            } 
            // 取消键逻辑
            else if(current_key == 12) {
                input_password = 0;
                input_count = 0;
                LCD_ShowString(1, 13, "       ");
                LCD_ShowNum(2, 1, input_password, 4);
            }
        }
    }
}
标签: 51单片机

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。