QMK机械键盘固件开发指南:从源码到实践
前言
QMK(Quantum Mechanical Keyboard)是一款开源的键盘固件,支持众多自定义键盘的功能配置。通过QMK,您可以完全掌控键盘的每一个按键,实现复杂的宏指令、多层按键映射、RGB灯效等高级功能。本教程将带您从零开始构建一个基础的QMK键盘固件,使您的键盘真正实现个性化定制。
一、QMK项目文件结构
在开始编写固件代码前,我们需要先了解QMK的文件结构。对于每一个键盘项目,我们需要在keyboards
文件夹下创建特定的文件和文件夹。
1.1 基本结构
keyboards/
└── your_keyboard_name/ # 键盘名称(全小写,无空格,无特殊符号)
├── rules.mk # MCU类型、Bootloader选择及功能开关配置
├── config.h # 硬件参数配置
├── info.json # USB VID/PID、制造商信息等
├── your_keyboard_name.h # 键盘矩阵定义
├── your_keyboard_name.c # 键盘核心功能实现
└── keymaps/ # 键盘映射文件夹
└── default/ # 默认键盘映射
└── keymap.c # 按键功能定义
1.2 文件命名规则
关于命名规则,有几点需要特别注意:
- 键盘名称文件夹必须全部小写,不能包含空格和特殊符号(下划线除外)
.h
和.c
文件的名称应与最深层文件夹名称一致- 例如:如果键盘文件夹结构为
keyboards/modelo75/costume/
,则对应的文件应命名为costume.h
和costume.c
,而非modelo75.h
1.3 ARM架构专用文件
对于使用ARM架构芯片(如STM32系列)的键盘,还需要两个额外的文件:
mcuconf.h
- MCU配置文件halconf.h
- HAL层配置文件
注意:这两个文件对于AVR架构(如ATmega32U4)的键盘不是必需的。
二、创建键盘固件项目
现在,让我们一步步创建一个完整的键盘固件项目。本教程以一个名为"Modelo75"的75%布局键盘为例。
2.1 创建项目文件夹
首先,在QMK固件的keyboards
目录下创建一个新文件夹:
# 进入QMK固件目录
cd qmk_firmware
# 创建键盘文件夹
mkdir keyboards/modelo75
2.2 编写 rules.mk 文件
rules.mk
是项目的核心配置文件,用于指定MCU类型、Bootloader以及各种功能开关。
# MCU名称
MCU = STM32F103
# 注释:芯片型号
# Bootloader选择
BOOTLOADER = stm32duino
# 注释:F103需要使用stm32duino bootloader,因为它原生不支持USB DFU
# 功能开关
NKRO_ENABLE = yes # 启用全键无冲
EXTRAKEY_ENABLE = yes # 启用音频控制和系统控制
# LTO_ENABLE = yes # 链接时优化,可减小固件体积(对于Flash空间小的MCU有用)
扩展知识:LTO(Link Time Optimization)是一种编译优化技术,可以在链接阶段对整个程序进行优化,减小固件体积并提高执行效率。对于Flash空间有限的AVR系列MCU(如ATmega32U4),启用LTO非常有用。
2.3 定义键盘矩阵 (modelo75.h)
键盘矩阵文件定义了键盘的物理布局,是固件开发中最重要的文件之一。这个文件将指导QMK如何理解您的键盘按键排列。
#pragma once
#include "quantum.h"
/* 这个宏防止头文件被重复包含 */
/* 定义键盘布局 */
#define LAYOUT( \
K000, K001, K002, K003, K004, K005, K006, K007, K008, K009, K010, K011, K012, K013, K014, \
K100, K101, K102, K103, K104, K105, K106, K107, K108, K109, K110, K111, K112, K113, K114, \
K200, K201, K202, K203, K204, K205, K206, K207, K208, K209, K210, K211, K212, K214, \
K300, K301, K302, K303, K304, K305, K306, K307, K308, K309, K310, K311, K313, K314, \
K400, K401, K402, K403, K404, K405, K406, K407, K408, K409, K410, K412, K413, K414, \
K500, K501, K502, K506, K510, K511, K512, K513, K514 \
) { \
{ K000, K001, K002, K003, K004, K005, K006, K007, K008, K009, K010, K011, K012, K013, K014 }, \
{ K100, K101, K102, K103, K104, K105, K106, K107, K108, K109, K110, K111, K112, K113, K114 }, \
{ K200, K201, K202, K203, K204, K205, K206, K207, K208, K209, K210, K211, K212, KC_NO, K214 }, \
{ K300, K301, K302, K303, K304, K305, K306, K307, K308, K309, K310, K311, KC_NO, K313, K314 }, \
{ K400, K401, K402, K403, K404, K405, K406, K407, K408, K409, K410, KC_NO, K412, K413, K414 }, \
{ K500, K501, K502, KC_NO, KC_NO, KC_NO, K506, KC_NO, KC_NO, KC_NO, K510, K511, K512, K513, K514 } \
}
技巧:使用Excel等电子表格工具可以快速生成键盘矩阵布局。您可以在Excel中创建一个与键盘行列对应的表格,填入键位标识符,然后复制到代码中进行格式调整。
2.4 创建键盘C文件 (modelo75.c)
对于基础功能,这个文件可以非常简单:
#include "modelo75.h"
/* 键盘特定功能的实现可以放在这里 */
/* 例如RGB矩阵效果、旋钮功能等 */
2.5 配置硬件参数 (config.h)
config.h
文件包含了键盘硬件相关的配置,如矩阵尺寸、引脚定义等:
#pragma once
#include "config_common.h"
/* 键盘矩阵尺寸 */
#define MATRIX_ROWS 6
#define MATRIX_COLS 15
/* 键盘矩阵引脚定义 */
#define MATRIX_ROW_PINS { B5, B4, B3, A15, A2, A1 }
#define MATRIX_COL_PINS { A0, A3, A4, A5, A6, A7, B0, B1, B10, B11, B12, B13, B14, B15, B9 }
/* 二极管方向 */
#define DIODE_DIRECTION COL2ROW
2.6 创建USB和设备信息 (info.json)
在QMK 0.19版本后,需要在info.json
文件中定义USB相关信息:
{
"keyboard_name": "Modelo75",
"manufacturer": "YourName",
"url": "",
"maintainer": "YourName",
"usb": {
"vid": "0xF055",
"pid": "0x7501",
"device_version": "0.0.1"
}
}
注意:VID(厂商ID)和PID(产品ID)应该是唯一的。对于个人项目,可以使用随机的16进制数值,但要避免与商业产品冲突。
2.7 ARM架构特定文件
如果使用STM32等ARM架构芯片,还需要添加以下两个文件:
mcuconf.h:
#pragma once
#include_next <mcuconf.h>
halconf.h:
#pragma once
#include_next <halconf.h>
2.8 创建默认按键映射
现在创建键盘映射目录和默认映射文件:
mkdir -p keyboards/modelo75/keymaps/default
touch keyboards/modelo75/keymaps/default/keymap.c
编辑keymap.c
文件,定义键盘的默认按键功能:
#include QMK_KEYBOARD_H
/* 层定义 */
enum layer_names {
_BASE, // 基础层
_FN // 功能层
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* 基础层 (0) */
[_BASE] = LAYOUT(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_DEL,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_HOME,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGDN,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_END,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, MO(_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
/* 功能层 (1) */
[_FN] = LAYOUT(
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
RGB_TOG, RGB_MOD, RGB_HUI, RGB_SAI, RGB_VAI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, RGB_RMOD,RGB_HUD, RGB_SAD, RGB_VAD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, QK_BOOT, KC_TRNS, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
)
};
三、层与键码详解
QMK的强大功能之一是支持多层按键映射,借助层切换功能,您可以在有限的物理按键上实现几乎无限的功能。
3.1 常用层切换键码
以下是QMK中用于层控制的常用键码:
键码 | 说明 |
---|---|
DF(n) | 将层n设为默认层 |
MO(n) | 按住时临时切换到层n,松开后返回 |
OSL(n) | 单击后下一个按键从层n生效,然后返回 |
LM(n,mod) | 类似MO(n),但同时应用指定的mod修饰符 |
LT(n,kc) | 按住时临时切换到层n,单击时发送KC键码 |
TG(n) | 切换层n的开启/关闭状态 |
TO(n) | 直接切换到层n |
TT(n) | 点按功能类似MO,多次点击保持层n开启 |
3.2 特殊键码举例
QMK提供了许多特殊键码,以下是一些常用的例子:
QK_BOOT
:进入Bootloader模式,可用于刷新固件RGB_TOG
:开关RGB灯效RGB_MOD
:切换RGB灯效模式KC_MUTE
:系统静音KC_VOLD
/KC_VOLU
:音量减/增
四、编译和烧录固件
完成所有文件的创建和编辑后,就可以编译并烧录固件了。
4.1 编译固件
使用以下命令编译固件:
qmk compile -kb modelo75 -km default
如果您有多级目录,需要指定完整路径:
qmk compile -kb your_folder/modelo75 -km default
4.2 烧录固件
编译成功后,固件文件会生成在.build
文件夹中。根据MCU类型,文件格式可能是.hex
、.bin
或.uf2
。
使用QMK Toolbox或命令行工具烧录固件:
qmk flash -kb modelo75 -km default
重要提示:烧录固件前,需要将键盘设置为Bootloader模式。这通常可以通过按下键盘上的RESET按钮,或在PCB上短接RESET和GND引脚实现。
五、扩展功能与进阶技巧
5.1 快速构建键盘矩阵的Excel技巧
创建键盘矩阵是固件开发中最繁琐的工作之一。使用Excel可以大大简化这一过程:
- 创建一个与键盘行列数相匹配的表格
- 按照行列顺序填入键位标识符(如K000, K001等)
- 在单元格间添加逗号分隔符
- 复制整个表格数据到代码编辑器
- 使用查找替换功能调整格式
5.2 代码优化与调试技巧
- 保持代码整洁:适当的缩进和注释可以使代码更易于阅读和维护
- 模块化设计:将复杂功能拆分为单独的函数,提高代码可维护性
- 使用条件编译:对于可选功能,使用条件编译可以减小固件体积
- 日志输出:在调试复杂问题时,可以使用
print
或dprintf
函数输出调试信息
5.3 常见问题解决方案
- 编译错误:检查括号、逗号是否正确,确保所有必需文件都已创建
- 按键不响应:检查键盘矩阵定义是否正确,二极管方向是否设置正确
- 层切换问题:确认层切换键的位置和功能是否正确配置
- 固件太大:尝试启用LTO,或禁用不需要的功能
- USB不识别:检查VID/PID配置,确保已正确设置USB参数
六、结语
通过本教程,您已经学习了如何从零开始创建QMK键盘固件。这只是QMK功能的冰山一角,随着您的深入学习,还可以探索更多高级功能,如RGB灯光效果、OLED显示、旋钮编码器控制等。
持续学习QMK文档和社区资源,将帮助您进一步掌握键盘固件开发技术,创造出完全符合个人需求的独特键盘体验。
如果您在开发过程中遇到任何问题,欢迎在评论区留言交流,也可以加入QMK官方Discord社区获取更多帮助。
参考资源: