Skip to content

[自製QMK鍵盤-番外] 0.18.3版QMK韌體教學

2022 QMK 韌體教學

發佈

⚠ 由於最新的 0.21.3 版本的 QMK 在使用上的差異滿大的,這篇是針對舊版 0.18.3 的 QMK 教學,僅作為參考保留。

新版的 QMK 教學

如果你因為某些原因需要使用舊版 QMK 的話,可以使用下面的方法來切換 QMK 版本(需要先安裝好 QMK MSYS 環境)。

  1. 打開 QMK MSYS
  2. 執行 qmk cd
  3. 執行 git fetch --all --tags --prune
  4. 執行 git checkout tags/0.18.3

上一篇文章中已經完成鍵盤的 Layout,這篇文章將會接續製作步驟的第 3 步——生成並編輯 QMK 韌體。

自動產生韌體

首先使用 Keyboard Firmware Builder 來自動生成基本的 QMK 韌體,這樣就不用全部從頭開始,工具會生成基本的韌體程式。

Keyboard Firmware Builder 已經有好一段時間沒更新了,它產生的韌體在較新的 QMK 版本下會有多處出錯(0.18.3),並且隨著 QMK 來到 0.21.3,此工具所產生的大多數檔案已經不適用了。

讀入鍵盤

到 Keyboard Layout Editor 並載入你編輯好的鍵盤,複製其 raw data 並貼到 Keyboard Firmware Builder 中間的文字框,按下深藍色的「Import」按鈕。

▲ 在 Keyboard Firmware Builder 貼上 KLE 的 Raw data
▲ 在 Keyboard Firmware Builder 貼上 KLE 的 Raw data

接線(Wiring)

在標籤頁「Wiring」裡,你看到的是鍵盤的接線圖。

一般來說,鍵盤的按鍵數都大於微控制器的 GPIO 接腳數,所以會使用鍵盤矩陣掃描(Keyboard Matrix Scanning)技術。如果不是很懂鍵盤矩陣掃描的話,最好先找一些資料瞭解一下,這裡就不贅述。

在這裡設定鍵盤的接線(或者說鍵盤掃描矩陣)。點選其中一個按鍵可以設定它的鍵盤掃描矩陣的行列,還有設定二極體的方向(一般都是 Column to Row)。

▲ 編輯接線
▲ 編輯接線
▲ 點選一個按鍵後可以編輯該鍵位於掃描矩陣的行列
▲ 點選一個按鍵後可以編輯該鍵位於掃描矩陣的行列

腳位(Pins)

在標籤頁「Pins」裡可以設定使用的微控制器型號及其腳位。

首先選擇你使用的微控制器,例如用 Pro Micro 那就是「ATmega32U4」。如果這裡沒有列出你所用的微控制器器的話,那就可以先選「ATmega32U4」,等之後再手動修改。

如果你沒有使用微控制器的經驗,或是不知道要選哪個腳位才行,只要你的鍵盤沒有要加什麼特別的功能(如螢幕、搖桿、可條亮度的LED 或分離式鍵盤)的話,使用任何腳位都可以。如果你的鍵盤有這些需要特殊硬體功能(UART、SPI、I²C、PWM)的話,記得保留,不要被矩陣掃描佔用了。

當然,如果是使用現成的開發板(像是 Pro Micro)的話,記得要選有引出的接腳(開發板可能不會把微控制器的所有接腳都拉出)。

▲ 「Pins」標籤頁示意
▲ 「Pins」標籤頁示意

要注意的是,這裡顯示的接腳名稱是該微控制器原始的接腳名稱,可能會和開發板上的腳位號碼不同。

例如 Pro Micro 開發板上的 D16 其實是 ATmega32U4 的 PB2,而在「Pings」標籤頁顯示的是 B2 代表的是 PB2,設定前記得看好腳位對照圖。

以下圖為例,「Pins」頁面中的 D0 其實是指 PD0(藍紫色),它也被稱為 D3(綠色)。要注意你現在看到的腳位名稱到底是微控制器(藍紫色)的還是開發板(綠色)的,「Pins」頁面顯示的是微控制器的腳位名。

PB2、PD7…的 P 是指 Port,通常以 8 或 16 腳為一個 Port。 P 後面的英文字為 Port 名,通常由 A 開始。再來的數字是腳位編號,通常由 0 開始。 所以 PB2 就代表 Port-B 的 2 號腳,也就是 Port-B 的第 3 支接腳,因為 Port-B 的第一支腳是 PB0。

▲ Pro Micro 腳位對應圖(取自SparkFun)
▲ Pro Micro 腳位對應圖(取自SparkFun)

鍵映射(Keymap)

再來就是「Keymap」標籤頁,按鍵的功能(鍵映射)會在這裡進行設定。

點選一個按鍵後,可以在下方選擇該按鍵的功能(如ACtrlEnter…等)。

而 QMK 也可以設定「層(Layer)」在設定按鍵的上方有個數字就是顯示目前在設定的層,透過按上下來設定不同層的按鍵。

▲ 「Keymap」標籤頁
▲ 「Keymap」標籤頁

如果你在 Keyboard Layout Editor 有設定好各個按鍵的名稱的話,它會自動讀入按鍵的功能,如果沒有的話就需要在此手動編輯。

QMK 可以設定的按鍵請看說明文件:Keycodes Overview。但你可能會發現這裡可以設定的按鍵並不完全,很多在「Keycodes Overview」裡面有的按鍵這裡都沒有。如果有你想要的按鍵,但沒有出現在選單中的話,可以先隨便選其它的按鍵,等之後再手動修改。

如果要使用層的功能的話,可以參考說明文件:Keycodes Overview-Layer Switching

歸功於 Vial,QMK 鍵盤可以很方便地隨時編輯 Keymap,甚至連下載軟體都不用,所以在「Keymap」頁面你可以不用真的把它編輯成最終的樣子,可以先用個大概,等之後再用 Vial 修改。 但不建議完全空白,至少預設的第 0 層的每個鍵都要分配按鍵,方便未來測試。

▲ 其中一種切換層的按鍵設定
▲ 其中一種切換層的按鍵設定
▲ 不同層可以設定不同的按鍵功能更
▲ 不同層可以設定不同的按鍵功能更

巨集鍵(Macros)

在「Macros」標籤頁裡,你可以設定巨集鍵功能。巨集鍵也可以等之後再用 Vial 設計。

▲ 「Macros」標籤頁
▲ 「Macros」標籤頁

Quantum

在「Quantum」標籤頁裡,可以設定更詳細且複雜的功能。如果你不知道這是什麼的話,請不要編輯它,保持預設即可。

▲ 「Quantum」標籤頁
▲ 「Quantum」標籤頁

設定(Settings)

在標籤頁「Settings」裡可以編輯一些其它的設定。包含名稱、Bootloader 大小、WS2812 LED 燈數量、背光等級。

「Save Configuration」按鈕可以下載一個 JSON 檔,裡面儲存了目前為止的各種設定。在一開始的頁面裡,上方有個「Upload」按鈕,將此 JSON 檔傳上後就可以繼續編輯或修改該鍵盤。建議一定要儲存此 JSON 檔,且重新命名以避免與 Keyboard Layout Editor 的 JSON 搞混。

▲ 「Settings」標籤頁
▲ 「Settings」標籤頁

編譯(Compile)

最後一個標籤頁「Compile」可以透過「Download .hex」按鈕,讓它幫我們完成編譯的工作,並直接進行燒錄的步驟。

但如果你和我一樣是使用 Pro Micro 開發板的話,直接使用它編譯好的檔案可能會有問題,或是你想要修改更豐富的按鍵和其它功能的話,請按下「Download .zip」按鈕,來儲存 QMK 韌體的原始檔,準備對其手動修改與編譯。

▲ 「Compile」標籤頁
▲ 「Compile」標籤頁

手動編輯韌體

接下來的步驟會需要編寫程式碼,請確保你的電腦裝有一個好用的文字編輯軟體(記事本?不太建議)。我自己是使用 Visual Studio Code,或是你可以參考 QMK 的建議

將 Keyboard Firmware Builder 「Compile」標籤頁下載的 .zip 檔解壓縮。

修改 rules.mk

在解壓縮資料夾 \qmk_firmware\keyboards\kb\ 底下,找到檔案 rules.mk,使用你的文字編輯軟體打開它。

kb\ 資料夾就是這把鍵盤的根目錄,資料夾名稱就是此鍵盤在編譯時的名稱。如果想修改名稱的話,資料夾內的 kb.hkb.ckeymaps\default\keymap.c#include "kb.h" 的名稱都要統一改掉。詳細的 QMK 鍵盤資料夾結構請參考 Keyboard Guidelines - Keyboard Folder Structure

我的原始 rules.mk 長這樣(省略部分註解):

# MCU name
MCU = atmega32u4
 
# Processor frequency.
F_CPU = 16000000
 
# LUFA specific
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8
 
# Input clock frequency.
F_USB = $(F_CPU)
 
# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
 
# Boot Section Size in *bytes*
OPT_DEFS += -DBOOTLOADER_SIZE=4096
 
# Build Options
BOOTMAGIC_ENABLE ?= yes	# Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE ?= yes	# Mouse keys(+4700)
EXTRAKEY_ENABLE ?= yes	# Audio control and System control(+450)
CONSOLE_ENABLE ?= no	# Console for debug(+400)
COMMAND_ENABLE ?= no    # Commands for debug and configuration
SLEEP_LED_ENABLE ?= no  # Breathing sleep LED during USB suspend
NKRO_ENABLE ?= yes      # USB Nkey Rollover
BACKLIGHT_ENABLE ?= no  # Enable keyboard backlight functionality
AUDIO_ENABLE ?= no
RGBLIGHT_ENABLE ?= no

微控制器型號

首先確認 MCU = atmega32u4 這行。請將等號右側改成你實際使用的微控制器晶片型號。例如用 Pro Micro 的話是 ATmega32U4,所以就是 MCU = atmega32u4;如果用的是 Raspberry Pi RP2040 的話就是 MCU = RP2040

QMK 支援的晶片型號可以參考 Compatible Microcontrollers

微控制器頻率

再來是 F_CPU = 16000000 這行。請確認你的晶片的運作頻率是多少,像是 Pro Micro 的話主要有 16MHz 和 8MHz 兩種型號,要分清楚。

如果你用的 Pro Micro 是 8MHz 的,要將原本代表 16MHz 的 F_CPU = 16000000 改成 8MHz:F_CPU = 8000000

如果你是用 RP2040 的話,可以把 F_CPU = ?ARCH = AVR8F_USB = $(F_CPU)OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINTOPT_DEFS += -DBOOTLOADER_SIZE=4096 這幾行刪除。

選擇 Bootloader

然後要選擇 Bootloader 種類,這個部分原本的 rules.mk 裡面沒有,要自己加入。你可以把它加在F_CPU = ? 的下面(位置其實沒什麼差別)。要加入的內容為:

# Bootloader selection
#   Pro Micro    caterina
#   RP2040       rp2040
#   Teensy       halfkay
#   Atmel DFU    atmel-dfu
#   QMK DFU      qmk-dfu
#   LUFA DFU     lufa-dfu
#   ATmega328P   usbasploader
BOOTLOADER = ?
微控制器/開發板Bootloader
Pro Microcaterina
RP2040rp2040
Teensyhalfkay
Atmel DFUatmel-dfu
LUFA DFUlufa-dfu
QMK DFUqmk-dfu
ATmega328Pusbasploader

至於 BOOTLOADER = ? 這行,請依照你的晶片去做選擇。例如是用 Teensy 開發板的話,就是打 BOOTLOADER = halfkay;Pro Micro 是 BOOTLOADER = caterina;RP2040 是 BOOTLOADER = rp2040

QMK 支援的微控制器和 Bootloader 很多,如果是上面沒有寫到的話,請自行參考 QMK 文件。更詳細的說明可以看 Flashing Instructions and Bootloader Information

我以前在這一步卡了好久,上網找問題找了好久才發現這個地方要注意。

其它功能

rules.mk 底下還有一段 Build Options:

# Build Options
#   comment out to disable the options.
#
BOOTMAGIC_ENABLE ?= yes	# Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE ?= yes	# Mouse keys(+4700)
EXTRAKEY_ENABLE ?= yes	# Audio control and System control(+450)
CONSOLE_ENABLE ?= no	# Console for debug(+400)
COMMAND_ENABLE ?= no    # Commands for debug and configuration
SLEEP_LED_ENABLE ?= no  # Breathing sleep LED during USB suspend
NKRO_ENABLE ?= yes      # USB Nkey Rollover
BACKLIGHT_ENABLE ?= no  # Enable keyboard backlight functionality
AUDIO_ENABLE ?= no
RGBLIGHT_ENABLE ?= no

這邊可以啓用/禁用一些特定的功能,可以參考 Feature Options 來瞭解各個功能。

另外,如果你使用的是 ATmega32U4 的話,為了儘可能地降低最終韌體的大小,可以加入 LTO_ENABLE = yes,詳細可以參考 Squeezing Space from AVR

修改完成

rules.mk 的部分大概就是這些,裡面還有更多的設定可以調整,這裡就不細講了。

修改完rules.mk 長這樣(省略部分註解):

# 【Pro Micro (ATmega32U4) 範例 rules.mk】
# MCU name
MCU = atmega32u4
 
# Processor frequency.
F_CPU = 8000000
 
# Bootloader selection
BOOTLOADER = caterina
 
# LUFA specific
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8
 
# Input clock frequency.
F_USB = $(F_CPU)
 
# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
 
# Boot Section Size in *bytes*
OPT_DEFS += -DBOOTLOADER_SIZE=4096
 
# Build Options
BOOTMAGIC_ENABLE ?= yes	# Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE ?= yes	# Mouse keys(+4700)
EXTRAKEY_ENABLE ?= yes	# Audio control and System control(+450)
CONSOLE_ENABLE ?= no	# Console for debug(+400)
COMMAND_ENABLE ?= no    # Commands for debug and configuration
SLEEP_LED_ENABLE ?= no  # Breathing sleep LED during USB suspend
NKRO_ENABLE ?= yes      # USB Nkey Rollover
BACKLIGHT_ENABLE ?= no  # Enable keyboard backlight functionality
AUDIO_ENABLE ?= no
RGBLIGHT_ENABLE ?= no
 
#LTO_ENABLE = yes       # Link time optimization, enable to reduce the compiled size of firmware.
# 【RP2040 範例 rules.mk】
# MCU name
MCU = RP2040
 
# Bootloader selection
BOOTLOADER = rp2040
 
# Build Options
BOOTMAGIC_ENABLE ?= yes	# Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE ?= yes	# Mouse keys(+4700)
EXTRAKEY_ENABLE ?= yes	# Audio control and System control(+450)
CONSOLE_ENABLE ?= no	# Console for debug(+400)
COMMAND_ENABLE ?= no    # Commands for debug and configuration
SLEEP_LED_ENABLE ?= no  # Breathing sleep LED during USB suspend
NKRO_ENABLE ?= yes      # USB Nkey Rollover
BACKLIGHT_ENABLE ?= no  # Enable keyboard backlight functionality
AUDIO_ENABLE ?= no
RGBLIGHT_ENABLE ?= no

修改 config.h

在鍵盤路徑下有個 config.h 檔案,裡面可以修改腳位、USB 資訊等。使用文字編輯軟體打開它。

修改 USB 資訊

config.h 裡有以下這幾行:

/* USB Device descriptor parameter */
#define VENDOR_ID       0xFEED
#define PRODUCT_ID      0x6060
#define DEVICE_VER      0x0001
#define MANUFACTURER    qmkbuilder
#define PRODUCT         keyboard

請注意,原本有一行 #define DESCRIPTION,但新版的 QMK 已經不使用,請將此行刪除。

例如我可以改成:

#define VENDOR_ID       0x5A69  /* ASCII "Zi" */
#define PRODUCT_ID      0xE000
#define DEVICE_VER      0x0001
#define MANUFACTURER    ZiTe
#define PRODUCT         KeyPad

USB VID 與 PID 是 USB 設備的識別號,正常來說是要向 USB 協會申請/購買,但是我們只是要自己做鍵盤的話通常都自行設定就好。要注意的是,如果一臺電腦同時接了多個相同 VID 和 PID 的裝置,那這些裝置可能無法運作。

修改腳位

config.h 裡有以下這幾行,用來修改鍵盤矩陣掃描所用的微控制器腳位。請注意,這裡的腳位名稱是微控制本身的腳位,不是開發板上的,可以回顧一下腳位(Pins)內的說明。

/* key matrix pins */
#define MATRIX_ROW_PINS { B0, B1, B2, B3, B4 }
#define MATRIX_COL_PINS { B5, B6, B7, C0 }

如果你用的是 RP2040 的話,腳位名稱使用的是 GPx,可以參考 RP2040 Pin nomenclature。例如:

#define MATRIX_ROW_PINS { GP0, GP1, GP2, GP3, GP4 }
#define MATRIX_COL_PINS { GP10, GP11, GP12, GP13 }

請注意,原本還有 #define UNUSED_PINS,但是新版的 QMK 已經不使用,請將該行刪除。詳見 QMK Breaking Changes - 2022 August 27 ChangelogPull Request #17931 · qmk/qmk_firmware

鍵盤矩陣大小

鍵盤矩陣的大小可以在此修改。Row 與 Colume 的數量要和設定的腳位數量一致:

/* key matrix size */
#define MATRIX_ROWS 5
#define MATRIX_COLS 4

防彈跳

請注意,原本的防彈跳是使用:

/* Set 0 if debouncing isn't needed */
#define DEBOUNCING_DELAY 5

但新版的 QMK 將 DEBOUNCING_DELAY 改成 DEBOUNCE,所以要將該行修改成:

/* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5

其它

請注意,原本的 config.h 內有:

/* prevent stuck modifiers */
#define PREVENT_STUCK_MODIFIERS

但新版的 QMK 已經不使用 PREVENT_STUCK_MODIFIERS,請將該行刪除。詳見 Issue #2518 · qmk/qmk_firmware

另外,原本的 config.h(及其它 .h 檔案) 的 Include Guard 是使用傳統的預處理器寫法,你可以將其改成較先進的 #pragma once。例如:

/* 舊 */
#ifndef CONFIG_H
#define CONFIG_H
 
...
 
#endif

改成以下

/* 新 */
#pragma once
 
...

如果你沒有改用 #pragma once,且你有更改鍵盤的名稱(不是 #define PRODUCT 的名稱,是預設為 kb 的資料夾與檔案名稱),那原本的 kb.h 被修改成 my_new_keyboard.h 後,其內的 KB_H 要修改成 MY_NEW_KEYBOARD_H,即這裡也要改成你鍵盤的名稱且習慣全大寫。當然,如果你熟悉 C 的話可以用你喜歡的方式。

如果你使用的是 RP2040 的話,可以在 config.h 中加入:

#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET

這樣就可以啓用 Double-tap Reset 功能,未來燒錄時會比較方便。

修改完成

修改完成的 config.h 範例:

#pragma once
 
#include "config_common.h"
 
/* USB Device descriptor parameter */
#define VENDOR_ID       0x5A69  /* ASCII "Zi" */
#define PRODUCT_ID      0xE000
#define DEVICE_VER      0x0001
#define MANUFACTURER    ZiTe
#define PRODUCT         KeyPad
 
/* key matrix size */
#define MATRIX_ROWS 5
#define MATRIX_COLS 4
 
/* key matrix pins */
#define MATRIX_ROW_PINS { B0, B1, B2, B3, B4 }
#define MATRIX_COL_PINS { B5, B6, B7, C0 }
 
/* COL2ROW or ROW2COL */
#define DIODE_DIRECTION COL2ROW
 
/* number of backlight levels */
#ifdef BACKLIGHT_PIN
#define BACKLIGHT_LEVELS 3
#endif
 
/* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5
 
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
 
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE
 
/* key combination for command */
#define IS_COMMAND() ( \
    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)
 
#ifdef RGB_DI_PIN
#define RGBLIGHT_ANIMATIONS
#define RGBLED_NUM 0
#define RGBLIGHT_HUE_STEP 8
#define RGBLIGHT_SAT_STEP 8
#define RGBLIGHT_VAL_STEP 8
#endif

修改 keymap.c

\kb\keymaps\default\ 底下,有個 keymap.c 檔案,這是用來指定鍵映射的,使用文字編輯軟體打開它。

刪除 even

首先找到 const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) 這一段,將其用 // 註解掉(或直接刪除),也就是把該區塊變成:

// const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
//   keyevent_t event = record->event;
//
//   switch (id) {
//
//   }
//   return MACRO_NONE;
// }

這邊預設會造成編譯錯誤 unused variable 'event' [-Werror=unusued-variable] keyevent_t event = record->event;,當然,如果你懂 C 的話就知道這是什麼意思,可以透過其它你自己喜歡的方式解決。可以參考 QMK issue - error: unused variable ‘event’ [-Werror=unused-variable] : olkb

改按鍵映射

先前的段落有提到 Keyboard Firmware Builder 裡的「Keymap」標籤頁可以設定的按鍵並不完全,如果想要自行修改的話就要再此編輯。

keymap.c 裡你會看到許多像是這樣的內容:

KEYMAP(
	KC_NLCK, KC_SLSH, KC_ASTR, KC_MINS,
	KC_P7,   KC_P8,   KC_F9,
	KC_P4,   KC_P5,   KC_P6,   KC_PLUS,
	KC_P1,   KC_P2,   KC_P3,
	KC_P0,   MO(1),   KC_PENT),

這些就代表了鍵盤各個鍵位的按鍵功能。像是 KC_P7 代表了 Numpad7(數字鍵盤的 7),而詳細的按鍵名稱請參考 QMK 的說明文件:Keycodes Overview

你所需要做的就是把該按鍵的代號(如 KC_P7)放在對的位置就好了。而每一塊 KEYMAP(...) 代表的是一層,最上面的是第 0 層,往下是第 1、2…n 層。

新版的 QMK 習慣使用 LAYOUT 為名而非 KEYMAP,你可以將 keymap.ckb.h 內的 KEYMAP 都改成 LAYOUT。但是不修改應該還是可以完成編譯。

結語

到此為止,QMK 韌體原始檔的基本編輯就完成了,接下來就要準備進行編譯。

這一篇的內容可能比較難,且 QMK 也一直再更新,如果有我寫得不夠清楚或是有誤的地方,歡迎提出。

相關網站及參考資料

本文最早發佈於 2020-06-21,於 2023 重新編排並更新內容。


KiCanvas——線上預覽KiCAD電路圖
[自製QMK鍵盤-1] 編輯鍵盤佈局 (Layout)

留言可能不會立即顯示。若過了幾天仍未出現,請 Email 聯繫:)