news 2026/9/19 20:01:22

QMK Firmware 实战:Palm Pilot 时代 Stowaway 串行键盘转 USB 协议转换器深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QMK Firmware 实战:Palm Pilot 时代 Stowaway 串行键盘转 USB 协议转换器深度解析
  • 嵌入式
  • 固件
  • 驱动开发
  • 硬件开发

【免费下载链接】qmk_firmware

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

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

导读

本篇文章聚焦 QMK Firmware 仓库中的keyboards/converter/palm_usb/stowaway转换器项目,它专门解决 Palm Pilot 时代 Think Outside Stowaway 串行键盘与现代 USB 主机之间的协议桥接问题。读完本文,你将掌握:如何用一块 Arduino Pro Micro(ATMega32u4)把 Stowaway 键盘接到电脑上、不同版本键盘(Palm / Handspring / Journada / iPaq)的接线与协议差异、负逻辑 9600 波特串行协议的底层实现(软串行、复位握手、矩阵状态机),以及如何通过配置头文件适配不同硬件。

项目定位:把"上古"串行键盘搬进现代 USB 世界

Stowaway 是 Think Outside 公司为 Palm Pilot 时代掌上设备设计的折叠式串行键盘,采用红外与串行两种接口,其中串行型号通过 9~12 芯排线连接 PDA。在 QMK 中,这类"旧外设转 USB"的设备被归入 converter 目录,与 ADB、Sun、XT 等经典键盘转换器并列,而 palm_usb/stowaway 正是其中专门面向 Stowaway 串行键盘的一员。

该转换器大量复用了 cy384 的 Arduino USB HID 适配方案(ppk_usb),由 milestogo 移植到 QMK。从实现上看,它没有沿用"行列扫描 + 键盘矩阵"的传统模式,而是以 自定义矩阵(CUSTOM_MATRIX) 的方式接管了矩阵层:串口收到键盘发来的按键编码后,被解析为 12 行 × 8 列的虚拟矩阵,再交给 QMK 键值处理管线。这意味着你拥有 QMK 全部的键位编排、层切换、宏等能力,只是"扫描"的对象从物理引脚变成了串行字节流。

构建与刷写:一条命令编译固件

在搭建好 QMK 构建环境后,编译本转换器固件只需要一条命令:

make converter/palm_usb/stowaway:default

关于环境搭建与 make 的详细说明,可参考仓库内的 make 指南 与 新手指南。

固件的目标信息可以从 keyboard.json 中直接读出:

  • 主控atmega32u4(即 Arduino Pro Micro / Teensy 2.0 常用的 USB 型 AVR,天然自带 USB 引擎,无需额外转接芯片);
  • 引导加载程序caterina(Pro Micro 的 Arduino Leonardo 风格引导);
  • USB 标识:VID0xFEED、PID0x0001、设备版本1.0.0
  • 功能开关:默认关闭 bootmagic、mousekey、extrakey,开启 console 与 command——前者便于通过串口调试输出观察协议交互,后者允许用键组合触发 QMK 命令模式。

需要说明的是,readme 指出目标主控虽是 ATMega32u4,但"其他具备 USB 能力的 AVR 也应当可用",因为核心逻辑只依赖 UART 与 GPIO。若你手头是其他 USB AVR,只需按 config.h 中的引脚注释调整引脚即可(见下文)。

硬件接线:Pro Micro 与 Stowaway 的一一对应

cy384 的原版方案有非常特殊的引脚分配,其 Arduino 软串行库使用的引脚与 QMK 不同,直接照搬会"破坏"QMK 的引脚约定,因此本移植版专门为 Pro Micro 重新规划了接线。readme 给出的接线表如下:

LabelTX0RX1GNDGND234567
Palm*GNDVCCRXNCRTSNCDCD
MCUD1D0C6E6

对应到 config.h 中的宏,即为:

#define VCC_PIN D1 // Pro Micro 的 2 号引脚,给键盘供电 #define RX_PIN D0 // Pro Micro 的 3 号引脚,接收键盘串行数据(原 cy384 方案用 8 号) #define RTS_PIN C6 // Pro Micro 的 5 号引脚(原方案用 D4/4 号),用于复位握手 #define DCD_PIN E6 // Pro Micro 的 7 号引脚,读取键盘的 DCD 电平

接线要点:

  • VCC(电源):由 MCU 输出驱动键盘供电;matrix_init()中上电后会将 VCC 拉高,模拟键盘被主机上电。
  • RX(数据):键盘的 RXD 是"输出到 MCU 的 RX"方向,接 D0。这是软件串行口,具体实现见后文。
  • RTS(请求发送):在复位流程中,MCU 会先读取该引脚电平,再将其切换为输出并"抖动"(toggle)以通知键盘"主机已重启"。这就是rts_reset()函数做的事。
  • DCD(载波检测):键盘上电后会主动拉高 DCD(最多 3 次)表示就绪,MCU 在matrix_init()中会阻塞等待 DCD 变高才开始握手。
  • 下拉电阻:键盘的 RX 线必须通过一个约10KΩ的电阻下拉到地,防止无数据时的浮空电平导致误码:
RX --|--3 10K | GND

readme 特别注明:目前只有 Palm 3 型号的接线经过实测验证,其余型号的连线与插座参考 cy384 的 ppk_usb 项目文档及其提供的 3D 打印插座模型。

键盘版本与分组:至少 5 种硬件变体

Stowaway 折叠键盘在市面上至少有 5 个版本,readme 将它们归为三组,各自协议与接脚不同:

  • Group 1:Palm 3、Palm 5、HP Journada 540、Compaq iPaq 键盘。这些型号共享同一套 RTS 握手协议,但每种设备的排线定义不同。
  • Group 2:Handspring 键盘。不使用 RTS/DCD 握手协议,直接使用 TTL 电平信号;需要在 config.h 中把HANDSPRING置为 1 来切换。
  • Group 3:IRDA(红外)型号。未经测试,但理论上同样走串行。

readme 按"键盘处于打字位时从左到右"的视角给出了各型号排线顺序:

型号引脚顺序
Palm3[NC, VCC, RXD, RTS, NC, NC, DCD, NC, NC, GND]
Palm5[NC, VCC, RXD, RTS, NC, NC, DCD, NC, NC, GND](顺序相同,连接器不同)
Handspring[VCC/TXD, NC, NC, NC, GND, NC, NC, RXD]
Journada[NC, NC, NC, GND, NC, RTS, NC, DTR/VCC, RXD, DCD, NC] + [GND-IN, VCC-IN]
Ipaq[NC, NC, DTR/VCC, NC, NC, RTS, NC, RXD, DCD, GND, NC, NC]

可以看到,Palm 3 与 Palm 5 电学定义一致(仅物理连接器不同),而 Journada/iPaq 的排线更长、电源信号(DTR/VCC、VCC-IN)位置各不相同,接错会造成损坏风险,务必按上表核对。

串行协议:负逻辑、9600 波特、无流控

readme 中给出了协议的核心参数,这是整个转换器的"翻译字典":

信号:异步、负逻辑(Negative logic)、9600 波特率、无流控 帧格式:1 起始位 + 8 数据位 + 无校验 + 1 停止位(即 8N1)

这里最关键的一点是负逻辑:Stowaway 键盘的空闲电平是低电平、数据位用高电平表示,而 AVR 的 USART 硬件引擎期望的是正逻辑(空闲高电平)。如果要用 AVR 硬件 UART,就必须在 RX/TX 引脚前外接反相器。本转换器选择了纯软件串行方案,因此完全不需要反相器电路,这也是它取名为"软串行"的原因。

从键盘到系统的命令

  • 系统 → 键盘:无任何命令(转换器单向接收)。
  • 键盘 → 系统
    • 0xFA:复位/就绪响应(Reset/Ready Response),随后紧跟0xFD

结合 matrix.c 的源码可以看到更完整的字节流语义:

  • palm_handshake()会连续监听最多 5 个数据包,期望收到序列FF FA FD0xFF之后0xFA表示复位就绪,紧随其后的0xFD确认握手完成;
  • matrix_scan()中,若运行期再次收到0xFA0xFD,会被当作"意外的复位字节"处理,直接丢弃并返回(源码注释为rstA/rstD);
  • Handspring 变体走另一条握手:handspring_handshake()期望0xF9后跟0xFB,且按协议应在键盘上电约 15ms 后发送。

按键编码:一位一位"抠"出矩阵坐标

转换器把串行字节直接映射为虚拟矩阵坐标,matrix.c 中用三组位掩码完成解码:

#define KEY_MASK 0b10000000 // bit7:按下(0)/抬起(1) 标志 #define COL_MASK 0b00000111 // bit0-2:列号(0~7) #define ROW_MASK 0b01111000 // bit3-6:行号(0~11) #define ROW(code) (( code & ROW_MASK ) >> 3) #define COL(code) ((code & COL_MASK)) #define KEYUP(code) ((code & KEY_MASK) >> 7)

即一个字节被拆解为:最高位表示键位状态(1 为抬起),bit3~6 为行号(配合MATRIX_ROWS 12),bit0~2 为列号(配合MATRIX_COLS 8)。matrix_scan()据此更新 12 字节的行位图matrix[MATRIX_ROWS],QMK 的键位处理层便能像对待普通矩阵一样读取状态。这也解释了为什么 keyboard.json 里的LAYOUT布局矩阵坐标范围是[0..11] × [0..7]

软件实现:matrix.c 里的完整状态机

CUSTOM_MATRIX = yes意味着矩阵扫描由 matrix.c 全权接管(见 rules.mk,同时以SRC += matrix.c加入编译、UART_DRIVER_REQUIRED = yes拉入 UART 驱动)。整体流程可分为初始化、复位握手、周期扫描三个阶段。

初始化与复位握手

matrix_init()的流程:

  1. 开启调试输出(debug_enable = true);
  2. 调用uart_init(9600)初始化软件串行;
  3. 非 Handspring 模式下调pins_init():VCC 输出、DCD/RTS 设为输入(读键盘状态);
  4. 拉高VCC_PIN给键盘上电;
  5. 按版本分支执行握手:
    • Handspring:直接尝试handspring_handshake()(上电后约 15ms 内应收到0xF9 0xFB);
    • Palm 系while(!gpio_read_pin(DCD_PIN))阻塞等待键盘的 DCD 电平跳变(键盘会主动发出最多 3 次),随后调用rts_reset()抖动 RTS 让键盘认为"主机已重启",最后palm_handshake()验证0xFA 0xFD
  6. 清空 12 行矩阵位图,调用matrix_init_kb()交给用户层。

rts_reset()的实现细节值得一提:上电后 RTS 保持输入态,通过gpio_read_pin读取当前电平,再切换为输出:若读到高电平则先拉低,等待 10ms 后拉高,再等 5ms——这就是 readme 所说"频繁重启键盘"式的电源/复位管理(目前尚未实现真正的低功耗管理)。

周期扫描与睡眠恢复

matrix_scan()是每次扫描周期的主入口:

  • uart_read()读取一个字节;若无数据(返回 0)且距上次活动超过SLEEP_TIMEOUT(500000ms,见 config.h),则触发palm_reset()handspring_reset()重新完成复位握手;
  • 只要有数据到达,就更新last_activity并把disconnect_counter清零;
  • 丢弃意外的0xFA/0xFD复位字节;
  • 根据KEYUP(code)判断按下/抬起:按下则置位对应(row, col),抬起则清除;若连续收到相同的抬起码,则视为"全部按键已松开",清空状态并返回(readme 提到的手册要求——此时应释放所有遗留修饰键,但源码注释指出这可能干扰粘滞键功能,故当前实现是丢弃该字节)。

底层 UART 驱动

软件串行的载体是 QMK 平台的 UART 驱动。以 AVR 为例,platforms/avr/drivers/uart.c 提供了uart_init(baud)uart_read()等接口:uart_init(F_CPU / 4 / baud - 1) / 2配置波特率寄存器并开启收发中断;uart_read()在接收缓冲(RX_BUFFER_SIZE为 64 字节)为空时阻塞等待字符,这正是matrix_scan()中"无数据时 UART 驱动会让出执行"的行为基础。CHIBIOS 平台则有等价的 uart_serial.c / uart_sio.c 实现,体现了 QMK 跨平台抽象的能力。

配置项速查:如何适配你的键盘

所有关键配置集中在 config.h:

默认值说明
VCC_PIND1键盘供电引脚(Pro Micro 2 号)
RX_PIND0软串行接收引脚(3 号)
RTS_PINC6RTS 复位握手引脚(5 号)
DCD_PINE6DCD 电平检测引脚(7 号)
CY384未定义若沿用 cy384 的 Arduino 引脚布局则定义之,会启用GND_PIN D7PULLDOWN_PIN B1的 GND/下拉引脚输出
HANDSPRING0置 1 表示 Handspring 键盘,禁用 RTS/DCD 握手并切换为0xF9/0xFB握手
MAXDROP10计划用于"每 X 次扫描检查键盘是否断开"的阈值(当前扫描逻辑中该计数分支被注释掉)
SLEEP_TIMEOUT500000无数据超过该毫秒数即触发复位握手(睡眠恢复)
MATRIX_ROWS12虚拟矩阵行数
MATRIX_COLS8虚拟矩阵列数

另外,IS_COMMAND()被定义为"同时按下左右 Alt 或左右 Win/Command 或左右 Shift"触发 QMK 命令模式,与 console/command 功能配合使用。

默认键位:三层布局开箱即用

keymaps/default/keymap.c 提供了完整可用的三层键位:

  • _QWERTY(默认层):标准全键盘布局,空格键位被拆分为两个 Space,TG(_CDH)用于切换到 Colemak-DH 层;
  • _CDH(Colemak-DH 层):字母区重排为 Colemak-DH 指法,其余键位继承默认层;
  • _FN(功能层):由MO(_FN)临时按住触发,当前仅将 Enter 映射到空格位(KC_ENT),为快捷键预留了扩展空间。

由于矩阵是 12×8 的虚拟网格,keyboard.json 中的LAYOUT把每个键位映射到对应的[row, col],并定义了物理坐标(含 2.25u 空格、导航键簇等),QMK 的 info.json 数据驱动能力使得布局可视化与配置生成都能直接工作。

已知限制与后续路线

readme 与源码共同指出了当前实现的边界与 TODO,读者在自行移植或调试时值得留意:

  1. 测试覆盖有限:目前仅 Palm 3 型号键盘经过实测,其余型号(Palm 5、Journada、iPaq、Handspring、IRDA)的接线与握手需要自行验证;
  2. 软串行待重构:TODO 中计划把软串行实现迁移到新版 Helix 风格的代码,以便更容易切换引脚(当前引脚宏集中在 config.h,已为重构留出接口);
  3. 断开检测未启用:源码注释了"键盘按住删除键后断开"的检测逻辑——按计划应每MAXDROP次扫描检查键盘是否还在,若不在则清空矩阵,但由于矩阵扫描远快于串行速率,该分支目前被注释,尚未实现;
  4. 电源管理缺失:readme 直言"Power management is not implemented yet",当前只是通过频繁复位握手让键盘保持唤醒。

结语

converter/palm_usb/stowaway是 QMK"万物皆矩阵"思想的典型例证:一段 9600 波特、负逻辑的串行协议,通过自定义矩阵与位运算解码,被无缝纳入 QMK 的键位处理管线,让 20 年前的折叠键盘在现代电脑上重新工作。无论你是想复刻这套转换器,还是研究如何为其他串行/非标准协议外设编写自定义矩阵驱动,readme、config.h 与 matrix.c 三件套都是极佳的参考模板。

  • 嵌入式
  • 固件
  • 驱动开发
  • 硬件开发

【免费下载链接】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 19:58:11

Java重构会展服务平台:状态机、并发控制与数据库优化实践

简介:基于Java的会展服务平台设计与实现文档,内容覆盖平台需求、设计目标、设计方案及实现技术,面向Java Web方向的高校毕业生或开发者。文档从会展服务管理实际场景出发,围绕管理员与用户两类角色展开,管理员侧涉及个…

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

BMAD Deep Recon 研究生命周期:Refresh 与 Deepen 机制实战指南

BMAD Deep Recon 研究生命周期:Refresh 与 Deepen 机制实战指南 【免费下载链接】BMAD-METHOD Breakthrough Method for Agile Ai Driven Development 项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHOD 导读 本指南围绕 BMAD-METHOD 项目中 bmad-d…

作者头像 李华
网站建设 2026/9/19 19:56:03

自考AI工具对比:千笔与灵感的场景化应用

1. 项目背景与需求解析作为一名长期关注教育科技领域的从业者,我注意到近年来自考学习群体对AI辅助工具的需求呈现爆发式增长。特别是在论文写作、作业辅导等场景中,AI生成内容(AIGC)工具的使用率持续攀升。但市面上的通用型AI工具…

作者头像 李华
网站建设 2026/9/19 19:51:06

DOE实验设计实战:用Minitab从全因子到响应面优化工艺参数

简介:这是一份面向品质管理及工程技术人员的中文PPT课件,系统讲解DOE(实验设计)基础知识,并结合Minitab软件演示完全要因实验的操作流程。内容涵盖实验计划法的定义与目的、因子/水准/处理/交互作用等核心术语、主要实…

作者头像 李华
网站建设 2026/9/19 19:50:40

电力系统备用优化:计及需求侧响应的两阶段鲁棒模型

1. 项目背景与核心价值电力系统备用容量优化是保障电网安全稳定运行的关键环节。传统备用优化通常仅考虑发电侧资源,而随着需求侧管理技术的发展,将需求侧响应(Demand Response, DR)纳入备用优化框架已成为行业共识。这个Matlab项…

作者头像 李华