news 2026/9/17 11:14:44

QMK 中 3W6HS 分体键盘的构建、烧录与双 MCU 矩阵扫描机制详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QMK 中 3W6HS 分体键盘的构建、烧录与双 MCU 矩阵扫描机制详解

QMK 中 3W6HS 分体键盘的构建、烧录与双 MCU 矩阵扫描机制详解

【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware

3W6HS 是一款基于 RP2040、支持热插拔(hotswap)的低配列(low profile)分体(split)键盘,每侧 5 列 × 4 行共 36 键,由 weteor 的 3W6 改版而来,维护者为 beekeeb。本文以仓库中 3W6HS 键盘文档 为主体,结合 config.h、matrix.c、rules.mk 与默认键位 keymap.c,讲解该键盘在 QMK 固件中的完整构建与烧录流程、RP2040 bootloader 进入方法,以及左板原生 GPIO + 右板 TCA9555 I2C 扩展芯片的混合矩阵扫描实现。读完本文,你可以独立完成make beekeeb/3w6hs:default的编译烧录,并理解分体键盘中一侧通过 I2C 扩展 GPIO 的接线与扫描原理。

硬件规格与仓库布局

按 readme.md 的官方描述,3W6HS 的核心属性如下:

项目说明
主控RP2040(bootloader 为 RP2040 板载 USB-Bootloader)
形态低配列、分体、左右各 5×4 矩阵加底部拇指键,共 36 键
热插拔支持(hotswap)
维护者beekeeb(由 weteor 的 3W6 改版)

键盘目录下的关键文件分工明确:

  • keyboard.json:描述处理器(RP2040)、bootloader(rp2040)、USB 描述符(VID0xBEEB、PID0x0003)、启用bootmagicmousekeyextrakey特性,并定义布局LAYOUT_split_3x5_3的键位坐标;
  • config.h:定义矩阵尺寸 8 行 × 10 列及两侧引脚分配;
  • matrix.c:自定义矩阵扫描逻辑(I2C + TCA9555);
  • rules.mk:声明CUSTOM_MATRIX = lite、加入matrix.c并启用 I2C 驱动;
  • halconf.h / mcuconf.h:ChibiOS 层配置,启用HAL_USE_I2C并将 RP2040 的 I2C 外设锁定为 I2C0。

构建与烧录

文档给出的两条标准命令(在配置好 QMK 构建环境之后执行):

# 编译默认键位 make beekeeb/3w6hs:default # 编译并烧录 make beekeeb/3w6hs:default:flash

构建环境配置与 make 用法可参考仓库内的 构建工具入门、make 指南 与 新手指南。default指使用 keymaps/default/keymap.c 中预置的六层键位;若自行编写键位,将其置于keyboards/beekeeb/3w6hs/keymaps/<name>/keymap.c后执行make beekeeb/3w6hs:<name>即可。

编译时 rules.mk 的三个指令决定了固件形态:

CUSTOM_MATRIX = lite # 使用自定义 matrix_scan_custom() 而非通用扫描器 SRC += matrix.c # 加入键盘目录下的自定义矩阵实现 I2C_DRIVER_REQUIRED = yes # 强制启用 I2C 硬件驱动(右板 TCA9555 依赖)

其中CUSTOM_MATRIX = lite的含义是:QMK 不再使用内置的matrix.c通用扫描,而是调用本键盘提供的matrix_init_custom()matrix_scan_custom()(见后文)。I2C_DRIVER_REQUIRED = yes则保证即便键位层面没有显式依赖 I2C,I2C 外设驱动也一定会被编入固件——这对右半区扫描是硬性前提。

进入 RP2040 Bootloader

readme.md 给出的 bootloader 进入步骤:

  1. 将键盘从电脑上断开;
  2. 找到 BOOT 按键——位于键盘左侧面板的顶部;
  3. 按住 BOOT 键不放,重新将键盘连接回电脑。

此时 RP2040 会以板载 USB-Bootloader(mass storage)模式枚举,即可通过make beekeeb/3w6hs:default:flash或手动拷贝.uf2文件完成烧录。由于keyboard.json中 bootloader 字段为rp2040,QMK 构建系统会自动生成配套的.uf2固件(将固件镜像包装进 UF2 容器)。另外该键盘启用了bootmagic特性:若将 USB 连接至特定键位(默认是左板 Q 键所在的矩阵点,可编译时通过BOOTMAGIC_DIODE_DIRECTION调整),固件会在启动时直接进入 bootloader,方便快速重刷。

矩阵结构与引脚分配

从 config.h 可以确认整个键盘是一个逻辑上的 8×10 矩阵,物理上被拆成两半:

#define MATRIX_ROWS 8 #define MATRIX_COLS 10 #define MATRIX_ROWS_PER_SIDE (MATRIX_ROWS / 2) // 4 #define MATRIX_COLS_PER_SIDE (MATRIX_COLS / 2) // 5 #define MATRIX_ROW_PINS_L { GP7, GP8, GP9, GP10 } #define MATRIX_COL_PINS_L { GP11, GP12, GP13, GP14, GP15 } #define MATRIX_ROW_PINS_R { P10, P11, P12, P05 } #define MATRIX_COL_PINS_R { P06, P13, P14, P01, P00 } #define I2C_DRIVER I2CD0 #define I2C1_SDA_PIN GP0 #define I2C1_SCL_PIN GP1

左板 4 行 5 列全部由 RP2040 的 GPIO 直接驱动;右板的 4 行 5 列虽然也在config.h中声明了引脚宏(MATRIX_ROW_PINS_R/MATRIX_COL_PINS_R),但从 matrix.c 的实现看,右板实际是经由一颗TCA9555 I2C GPIO 扩展芯片扫描的:I2C 数据线挂在 RP2040 的GP0(SDA)与GP1(SCL),通过I2CD0(即 I2C0 外设)通信,这一选择由 mcuconf.h 中的RP_I2C_USE_I2C0 TRUE与 halconf.h 中的HAL_USE_I2C TRUE配合保证。这种"单 MCU + I2C 扩展"的接线方式正是该键盘分体方案中无需为右板再放一颗主控、又能保持热插拔与低配列结构的原因(右板行选择与列读取均通过 TCA9555 的寄存器完成)。

TCA9555 初始化与寄存器操作

matrix.c 顶部定义了 TCA9555 的 I2C 地址与关键寄存器:

// TCA9555 的地址引脚全部接地:0b0100000 << 1 => 0x20 #define I2C_ADDR (0b0100000 << 1) #define IODIRA 0x06 // I/O 方向寄存器 #define IODIRB 0x07 #define IREGP0 0x00 // GPIO 输入端口寄存器 #define IREGP1 0x01 #define OREGP0 0x02 // 输出端口寄存器(写操作) #define OREGP1 0x03

init_tca9555()的执行流程:

  1. 若 I2C 子系统尚未初始化,调用 QMK 通用驱动i2c_init()(引脚即config.h中的 GP0/GP1)并延时I2C_TIMEOUT等待上电稳定;
  2. 写方向寄存器IODIRA:Port A 全设为输入(读列线),Port B 低 4 位设为输出(驱动行选择)、高 4 位保持输入;
  3. i2c_write_register()的返回值存入全局tca9555_status,作为后续扫描的"右板健康"标志。

i2c_write_register()/i2c_read_register()声明于 drivers/i2c_master.h,是 QMK 提供的 I2C 寄存器读写抽象,屏蔽了底层时序细节。

矩阵扫描:左右并行与故障自愈

matrix_scan_custom()是每次扫描循环的核心,其行为有三个值得关注的点:

1. TCA9555 断连时的自动重试。若上一次 I2C 通信出错(tca9555_status非零),扫描函数会让 8 位计数器tca9555_reset_loop自增,利用其溢出回卷的特性,大约每 255 次扫描(源码注释:略高于每秒一次)重新执行一次init_tca9555()。这意味着右板热插拔或 I2C 总线短暂紊乱后,固件无需重启即可自动恢复,日志会通过dprint输出 "right side attached" / "right side not responding"。

2. 左右行同步选择。每轮循环对MATRIX_ROWS_PER_SIDE(4)对行同时做select_row(i)select_row(i + 4),再各调用一次store_matrix_row()读回左右两侧状态。左板行选择是本地 GPIO 拉低;右板行选择则是向 TCA9555 的OREGP1写一个"仅目标行位为 0、其余位为 1"的字节。源码注释还指出:由于选行本身要经过一次 I2C 写操作,耗时已远超传统 AVR 方案所需的 30 µs 列稳定延时,因此无需额外延时。

3. 右板列数据的位重排。read_cols()对行号>= MATRIX_ROWS_PER_SIDE的读取流程是:读 TCA9555 的IREGP0→ 按位取反(键按下时列线被拉低)→ 将 Port A 的物理引脚位重排为矩阵列序:

data |= (port0 & 0x01) << 4; data |= (port0 & 0x02) << 2; data |= (port0 & 0x04); data |= (port0 & 0x08) >> 2; data |= (port0 & 0x10) >> 4;

注释说明右板列线在 TCA9555 上并非按顺序映射(col 5 对应 GPIO04、col 6 对应 GPIO03 等,从高到低递减),因此需要这段位重排才能与keyboard.json中声明的[row, col]矩阵坐标一致。任一步 I2C 读取失败时该侧行返回 0(视为无键按下),且不再污染全局状态以外的逻辑。

左板路径则完全走 RP2040 原生 GPIO:init_cols()将 5 个列脚设为带内部上拉的输入(gpio_set_pin_input_high+gpio_write_pin_high),read_cols()中按键按下时列脚被行线拉低,pin_state ? 0 : (1 << col_index)将低电平映射为矩阵位 1,即keyboard.json"diode_direction": "COL2ROW"所描述的"列接输入、行驱动"极性。

默认键位:六层设计与 Tap-Mod

默认键位 定义了 6 个层,充分利用了 36 键的拇指键区:

enum layers { _ALPHA_QWERTY, _ALPHA_COLEMAK, _SYM, _NAV, _NUM, _CFG };
  • _ALPHA_QWERTY/_ALPHA_COLEMAK:两套字母层,拇指区六个键为LCTL_T(KC_ESC)LT(_NUM, KC_SPC)LT(_NAV, KC_TAB)LT(_SYM, KC_BSPC)KC_ENTLALT_T(KC_DEL)——同时使用 Tap-Mod(_T,轻敲/修饰二合一)与LT(按下时切层、松开还原)两类技巧;
  • _SYM:符号层,MO(_CFG)直达配置层;
  • _NAV:音量、媒体键与光标方向键(Colemak 层中 Colemak 用户习惯 Enter 在左、Esc 在右,故 Colemak 层拇指区将 Enter/Esc 对调);
  • _NUM:F1–F12 与数字小键盘(KC_P*系列);
  • _CFG:配置层,提供DF(_ALPHA_QWERTY)/DF(_ALPHA_COLEMAK)两个"默认层"按键——按下即持久切换默认字母布局,重刷前也保留在 EEPROM 中。

布局宏LAYOUT_split_3x5_3由 keyboard.json 自动生成:前 5 个参数为左板第一行(矩阵 [0][0..4]),随后 5 个为右板第一行([4][0..4]),中间行同理,最后 6 个参数为底部拇指区(矩阵 [3][2..4] 与 [7][0..2])。该坐标映射保证键位表中的键与物理位置一一对应,社区布局文件(community_layouts: ["split_3x5_3"])亦可复用同一宏。

小结

3W6HS 在 QMK 中的实现要点可以归纳为:RP2040 主控 + RP2040 bootloader(按住左板顶部 BOOT 键上电进入);make beekeeb/3w6hs:default[:flash]完成编译烧录;8×10 逻辑矩阵拆分为左板 4×5 原生 GPIO 扫描 + 右板 4×5 经 GP0/GP1 上的 I2C0 总线驱动 TCA9555 扫描;CUSTOM_MATRIX = lite将扫描权交给 matrix.c 中具备 I2C 故障自愈能力的自定义实现;默认键位则以 Tap-Mod/LT/MO/DF组合覆盖 QWERTY、Colemak、符号、导航、数字与配置六大层。这一实现是 QMK 分体键盘中"单 MCU + I2C 扩展"接线的典型参考案例。

【免费下载链接】qmk_firmwareOpen-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/17 11:10:33

Java Web实习系统:JSP+Servlet+MySQL实战搭建与论文转化

简介&#xff1a;本资源是一篇面向高校计算机专业本科生与实习指导教师的毕业设计类论文&#xff0c;聚焦基于JSP与MySQL技术构建的实习实训管理系统&#xff0c;解决传统线下管理效率低、信息分散、流程不透明等痛点。论文完整覆盖需求分析、系统设计、数据库建模、JSP页面开发…

作者头像 李华
网站建设 2026/9/17 11:09:14

MySQL 8.0关键字与保留字避坑指南:从报错到规范

先从一个上周刚处理过的工单说起。业务同学建了一张客户反馈表&#xff0c;字段直接命名为desc&#xff0c;用来存描述内容。建表的时候一切正常&#xff0c;一到应用联调就报错&#xff1a;ERROR 1064&#xff0c;看错误日志定位到一条select desc from feedback ...&#xff…

作者头像 李华
网站建设 2026/9/17 11:07:58

Mac/Windows 部署 OpenClaw,模型通道接到 TaoToken 行不行?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 11:06:16

青少年开源创新:AI与游戏开发的新力量

1. 青少年开源论坛&#xff1a;当00后开始改变世界第一次在COSCon青少年开源论坛现场&#xff0c;我完全被震撼了——台上演讲的是一群平均年龄不到16岁的孩子&#xff0c;他们展示的项目却让台下数百位资深开发者频频点头。有人用AI技术保护濒危方言&#xff0c;有人在Minecra…

作者头像 李华