Arduino 64 键原型键盘矩阵:用移位寄存器打造全自定义键盘
项目缘起
作者需要在一个嵌入式项目中集成键盘,但不能使用 USB 键盘或现成 Arduino 键盘库,因为目标 MCU 需要直接扫描矩阵。于是设计了这款无集成电路的 64 键 PCB 原型键盘:行列引脚直接引出到排针,配合 74HC595 移位寄存器仅占用 MCU 11 个 I/O,即可实现 64 键全键无冲 (NKRO) 扫描。
原理:键盘矩阵 + 二极管防鬼键
矩阵扫描:8 行 × 8 列 = 64 键。逐行拉低 (输出 LOW),读取 8 列 (输入上拉);列读 LOW 表示该行该列按键按下。全键盘每秒扫描 200 次 (每行 5 ms)。
1N4148 二极管:串联在每个按键阳极侧,单向导通防止“鬼键”,实现真正的 N-Key Rollover。
74HC595 省引脚:3 根线 (Data/Clock/Latch) 控制 8 行输出,节省 5 个 I/O。输入端直接用 MCU 内部上拉,不再用输入移位寄存器,避免抖动与噪声。
PCB 设计要点
- 工具:KiCad 原理图 + PCB;板框在 Fusion 360 绘制导出 DXF 导入 Edge.Cuts 层
- 按键布局参考标准键盘排列,走线需过孔 (2 层板)
- 关键坑点:KiCad 自带二极管符号引脚序与封装不一致,导致首版 PCB 二极管全反向。作者自建封装交换引脚序解决。
- Gerber 打包可直接上传 JLCPCB 等厂商生产
焊接建议
- 先焊 64 颗 1N4148 (注意标记方向),修剪引脚
- 再焊 64 颗 6×6×5 mm 轻触开关
- 最后焊 2×8 排针 (公/母均可,公头插在板底可直插面包板)
接线指南 (Arduino Uno 示例)
| 键盘列 | Arduino 引脚 |
|---|---|
| Col 1~6 | A0~A5 |
| Col 7 | D5 |
| Col 8 | D6 |
74HC595 接线:
- Data (DS/14) → D2
- Latch (ST_CP/12) → D3
- Clock (SH_CP/11) → D4
- VCC/GND 各两脚接 5V/GND
- 输出 Q0~Q7 对应 Row 1~8 (注意 Q1 对应 Row 2 等非顺序排布,详见文中 Pinout 表)
固件特性
- 零依赖库,纯手写扫描逻辑,确保每个键在每种修饰键组合下行为可独立定义
- 支持 Shift / CapsLock / Ctrl / Alt / Fn / Special 六种修饰键,正确处理 “Caps+Shift=小写” 等真实键盘逻辑
- 默认向串口输出 ASCII,替换
Serial.print即可接驱 OLED、LCD、USB HID 等 - 两个版本:
ProtoKeyboardV1-Bits.ino(v1.2) —— 位运算比较当前/上一帧全键盘状态,250 Hz 扫描,Flash 3.5 KB / RAM 605 B,兼容 Cortex-M4 等高速 MCUProtoKeyboardV1.1-Shifted.ino(旧版) —— 仅记录上一个按键,Flash 9.1 KB / RAM 394 B
新版核心扫描逻辑 (v1.2 精简版)
const int rowData=2, rowLatch=3, rowClock=4;
const int colPins[8] = {A0,A1,A2,A3,A4,A5,5,6};
byte shiftRow[8] = {B01111111, B10111111, B11011111, B11101111,
B11110111, B11111011, B11111101, B11111110};
byte rowState[8], prevRowState[8];
int rowToCheck = 0;
long prevMicros = 0, interval = 500; // µs
void setup() {
Serial.begin(9600);
for (int p: colPins) pinMode(p, INPUT_PULLUP);
pinMode(rowLatch, OUTPUT); pinMode(rowClock, OUTPUT); pinMode(rowData, OUTPUT);
updateShiftRegister(B11111111);
}
void loop() {
if (micros() - prevMicros > interval) {
prevMicros = micros();
checkKeyboard();
}
}
void checkKeyboard() {
updateShiftRegister(shiftRow[rowToCheck]);
for (int c=0; c<8; c++)
bitWrite(rowState[rowToCheck], c, digitalRead(colPins[c])==LOW);
updateShiftRegister(B11111111);
if (++rowToCheck > 7) { checkPressedKeys(); rowToCheck = 0; }
}
void checkPressedKeys() {
// 解析修饰键状态
bool shift = bitRead(rowState[5],1) | bitRead(rowState[6],4);
bool ctrl = bitRead(rowState[6],5) | bitRead(rowState[7],3);
bool spcl = bitRead(rowState[6],6) | bitRead(rowState[7],2);
bool alt = bitRead(rowState[6],7) | bitRead(rowState[7],1);
bool fn = bitRead(rowState[7],4);
bool caps = capsLockState; // 由 processKey 维护
bool capsShift = shift && caps;
for (int r=7; r>=0; r--)
for (int c=7; c>=0; c--) {
bool now = bitRead(rowState[r],c);
bool prev = bitRead(prevRowState[r],c);
if (now && !prev) { // 上升沿 = 新按下
int idx = r*8 + c;
char ch = capsShift ? capsShiftKey[idx] :
shift ? shiftKey[idx] :
ctrl ? ctrlKey[idx] :
alt ? altKey[idx] :
spcl ? spclKey[idx] :
fn ? fnKey[idx] :
caps ? capsKey[idx] : key[idx];
processKey(ch);
}
bitWrite(prevRowState[r], c, now);
}
}
void processKey(char k) {
if (k == 7) capsLockState = !capsLockState; // ASCII 7 = CapsLock 自定义码
else Serial.print(k);
}
void updateShiftRegister(byte b) {
digitalWrite(rowLatch, LOW);
shiftOut(rowData, rowClock, MSBFIRST, b);
digitalWrite(rowLatch, HIGH);
}
按键映射表 (key[] 数组索引 = 行×8+列)
数组按行主序排列,含字母、数字、符号、修饰键、功能键,共 64 位。修饰键位置固定 (如 Left Shift=Row5 Col1, Right Shift=Row6 Col4 等),其 ASCII 码设为 0,由单独逻辑处理。所有映射表 (key、shiftKey、capsKey… ) 均在代码开头,便于修改。
资源文件
- PCB Gerber 打包:
keyplots_4xipOSLHzg.zip(可直接下单打板) - 原理图 PDF:
schematic.pdf - 两版固件源码
适用场景
- 嵌入式设备原型需集成键盘
- 自制宏键盘、编程键盘、乐器控制器
- 教学演示键盘矩阵扫描、防鬼键原理
制造工艺
- Arduino Nano飞行模拟2020控制面板——LCD与CDI显示
- Arduino 飞行模拟器 2020 实体开关面板
- 将 MIDI 键盘变身智能钢琴导师:Arduino + LED 灯带 + MuseScore
- Arduino Uno驱动MAX7219级联8×8 LED矩阵:从入门到动画显示
- 校园智能体温监测系统 - 精准、实时、安全的学生健康守护方案
- Arduino 8 位并行 IO 端口库:一行代码实现 8 位数字读写
- Arduino Nano 专用 2.8 英寸 TFT 扩展板 – 320×240 SPI 显示屏
- 为Arduino构建隔离模拟输入电路
- Arduino DIY 计算器:1602 LCD + 4×4 矩阵键盘完整教程
- 掌握直流电机控制:PID 与 PWM 专家技巧全解析
- 低成本 Arduino 闪电探测器制作指南
- 适用于 Arduino 项目的智能室内导航机器人套件