4x4矩阵键盘接Arduino:扫描原理与密码输入实操

2026-11-11 20:28:14 15阅读

给机器人加个操作面板,或者给柜子做一把口令锁,绕不开同一件事:怎么用最少的引脚读一大堆按键。薄膜矩阵键盘就是干这个的,4x4 一共 16 个键,只吃 8 根线。这篇把扫描原理、接线和密码输入代码一次理顺,参数与代码逐项对照 Last Minute Engineers(教程 2026 年 1 月更新)和 ArduinoGetStarted 两家的页面核过,新手照着做能直接跑通。

4x4矩阵键盘接Arduino总览

16 个键为什么只要 8 根线

先算一笔账。如果 16 个键每个都当独立按键接,按每键一个引脚加公共地的接法,要吃掉 17 个引脚,UNO 根本供不起。排成 4 行 4 列的矩阵之后,每个键正好压在一个行线和一个列线的交叉点上,整块键盘只要 8 根线:4 根行线加 4 根列线。

这种用行列交叉复用引脚的思路叫多路复用(Multiplexing)。代价是程序不能一次判断哪个键被按下,得靠逐行扫描去定位,这也是很多人第一次接键盘时觉得"代码怎么这么绕"的成因。好在扫描逻辑库都封装好了,先把原理看懂,后面用起来就踏实。

4x3与4x4薄膜矩阵键盘外观

常见的是 4x3(12 键)和 4x4(16 键)两种,布局和电话键盘一致,上手没有学习成本。薄膜键盘还防水、便宜、耐按,做机器人面板或者门禁都合适。键盘背面引出一条杜邦母座排线,正面朝自己时,行引脚在左、列引脚在右。

扫描是怎么回事:逐行拉低,读列线

扫描的分工很明确:行线接 Arduino 的输出脚,列线接输入脚并启用内部上拉(INPUT_PULLUP),没有按键时列线稳定读高电平。单片机每次只把一行拉低、其余行保持高,然后逐个读列线;如果某根列线也变低了,说明这根行线和这根列线被某个键接通了,交叉点上的那个键就是被按下的键。

举个例子:程序拉低第 2 行,接着发现第 2 列也是低电平,那按下的就是行 2 列 2 交叉点上的"5"。每检测到一次按键,程序等键松开后再去 keymap 数组里查表,把行列坐标翻译成对应的字符,比如'4'、'A'或者'#'。整个过程几毫秒跑一轮,人手再快也感觉不到延迟。

薄膜键盘内部结构分层示意

顺带看一眼薄膜键盘的内部结构,一共六层:最上面是聚酯材质的图形面层,下面是负责"咔哒"手感的金属弹片,再往下是上电路层、隔层、下电路层,最后是背胶。按下一个键,实际是弹片把上下两层的导电触点压到了一起。

接线:一条杜邦排线解决

接线几乎不用动脑子,因为键盘引脚顺序和 Arduino 数字脚正好一一对应。从键盘 1 脚接 D9 开始,往后依次往下排就行。对照表如下:

键盘引脚Arduino 引脚
R1(行1)D9
R2(行2)D8
R3(行3)D7
R4(行4)D6
C1(列1)D5
C2(列2)D4
C3(列3)D3
C4(列4)D2

4x3 键盘少一列,C4 那一行对应关系直接去掉即可,程序里把列数改成 3。想接得整齐,用一条 8 针公对母杜邦排线最省事,不容易插错位;打算长期跑的项目,ArduinoGetStarted 的教程还建议加一块螺丝端子扩展板,把每根线拧在螺丝底下,比杜邦线扛折腾。

4x4矩阵键盘引脚排列

矩阵键盘与Arduino UNO接线图

装库与按键检测: getKey 一把梭

扫描逻辑不用自己写,装 Keypad 库就行。Arduino IDE 左侧点开库管理器,搜 keypad,认准 Mark Stanley、Alexander Brevig 写的那个,点安装。

Arduino IDE库管理器安装Keypad库

下面这份 4x4 例程从底稿教程原样搬来,逐字符没动过,唯一改动是头文件写法:站点编辑器会把尖括号头文件吞掉,所以按 Arduino 等价写法换成了双引号。

#include "Keypad.h"

const byte ROWS = 4;  //four rows
const byte COLS = 4;  //four columns

char keys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

byte rowPins[ROWS] = { 9, 8, 7, 6 };  //connect to the row pinouts of the keypad
byte colPins[COLS] = { 5, 4, 3, 2 };  //connect to the column pinouts of the keypad

//Create an object of keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup() {
  Serial.begin(9600);
}

void loop() {
  char key = keypad.getKey();  // Read the key

  // Print if key pressed
  if (key) {
    Serial.print("Key Pressed : ");
    Serial.println(key);
  }
}

烧录进板子,打开串口监视器,波特率设 9600,按哪个键屏幕上就打出哪个字符。代码骨架就四件事:keys 二维数组按键盘实际布局填字符,做计算器的话可以换成加减乘除;rowPins、colPins 两个数组按接线顺序填引脚号,顺序错了按键就对不上号;Keypad 构造函数把这几样收进去生成对象;loop 里 getKey() 不停轮询,有键按下就返回字符,没有就返回 0。

串口监视器输出按键字符

库还有几个函数值得记:waitForKey() 会阻塞程序死等一个键,菜单场景以外慎用;getState() 返回键的四种状态 IDLE、PRESSED、RELEASED、HOLD,配 keyStateChanged() 能做长按短按;setDebounceTime() 设消抖毫秒数,防止一次按压被算成两下;setHoldTime() 定长按阈值;addEventListener() 则挂个回调,有键事件就自动触发。

密码输入:两个功能键把按键串成口令

键盘最经典的用法就是口令锁。约定两个功能键:* 键清空重输,# 键提交比对,其余键都算密码字符。按下普通键就往字符串末尾追加,按下 # 就拿整串和预设密码比对,然后清空重来。

下面这份密码例程同样原样搬运自底稿教程,预设密码是"1234":

/*
 * Created by ArduinoGetStarted.com
 *
 * This example code is in the public domain
 *
 * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-keypad
 */

#include "Keypad.h"

const int ROW_NUM = 4; //four rows
const int COLUMN_NUM = 3; //three columns

char keys[ROW_NUM][COLUMN_NUM] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

byte pin_rows[ROW_NUM] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

const String password = "1234"; // change your password here
String input_password;

void setup(){
  Serial.begin(9600);
  input_password.reserve(32); // maximum input characters is 33, change if needed
}

void loop(){
  char key = keypad.getKey();

  if (key){
    Serial.println(key);

    if(key == '*') {
      input_password = ""; // clear input password
    } else if(key == '#') {
      if(password == input_password) {
        Serial.println("password is correct");
        // DO YOUR WORK HERE
      } else {
        Serial.println("password is incorrect, try again");
      }

      input_password = ""; // clear input password
    } else {
      input_password += key; // append new character to input password string
    }
  }
}

这份例程用的是 4x3 键盘,换 4x4 只改列数、keymap 和列引脚数组三处。串口里输入 123456 按 #,会回"password is incorrect, try again";输入 1234 按 #,回"password is correct",真正做锁的时候把注释那行换成开锁动作就行。input_password.reserve(32) 是给字符串预分配内存,避免频繁拼接产生内存碎片,这个小细节很多自己写口令的例子都漏了。

整体看,矩阵键盘是入门性价比极高的一块外设:接线十分钟,代码十几行,扫描原理还顺便把"复用引脚"这个思想讲透了。往后想升级,把提交动作接到继电器驱动电磁锁,或者把按下的键显示到 LCD 上做成完整面板,都是顺手的事。


作者:固件烧录仔
链接:https://www.aiddithome.com/p/984878dd436fa.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
5条评论
拆开看看再说
1楼 · 20分钟前

照着接了一遍,8根杜邦线插完直接就出字了,比想象中顺利。就是C4那根一开始插错列,按出来全对不上号,回来看引脚表才找到问题。

刷视频进来围观
2楼 · 20分钟前

getKey() 轮询确实省事,不过waitForKey()那句提醒很有必要,我上次用它直接把电机控制卡死了,菜单场景慎用是真的。

只看不说话
3楼 · 20分钟前

密码那个例子改改就能接到电磁锁上了,实用

板砖搬不动
4楼 · 20分钟前

扫描那段写得很清楚,之前一直纳闷为什么键盘就8根线能管16个键,看到行列交叉那张图才反应过来,本质上就是数学里的组合问题。把行拉低读列这个思路,其实跟LED点阵屏是一个道理,学会一个另一个就通了。

电烙铁爱好者
5楼 · 20分钟前

reserve(32)这个细节提得好,String拼接确实容易炸内存,新手踩过一次就长记性了