news 2026/9/19 22:21:05

用 QMK 为 HP 46010A 老式键盘制作 USB 转换器:引脚接线、位带 SPI 矩阵读取与固件编译

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 QMK 为 HP 46010A 老式键盘制作 USB 转换器:引脚接线、位带 SPI 矩阵读取与固件编译
  • 嵌入式
  • 固件
  • 驱动开发
  • 硬件开发

【免费下载链接】qmk_firmware

Open-source keyboard firmware for Atmel AVR and Arm USB families

项目地址:https://gitcode.com/GitHub_Trending/qm/qmk_firmware
点击查看免费下载

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_usbibm_terminalm0110_usbsun_usbxt_usb等转换器并列。

从 keyboard.json 可以看出它的自我定位:

  • 键盘名称为 "HP 46010A to USB Keyboard Converter";
  • 维护者为 listofoptions;
  • USB 标识为 VID0xFEED、PID0x6060、设备版本0.0.1,并开启wait_for_enumeration
  • 处理器为atmega32u4,引导加载程序为halfkay——这正是Teensy 2.0的典型配置;
  • 固件特性中启用了mousekeyextrakeyconsolenkro,并关闭了bootmagic

原 readme.md 明确给出硬件支持范围:HP 46010A 键盘 + Teensy 2.0。换言之,这是一个"协议转换器"固件:键盘内部逻辑负责扫描,Teensy 负责把扫描结果翻译成 USB 键码。

接线准备:认识 6P6C 接口与 PCB 引脚定义

转换器最关键的第一步,是把键盘线缆与 MCU 正确对接。原 readme 给出的做法是:

  1. 购买一个6P6C(六位六芯)模块化连接器,插入键盘对应的接口;
  2. 剪掉线缆另一端,把内部导线逐根剥出;
  3. 用万用表的蜂鸣/欧姆档(ohm-meter),逐根确认与 PCB 底部引脚对应的导线。

从 PCB 底部看,引脚排布如下(注意这是"底视图"编号):

4 5 6 3 2 1

各引脚含义为:

引脚含义
1reset(复位)
2无连接(no connection)
3vcc(电源)
4data out(数据输出)
5clock(时钟)
6ground(地)

其中reset用于把键盘内部的扫描计数器复位到已知状态,clock驱动逐位移位,data out则是串行输出的单线数据——这三个信号构成了下文要讲的"位带 SPI"协议基础。

Teensy 与键盘的连线表

确认好每根导线对应哪个引脚之后,按下表把键盘接到 Teensy 2.0(其他 AVR 设备亦可,但需要自行核对引脚定义):

Teensy 2.0HP 46010A
gndgnd(6)
vccvcc(3)
PB0reset(1)
PB1clock(5)
PB3data out(4)
gndno 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 14MATRIX_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()的工作顺序为:

  1. Matrix_ThrowByte()丢弃首字节;
  2. 逐行调用Matrix_ReceiveByte()读取 14 行 × 8 列的状态;
  3. 配合软件去抖逻辑(见下);
  4. 本轮结束后调用Matrix_Reset()复位计数器,为下一轮扫描做好准备。

去抖实现matrix.c在未定义DEBOUNCE时默认设为 5(毫秒),并通过三份矩阵状态matrixmatrix_debounce_oldmatrix_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_P0KC_PDOTKC_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_usbibm_terminalxt_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

项目地址:https://gitcode.com/GitHub_Trending/qm/qmk_firmware
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 22:21:03

ARINC 704惯导接口解析:从ARINC 429字格式到BNR数据解码实践

简介&#xff1a;ARINC 704-7于1999年发布&#xff0c;是面向航空电子工程领域的重要技术标准&#xff0c;专门规定惯性参考系统&#xff08;IRS&#xff09;的设计、性能指标、测试方法及安装要求&#xff0c;适合飞机制造商、航空公司、维修机构及航空电子工程师作为实现惯性…

作者头像 李华
网站建设 2026/9/19 22:20:42

低延迟跨设备交互链路:从投屏到实时操控的全栈实现

1. 项目概述&#xff1a;这不是“投屏”&#xff0c;而是构建一套低延迟、可交互的跨设备控制链路 你有没有过这样的场景&#xff1a;在电脑前写方案&#xff0c;突然手机弹出一条重要微信&#xff0c;得立刻点开看&#xff1b;或者正在调试一个App&#xff0c;需要一边在手机…

作者头像 李华
网站建设 2026/9/19 22:20:02

x64dbg从入门到实战:下载安装、插件配置与调试技巧全解析

1. 下载前的准备与版本选择1.1 为什么要选 x64dbg&#xff0c;而不是其他调试器很多刚接触逆向分析的朋友&#xff0c;一上来就会纠结&#xff1a;网上调试器一大堆&#xff0c;OllyDbg、WinDbg、x64dbg、IDA Pro&#xff0c;到底该用哪个&#xff1f;我的建议很直接&#xff1…

作者头像 李华
网站建设 2026/9/19 22:18:44

意义行为原生论:自感与先验意义场域的哲学解析

1. 意义行为原生论的理论框架解析意义行为原生论的核心在于将"自感"&#xff08;发生-觉知一体&#xff09;确立为源初实在&#xff0c;这一理论框架试图超越传统哲学中意识与存在、主体与客体、个体与社会的二元对立。在2026年的修订版中&#xff0c;作者岐金兰系统…

作者头像 李华
网站建设 2026/9/19 22:16:15

应急管理数据治理技术规范:从分类分级到质量校验的落地指南

简介&#xff1a;《应急管理数据治理技术规范》是一份PDF格式的规范性文档&#xff0c;面向应急管理行业的信息化规划人员、数据治理工程师、系统架构师以及相关项目评审人员&#xff0c;用于解决应急场景下数据接入不统一、治理流程不规范、数据服务与运维缺乏标准等核心问题。…

作者头像 李华
网站建设 2026/9/19 22:14:41

9款AI写论文哪个好?我花了两周实测,发现了三个反常识的真相

毕夏AI官网 www.bixiaai.com 毕夏AI写作官网 www.bixiaai.com 毕夏官网 www.bixiaai.com 毕夏智能写作官网 www.bixiaai.com 毕夏AI官网 www.bixiaai.com 微信公众号搜一搜“毕夏AI官网” 第一个真相&#xff1a;文献“编造”比“生成”更致命 我测的第一款工具是 Pris…

作者头像 李华