- 嵌入式
- 固件
- 驱动开发
- 硬件开发
【免费下载链接】qmk_firmware
Open-source keyboard firmware for Atmel AVR and Arm USB families
HP 46010A 是惠普早期生产的一款老式终端键盘,其内部通过"时钟 + 复位 + 单线数据"的串行协议输出键位,无法直接连接现代电脑。QMK 仓库中keyboards/converter/hp_46010a提供了一个完整的转换器方案:以 Teensy 2.0(ATmega32u4)为桥接 MCU,通过自定义矩阵扫描逐行读回 14×8 键位矩阵,最终以标准 USB HID 键盘形态输出。读完本文,你将掌握该转换器的完整接线方法、引脚定义、固件编译烧录流程,以及自定义矩阵(CUSTOM_MATRIX)位带实现的工作原理。
项目定位:converter 目录下的老键盘复活方案
在 QMK 中,keyboards/converter/目录专门收录"键盘转接器"类目标——它们本身不是键盘,而是把老式或专用键盘的私有协议翻译成 USB HID 的设备固件。hp_46010a就位于其中,与adb_usb、ibm_terminal、m0110_usb、sun_usb、xt_usb等转换器并列。
从 keyboard.json 可以看出它的自我定位:
- 键盘名称为 "HP 46010A to USB Keyboard Converter";
- 维护者为 listofoptions;
- USB 标识为 VID
0xFEED、PID0x6060、设备版本0.0.1,并开启wait_for_enumeration; - 处理器为
atmega32u4,引导加载程序为halfkay——这正是Teensy 2.0的典型配置; - 固件特性中启用了
mousekey、extrakey、console、nkro,并关闭了bootmagic。
原 readme.md 明确给出硬件支持范围:HP 46010A 键盘 + Teensy 2.0。换言之,这是一个"协议转换器"固件:键盘内部逻辑负责扫描,Teensy 负责把扫描结果翻译成 USB 键码。
接线准备:认识 6P6C 接口与 PCB 引脚定义
转换器最关键的第一步,是把键盘线缆与 MCU 正确对接。原 readme 给出的做法是:
- 购买一个6P6C(六位六芯)模块化连接器,插入键盘对应的接口;
- 剪掉线缆另一端,把内部导线逐根剥出;
- 用万用表的蜂鸣/欧姆档(ohm-meter),逐根确认与 PCB 底部引脚对应的导线。
从 PCB 底部看,引脚排布如下(注意这是"底视图"编号):
4 5 6 3 2 1各引脚含义为:
| 引脚 | 含义 |
|---|---|
| 1 | reset(复位) |
| 2 | 无连接(no connection) |
| 3 | vcc(电源) |
| 4 | data out(数据输出) |
| 5 | clock(时钟) |
| 6 | ground(地) |
其中reset用于把键盘内部的扫描计数器复位到已知状态,clock驱动逐位移位,data out则是串行输出的单线数据——这三个信号构成了下文要讲的"位带 SPI"协议基础。
Teensy 与键盘的连线表
确认好每根导线对应哪个引脚之后,按下表把键盘接到 Teensy 2.0(其他 AVR 设备亦可,但需要自行核对引脚定义):
| Teensy 2.0 | HP 46010A |
|---|---|
| gnd | gnd(6) |
| vcc | vcc(3) |
| PB0 | reset(1) |
| PB1 | clock(5) |
| PB3 | data out(4) |
| gnd | no connection(2)——可选 |
这里PB0 / PB1 / PB3是 AVR 芯片端口 B 的位,对应 Teensy 2.0 上具体引出的物理引脚。readme 特别注明:引脚 2 为空脚,把 Teensy 的 gnd 也接到它是可选项(不接也不影响工作)。
这段连线表与固件源码中的引脚宏完全一一对应,见 matrix.c:
#define HP_46010A_RESET_PIN B0 #define HP_46010A_SCLK_PIN B1 #define HP_46010A_SDATA_PIN B3 #define HP_46010A_LED_PIN D6固件还会把 Teensy 的D6配置为输出并拉低——这是一个 LED 控制脚位,与键盘数据线无关。
编译与烧录固件
完成接线后,在 QMK 构建环境中执行原 readme 给出的编译命令:
make converter/HP_46010A:default- 第一次使用 QMK 的用户,可先阅读 newbs.md(入门指南)与 getting_started_make_guide.md(make 用法)完成构建环境搭建;
- 目标名
converter/HP_46010A:default表示编译keyboards/converter/hp_46010a下的default键位映射,产出对应 Teensy 2.0(halfkay引导)可用的固件; - 由于引导加载程序为
halfkay,烧录方式遵循 Teensy 标准流程(进入编程模式后由 Teensy 加载器写入),这正是 keyboard.json 中"bootloader": "halfkay"的含义。
键盘内部原理:7 位计数器驱动的 14×8 矩阵
要理解固件为何这样写,必须先知道 HP 46010A 键盘内部是如何扫描矩阵的。matrix.c 的注释给出了完整说明:
- 键盘内部有一个7 位计数器,由外部输入的
clock信号驱动,每来一个时钟脉冲计数加一; - 计数器低 3 位接到一个1-of-8 多路复用器,选中 8 列之一——这就是矩阵的列选择;
- 计数器高 4 位经过BCD 转十进制译码器(bcd-to-decimal),14 路输出接到 14 行(16 个输出中实际使用 14 个)——这就是矩阵的行选择;
- 每个按键串联一颗二极管:行信号 → 开关 → 二极管 → 列线,二极管的作用是防止多键同时按下时发生"鬼键"串扰;
reset引脚用于把整个计数器复位到初始状态。
因此,Teensy 读矩阵的方式不是逐行列扫,而是给 128 个时钟脉冲(7 位计数器周期),同时监听单线data out,把每次行选择对应的 8 位列状态按字节收回来。这就是 config.h 中MATRIX_ROWS 14、MATRIX_COLS 8的来源——14 行 × 8 列 = 112 个扫描位置,对应键盘上全部物理按键。
自定义矩阵:位带 SPI 逐字节读回键位
HP 46010A 的扫描逻辑与 QMK 默认矩阵驱动完全不同,因此该目标采用了 QMK 的完整自定义矩阵(Full Replacement)方案。rules.mk 只有两行:
CUSTOM_MATRIX = yes SRC = matrix.c其中CUSTOM_MATRIX = yes表示完全替换矩阵扫描实现,SRC = matrix.c把自定义扫描源码加入编译——这一配置方式与官方 custom_matrix.md 中"Full Replacement"一节的约定一致。
固件用**位带(bit-banging)**方式模拟 SPI 时序。原作者在注释中说明:键盘的输入是时钟与复位两条线,输出是单条数据线,本来也可以直接用 AVR 的 SPI 硬件外设,但这里选择了逐位翻转 GPIO 的软件实现。matrix.c 中的四个核心原语如下:
1.SCLK_increment()——产生一个时钟脉冲
gpio_write_pin_low(HP_46010A_SCLK_PIN); _delay_us( 4 ) ; // make sure the line is stable gpio_write_pin_high(HP_46010A_SCLK_PIN); _delay_us( 4 ) ;时钟先拉低再拉高,每个电平状态保持 4 微秒以确保信号稳定——这既推动键盘内部计数器前进,也是数据采样的节拍。
2.Matrix_Reset()——高有效复位计数器
gpio_write_pin_high(HP_46010A_RESET_PIN); _delay_us( 4 ) ; gpio_write_pin_low(HP_46010A_RESET_PIN);与常规"低有效"的复位不同,这块板子的reset是高有效:拉高后复位,再拉低回到正常工作状态。matrix_init()中把复位线初始状态设为低电平,正是为后续Matrix_Reset()的高脉冲做准备。
3.Matrix_ReceiveByte()——读回一个 8 位列字节
for ( uint8_t bit = 0; bit < MATRIX_COLS; ++bit ) { SCLK_increment(); temp = gpio_read_pin(HP_46010A_SDATA_PIN) << 4 ; received |= temp >> bit ; }每给一个时钟脉冲就读一次data out,把读到的位拼进字节——一个字节对应一行 8 列的状态。MATRIX_COLS在这里充当循环次数,从 config.h 可知其为 8。
4.Matrix_ThrowByte()——丢弃数据流的首字节
for ( uint8_t bit = 0; bit < MATRIX_COLS - 1; ++bit ) { SCLK_increment(); }注释指出键盘输出数据的第一个字节可以忽略,因此只需给出 7 个时钟(MATRIX_COLS - 1)把它"跳过"。
扫描主流程matrix_scan()的工作顺序为:
Matrix_ThrowByte()丢弃首字节;- 逐行调用
Matrix_ReceiveByte()读取 14 行 × 8 列的状态; - 配合软件去抖逻辑(见下);
- 本轮结束后调用
Matrix_Reset()复位计数器,为下一轮扫描做好准备。
去抖实现:matrix.c在未定义DEBOUNCE时默认设为 5(毫秒),并通过三份矩阵状态matrix、matrix_debounce_old、matrix_debounce_new实现"新状态与旧状态不同则启动去抖计时,超过DEBOUNCE毫秒才提交"的软件消抖逻辑,与 QMK 常规去抖思路一致。
初始化matrix_init()完成的事包括:把PB0(复位)、PB1(时钟)设为输出,PB3(数据)设为输入;复位线置低、时钟线置高;D6LED 脚设为输出并拉低;调用matrix_init_kb()回调链;最后执行一次Matrix_Reset()让键盘逻辑进入已知状态。
默认键位:LAYOUT 与键码映射
键盘矩阵本身只有"行、列"编号,把矩阵坐标映射到物理键位与键码的是LAYOUT布局与键位映射文件。
keyboard.json 中的LAYOUT定义了每个矩阵坐标matrix: [row, col]对应的物理位置x / y及键帽宽度w、高度h。从布局数据可以看出键盘的物理分区:
- 顶部一排功能键
F1~F12加 Esc; - 主键区:数字行、Q/W/E/R/T/Y 行、A/S/D/F 行、Z/X/C/V 行与空格行;
- 编辑键区:Insert/Home/Del/End/PageUp/PageDown 与方向键;
- 右侧独立的数字小键盘区(含
KC_P0、KC_PDOT、KC_PENT等)。
默认键位映射见 keymaps/default/keymap.c:源文件头部用 ASCII 图完整画出了键位分布,代码中以LAYOUT(...)按行填入键码。其中多处使用KC_NO(无功能占位)对应 ASCII 图中标注为xxxx的位置——这些是原键盘上实际不存在或未接线的键位,例如 F5/F6 上方的空位。这种"占满矩阵、空位用KC_NO"的写法,正是 14×8 矩阵中部分坐标无实体键的标准处理方式。
非美式布局:如何生成自己的矩阵
原 readme 特别提醒:如果你的 HP 46010A 与作者手中的布局不同(作者以美式 US 布局为例),矩阵定义也需要相应调整。为此 readme 附带了两个工具性参考:
- 一个是矩阵定义本身的示例(对应 US 布局下 14×8 的键位坐标表);
- 另一个是用于生成矩阵的程序——根据你的键盘实际键位,程序化地输出与
LAYOUT兼容的矩阵定义。
这两个资源以 gist 形式由维护者提供(详见原 readme.md 中的链接)。对于拿到不同地区版本的玩家,正确做法是:先按本文接线并跑通默认固件,再用矩阵生成程序推导自己这块板子的坐标表,替换 keyboard.json 中的LAYOUT或直接调整键位映射。
调试与扩展方向
- 串口调试:keyboard.json 开启了
console特性,配合matrix.c中的matrix_print()(按行打印r/c 01234567格式的二进制矩阵状态)可以在开发阶段直接观察 14 行矩阵每一位的读取结果,非常适合验证接线是否正确; - 矩阵实时观测:
matrix.c中保留了被注释掉的debug_matrix = 1;开关,打开后即可输出扫描过程; - 键位定制:由于输出端是标准 USB HID 键盘,你可以像普通 QMK 键盘一样修改 keymaps/default/keymap.c,甚至为这块老键盘添加层、宏、组合键等现代功能;
- 同类方案参考:
keyboards/converter/目录下其他目标(如m0110_usb、ibm_terminal、xt_usb等)同样采用"自定义矩阵 + 协议翻译"的思路,其中多块板子也使用CUSTOM_MATRIX = yes,遇到共性问题时可横向对比它们各自的matrix.c实现。
总结
HP 46010A 转换器的核心价值在于:它证明了一块 1980 年代的终端键盘,通过一个几十元的 Teensy 2.0 和一份精心编写的自定义矩阵驱动,就能完整融入现代 USB 生态。整个过程包含三条主线——硬件层(6P6C 接线与引脚定义)、协议层(时钟/复位/单线数据的 7 位计数器扫描逻辑)、固件层(CUSTOM_MATRIX位带实现与 14×8 矩阵读取)。对照 matrix.c、rules.mk 与 keyboard.json 三份源码,即可完整还原从物理接线到 USB 键码输出的全部链路。
- 嵌入式
- 固件
- 驱动开发
- 硬件开发
【免费下载链接】qmk_firmware
Open-source keyboard firmware for Atmel AVR and Arm USB families
相关推荐
QMK 固件矩阵接线图解读:以 Boston 120% 键盘的 matrix_diagram.md 为例
QMK 固件矩阵接线图解读:以 Boston 120% 键盘的 matrix_diagram.md 为例 本篇技术指南围绕 QMK Firmware 仓库中 B
嵌入式固件驱动开发硬件开发QMK Firmware pianoforte 键盘实战指南:矩阵引脚、键位布局与编译烧录
QMK Firmware pianoforte 键盘实战指南:矩阵引脚、键位布局与编译烧录 本文为 QMK Firmware 中 AliceH pianofor
嵌入式固件驱动开发硬件开发AMJ84 矩阵图解读:QMK 固件中 AMJ84 键盘的矩阵坐标、引脚映射与布局变体
AMJ84 矩阵图解读:QMK 固件中 AMJ84 键盘的矩阵坐标、引脚映射与布局变体 本篇技术指南以 QMK 仓库中 AMJ84 矩阵图 https://li
嵌入式固件驱动开发硬件开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考