首页
/ QMK 固件移植实战:从 10bleoledhub 看蓝牙小键盘的完整实现与构建流程

QMK 固件移植实战:从 10bleoledhub 看蓝牙小键盘的完整实现与构建流程

2026-09-14 23:54:14作者:霍妲思

本文以 QMK Firmware 仓库中 keyboards/10bleoledhub 键盘为例,系统讲解一款 10 键蓝牙 OLED 小键盘在 QMK 生态中的完整落地方式:从硬件矩阵与蓝牙驱动的配置、RGB 与编码器的启用,到自定义 OLED 字体与按键层(Layer)的实现,最终给出可直接复制的编译命令与可验证的源码依据。读完本文,你将掌握如何阅读并二次开发一个 QMK 键盘目录,理解 keyboard.jsonconfig.hrules.mkkeymap.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.jsonfeatures.nkrofalse,即默认不使用 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:flashqmk 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_ENABLEOLED_ENABLE),从而决定 quantum/drivers/ 中的哪些模块被链接进固件。bluetooth.driver 指定为 bluefruit_le,对应仓库内的 drivers/bluetooth/bluefruit_le.cppdrivers/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 写入一段字节序列。这些字节(0x800xd4)并非 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.cppdrivers/bluetooth/bluefruit_le.h
OLED 渲染 API(oled_write_P 等) quantum/ 目录下的 OLED 驱动与量子功能模块

二次开发建议

如果你想基于该键盘做自己的固件:

  1. 改键位:复制 keymaps/defaultkeymaps/mine,在 keymap.c 中调整各键位与层定义,然后 make 10bleoledhub:mine 编译。
  2. 改灯效:编辑 keyboard.jsonrgblight.animations 开关,或直接用第 1 层键位在运行时切换。
  3. 改 OLED 内容:在 oled_task_user() 中替换 render_logo(),使用 oled_write_* 系列 API 绘制文本与图形;如需特殊字形,可参考 lib/glcdfont.c 的字体数据格式自行扩充。
  4. 改编码器功能:在 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 一键编译的完整链路——这套方法论同样适用于仓库中任何其他键盘的阅读与移植。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.81 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
945
1.86 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
537
607
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.28 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.39 K
1.48 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
401
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
347