QMK 固件移植实战:从 10bleoledhub 看蓝牙小键盘的完整实现与构建流程
本文以 QMK Firmware 仓库中 keyboards/10bleoledhub 键盘为例,系统讲解一款 10 键蓝牙 OLED 小键盘在 QMK 生态中的完整落地方式:从硬件矩阵与蓝牙驱动的配置、RGB 与编码器的启用,到自定义 OLED 字体与按键层(Layer)的实现,最终给出可直接复制的编译命令与可验证的源码依据。读完本文,你将掌握如何阅读并二次开发一个 QMK 键盘目录,理解 keyboard.json、config.h、rules.mk 与 keymap.c 各自的职责。
键盘概览:10bleoledhub 是什么
10bleoledhub(10 BLE OLED HUB)是一款由 haierwangwei2005 维护的迷你数字小键盘,核心卖点是 蓝牙(BLE)无线 + OLED 显示屏 + RGB 灯效 + 旋转编码器 的组合。它的主 README 位于 keyboards/10bleoledhub/readme.md,维护者信息、硬件来源均记录在该文件中。
在 QMK 仓库中,该键盘的完整支持代码位于 keyboards/10bleoledhub/ 目录,包含:
keyboard.json:键盘声明文件,集中描述硬件与功能开关;config.h:C 级编译配置(当前仅包含自定义 OLED 字体路径);rules.mk:Make 级规则(当前仅包含 CPU 主频);keymaps/default/keymap.c:默认键位映射与 OLED/编码器用户逻辑;lib/glcdfont.c:自定义 OLED 字库(5x7 ASCII 字体)。
从 keyboard.json 可以读出该键盘的硬件画像:
| 配置项 | 值 | 含义 |
|---|---|---|
processor |
atmega32u4 |
主控为 Atmel ATmega32U4(AVR 架构) |
bootloader |
caterina |
使用 Arduino Leonardo 风格的 Caterina 引导程序 |
usb.vid / usb.pid |
0x7C88 / 0x7C99 |
USB 设备标识,device_version 为 0.0.1 |
bluetooth.driver |
bluefruit_le |
蓝牙方案采用 Adafruit Bluefruit LE SPI 模块 |
matrix_pins |
cols: D6 D7 B5,rows: F0 F5 F4 F6 |
4 行 3 列矩阵 |
diode_direction |
ROW2COL |
二极管方向为行到列 |
encoder.rotary |
pin_a C7,pin_b F7 |
一个旋转编码器 |
rgblight.led_count |
4 | 4 颗 RGB LED |
ws2812.pin |
B7 |
WS2812 灯带接在 B7 |
features |
bluetooth / bootmagic / encoder / extrakey / mousekey / oled | 启用蓝牙、Bootmagic、编码器、额外键、鼠标键与 OLED |
值得注意的一点:keyboard.json 的 features.nkro 为 false,即默认不使用 N 键无冲,这与小键盘同时启用鼠标键、额外键的场景相符。
构建环境与编译命令
原 README 给出的构建命令为:
make 10bleoledhub:default
这条命令的含义是:为目标键盘 10bleoledhub 编译 default 键位映射。执行前需要先完成 QMK 构建环境的搭建(安装工具链、克隆本仓库并运行 qmk setup),随后在仓库根目录执行上述命令即可。
除传统 make 之外,现代 QMK CLI 同样支持编译该键盘:
qmk compile -kb 10bleoledhub -km default
编译产物的烧录方式取决于 bootloader 字段:由于 keyboard.json 声明为 caterina,在 Linux/macOS 下可使用 make 10bleoledhub:default:flash 或 qmk flash -kb 10bleoledhub -km default 进入 Caterina 引导流程进行烧录。需要注意的是,该键盘基于蓝牙方案,实际使用时主控可能通过 USB 连接进行刷写与调试,而键位输入则通过 BLE 无线链路传输。
深入 keyboard.json:硬件如何被 QMK 识别
keyboard.json 是 QMK 数据驱动配置(Data-Driven Configuration)的核心,构建系统会将其转换为 C 头文件参与编译。下面逐段解读 keyboard.json。
基础元信息
{
"keyboard_name": "10bleoledhub",
"manufacturer": "haierwangwei2005",
"url": "https://github.com/haierwangwei2005/10BLE-OLED-HUB",
"maintainer": "haierwangwei2005",
"usb": {
"vid": "0x7C88",
"pid": "0x7C99",
"device_version": "0.0.1"
}
}
keyboard_name 会显示在 QMK_KEYBOARD_H 等宏生成的键盘标识中;usb 段的 VID/PID 用于 USB 枚举,多键盘同时接入时依赖该组合区分设备。
功能开关与蓝牙驱动
"features": {
"bluetooth": true,
"bootmagic": true,
"encoder": true,
"extrakey": true,
"mousekey": true,
"nkro": false,
"oled": true
},
"bluetooth": {
"driver": "bluefruit_le"
}
features 中的每个布尔值都会映射为对应的编译宏(如 BLUETOOTH_ENABLE、OLED_ENABLE),从而决定 quantum/ 与 drivers/ 中的哪些模块被链接进固件。bluetooth.driver 指定为 bluefruit_le,对应仓库内的 drivers/bluetooth/bluefruit_le.cpp 与 drivers/bluetooth/bluefruit_le.h 驱动实现(由 drivers/bluetooth/bluetooth_drivers.c 统一调度)。Bluefruit LE 方案通过 SPI 与 Adafruit nRF51822 模块通信,将键盘的 HID 报文转发到主机。
矩阵与按键布局
"matrix_pins": {
"cols": ["D6", "D7", "B5"],
"rows": ["F0", "F5", "F4", "F6"]
},
"diode_direction": "ROW2COL",
"layouts": {
"LAYOUT": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0, "w": 0.8, "h": 0.8},
{"matrix": [1, 0], "x": 0, "y": 1},
{"matrix": [1, 1], "x": 1, "y": 1},
{"matrix": [1, 2], "x": 2, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2},
{"matrix": [2, 1], "x": 1, "y": 2},
{"matrix": [2, 2], "x": 2, "y": 2},
{"matrix": [3, 0], "x": 0, "y": 3},
{"matrix": [3, 1], "x": 1, "y": 3},
{"matrix": [3, 2], "x": 2, "y": 3}
]
}
}
矩阵为 4 行 3 列,其中 12 个矩阵位中实际使用了 10 个:[0,0] 单独位于顶部(对应默认键位图中的 PGUP 键),下方是 [1,0] 到 [3,2] 组成的 3x3 数字区。x/y/w/h 字段描述了每个键在可视化布局中的位置与尺寸,供 QMK Configurator 等工具渲染使用;而真正的按键功能则由 keymap.c 中的 LAYOUT() 宏按顺序填充。
RGB 灯效与编码器
"rgblight": {
"led_count": 4,
"animations": {
"breathing": true,
"rainbow_mood": true,
"rainbow_swirl": true,
"snake": true,
"knight": true,
"christmas": true,
"static_gradient": true,
"rgb_test": true,
"alternating": true,
"twinkle": true
}
},
"ws2812": {
"pin": "B7"
},
"encoder": {
"rotary": [
{"pin_a": "C7", "pin_b": "F7"}
]
}
rgblight 段声明了 4 颗 WS2812 灯珠并一次性开启了 10 种动画效果;ws2812.pin 指定数据引脚。encoder.rotary 声明一个旋转编码器,引脚为 C7/F7——对应默认键位中旋转可翻页(PGUP/PGDN)的实现。
config.h 与 rules.mk:两类底层配置
除 keyboard.json 外,该键盘还保留了传统配置文件,说明其移植方式为“数据驱动为主、传统配置为辅”的混合模式。
config.h:自定义 OLED 字库
config.h 全文只有一个有效宏:
#define OLED_FONT_H "./lib/glcdfont.c"
该宏将 OLED 渲染所用的字体数据指向键盘目录下的 lib/glcdfont.c。该文件定义了一个 5x7 的标准 ASCII 字库 font[] PROGMEM,共 241 行字节数据,存放于 Flash(PROGMEM)中。由于 QMK 的 OLED 渲染引擎默认提供内置字体,这里通过自定义字体文件,可以让屏幕显示更贴合该键盘风格的字符集——默认键位图中的 QMK Logo 渲染正是依赖这组字库中的特殊字形(见下文 keymap 解析)。
rules.mk:CPU 主频
rules.mk 设置了:
F_CPU = 8000000
即主控以 8 MHz 运行。对于 ATmega32U4 而言,8 MHz 通常是配合 3.3V 供电与 Bluefruit LE 模块低功耗场景的典型配置(5V 下常见 16 MHz),也说明该键盘的无线化设计对功耗与电压有明确取舍。
keymap.c 全解析:键层、OLED 与编码器
默认键位实现位于 keymaps/default/keymap.c,它同时演示了 QMK 的三个经典扩展点:多层键位、OLED 渲染钩子、编码器回调。
双层键位设计
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT(
KC_PGUP,
KC_KP_7, KC_KP_8, MO(1),
KC_P4, KC_P5, KC_P6,
KC_P1, KC_P2, KC_P3),
[1] = LAYOUT(
KC_NUM,
UG_TOGG, UG_NEXT, RGB_M_K,
UG_SATU, UG_SATD, UG_HUEU,
UG_VALU, UG_VALD, UG_SPDU),
};
- 第 0 层(默认层):顶部单键为
KC_PGUP;下方 3x3 区域是数字键盘KC_KP_7..KC_KP_3,其中[1,2]位置放置MO(1)——按住它即可临时切换到第 1 层。 - 第 1 层(功能层):顶部为
KC_NUM(NumLock);3x3 区域全部用于 RGB 控制,包括灯效开关UG_TOGG、灯效切换UG_NEXT、模式键RGB_M_K,以及饱和度增减UG_SATU/UG_SATD、色调增减UG_HUEU、亮度增减UG_VALU/UG_VALD、速度调整UG_SPDU。
这种“数字键 + 长按功能层控制灯效”的布局,是紧凑型小键盘的典型设计:日常输入数字,需要调光时按住 MO(1) 即可盲操作。
OLED:渲染 QMK Logo
static void render_logo(void) {
static const char PROGMEM qmk_logo[] = {0x80, 0x81, ..., 0xd4, 0};
oled_write_P(qmk_logo, false);
}
#ifdef OLED_ENABLE
bool oled_task_user(void) {
render_logo();
return false;
}
#endif
void matrix_init_user(void) { render_logo(); }
oled_task_user() 是 QMK 的 OLED 渲染回调,会在主循环中周期性被调用;这里用 oled_write_P() 从 Flash 写入一段字节序列。这些字节(0x80–0xd4)并非 ASCII 字符,而是指向 lib/glcdfont.c 中自定义字库的特殊字形索引,从而在屏幕上拼出 QMK Logo 图案。matrix_init_user() 中再次调用 render_logo() 则保证开机初始化时立即完成首帧渲染。
旋转编码器
bool encoder_update_user(uint8_t index, bool clockwise) {
if (index == 0) {
if (clockwise) {
tap_code(KC_PGDN);
} else {
tap_code(KC_PGUP);
}
}
return true;
}
encoder_update_user() 是编码器事件的用户回调:旋转一格即发送一次翻页键。由于 keyboard.json 中只声明了一个编码器,回调中通过 index == 0 判断即可;tap_code() 负责把键码转换为 HID 报文发送(蓝牙模式下经由 Bluefruit LE 驱动发出)。
从源码确认的引用链与可验证依据
为便于读者在仓库中继续深挖,本文涉及的关键文件汇总如下:
| 关注点 | 仓库路径 |
|---|---|
| 键盘 README | keyboards/10bleoledhub/readme.md |
| 硬件声明 | keyboards/10bleoledhub/keyboard.json |
| OLED 字体宏 | keyboards/10bleoledhub/config.h |
| 自定义字库 | keyboards/10bleoledhub/lib/glcdfont.c |
| CPU 主频 | keyboards/10bleoledhub/rules.mk |
| 默认键位与回调 | keyboards/10bleoledhub/keymaps/default/keymap.c |
| Bluefruit LE 驱动 | drivers/bluetooth/bluefruit_le.cpp、drivers/bluetooth/bluefruit_le.h |
OLED 渲染 API(oled_write_P 等) |
quantum/ 目录下的 OLED 驱动与量子功能模块 |
二次开发建议
如果你想基于该键盘做自己的固件:
- 改键位:复制
keymaps/default为keymaps/mine,在 keymap.c 中调整各键位与层定义,然后make 10bleoledhub:mine编译。 - 改灯效:编辑 keyboard.json 的
rgblight.animations开关,或直接用第 1 层键位在运行时切换。 - 改 OLED 内容:在
oled_task_user()中替换render_logo(),使用oled_write_*系列 API 绘制文本与图形;如需特殊字形,可参考 lib/glcdfont.c 的字体数据格式自行扩充。 - 改编码器功能:在
encoder_update_user()中把tap_code(KC_PGUP/PGDN)换成音量、媒体控制或其他组合键逻辑。
需要提醒的是:该键盘的蓝牙链路依赖 bluefruit_le 驱动,若更换蓝牙模块,需同步修改 keyboard.json 中的 bluetooth.driver 字段,并确认对应驱动存在于 drivers/bluetooth/ 目录中。
小结
10bleoledhub 虽然只有 10 个按键,却是 QMK 数据驱动配置、蓝牙无线化、OLED 自定义字体、RGB 动画与旋转编码器五类特性的浓缩范例。通过本文的拆解,你可以掌握从 keyboard.json 声明硬件、到 keymap.c 实现交互逻辑、再到 make 10bleoledhub:default 一键编译的完整链路——这套方法论同样适用于仓库中任何其他键盘的阅读与移植。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python670
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#230
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52874
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351