瀚文(HelloWord)智能鍵盤項目深度剖析:從0到1的全流程解讀
一、項目整體概述
瀚文(HelloWord)智能鍵盤是一款多功能、模塊化的智能機械鍵盤,由三大部分組成:鍵盤輸入模塊、可替換的多功能交互模塊(Dynamic組件)以及擴展塢底座。項目完全開源,涵蓋了硬件設計、固件開發、3D模型設計等全方位內容。
該鍵盤的特點包括:
- 左側可更換的多功能交互組件(默認為帶電子墨水屏和FOC力反饋旋鈕的Dynamic組件)
- 基于ARM Cortex-M的定制固件系統
- 基于移位寄存器的高效按鍵掃描電路
- 模塊化設計,可獨立使用或組合使用
二、項目文件夾結構及功能解析
2.1 .idea
文件夾
這是JetBrains IDE(如CLion)的配置文件夾,包含項目設置信息。對于初學者來說,可以暫時忽略。
2.2 1.Hardware
文件夾
此文件夾包含鍵盤硬件設計文件,主要是各模塊的電路原理圖:
1.Hardware/
├── 工程鏈接.txt # 立創EDA項目鏈接
├── SCH_HelloWord-Keyboard_2022-07-31.pdf # 主鍵盤電路圖
├── SCH_HelloWord-Ctrl_2022-07-31.pdf # 左側Dynamic組件電路圖
├── SCH_HelloWord-TypeC_2022-07-31.pdf # TypeC接口電路圖
└── [其他PCB模塊電路圖] # 各功能模塊電路圖
核心技術分析:
鍵盤硬件采用了高度模塊化設計,共有10塊PCB組成不同功能模塊:
// 鍵盤PCB模塊組成及功能
PCB_Modules = {"HelloWord-Keyboard": "主鍵盤PCB,STM32F103控制器,按鍵輸入+RGB燈","HelloWord-Ctrl": "Dynamic組件PCB,STM32F405控制器,帶FOC力反饋旋鈕和墨水屏","HelloWord-Connector": "主鍵盤連接底座的觸點PCB","HelloWord-TypeC": "底座TypeC接口PCB,帶電源管理和USB-Hub","HelloWord-Hub1": "底座USB-A接口轉接PCB","HelloWord-Hub2": "底座USB-A母座PCB","HelloWord-OLED": "OLED屏幕驅動電路","HelloWord-TouchBar": "電容觸摸條模塊PCB","HelloWord-Encoder": "磁編碼器PCB","[其他模塊]": "..."
}
這種模塊化設計使各功能塊可以獨立工作,也能通過底座聯動,大大提高了靈活性。
2.3 2.Firmware
文件夾
包含鍵盤和Dynamic組件的固件源碼及預編譯固件:
2.Firmware/
├── HelloWord-Keyboard-fw/ # 主鍵盤固件
├── HelloWord-Dynamic-fw/ # Dynamic組件固件
└── _Release/ # 預編譯的bin固件文件
2.3.1 按鍵映射實現
// 鍵盤固件中的按鍵映射方式(hw_keyboard.h)
const uint8_t keyMap[KEYMAP_NUM][IO_NUMBER] = {// 層0:硬件按鍵編號 -> 標準布局位置映射{9, 8, 7, 6, 5, 4, 3, 2, 1, 0, // 0-9號按鍵的映射19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 10-19號按鍵的映射// ... 更多按鍵映射},// 層1:標準布局(正常使用時的鍵值){ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, // 基本按鍵// ... 標準鍵盤布局},// 層2、3等:自定義功能層// ...
};
代碼解析:
keyMap
是一個二維數組,第一維表示映射層數,第二維表示按鍵序號- 第0層負責將PCB上物理按鍵位置映射到標準鍵盤布局位置
- 第1層是標準鍵盤鍵值映射
- 第2層及以上是自定義功能層,可以將任意按鍵映射為任意功能
通過軟件映射,PCB上的按鍵可以任意放置,不需要遵循傳統鍵盤的布局限制,這極大提高了設計靈活性。
2.3.2 按鍵濾波算法
// 對稱延遲獨立濾波(簡化版)
void HWKeyboard::ScanKeys()
{// 第一次掃描uint8_t buffer1[IO_NUMBER/8] = {0};ScanIO(buffer1);// 延遲一段時間(微秒級)DelayUs(DEBOUNCE_TIME);// 第二次掃描uint8_t buffer2[IO_NUMBER/8] = {0};ScanIO(buffer2);// 比較兩次結果,確保按鍵狀態穩定for(uint8_t i = 0; i < IO_NUMBER/8; i++){if((buffer1[i] ^ lastBuffer[i]) & (buffer1[i] ^ buffer2[i]) == 0){// 狀態穩定,更新按鍵狀態keysState[i] = buffer2[i];}lastBuffer[i] = buffer2[i];}
}
代碼解析:
- 這段代碼實現了"對稱延遲獨立濾波",對每個按鍵單獨進行抖動過濾
- 兩次掃描之間間隔微秒級延時,只有兩次狀態一致才認為按鍵狀態有效
- 這種方式比傳統全局濾波更高效,可以保證每個按鍵獨立處理,提高響應速度
2.3.3 RGB燈效控制
// RGB控制示例代碼
void HWKeyboard::SyncLights()
{// 將RGB數據轉換為WS2812B時序數據for(uint8_t i = 0; i < LED_NUMBER; i++){// R、G、B依次轉換為24位時序數據ConvertToSPIBits(rgbBuffer[i].g); // WS2812B需要GRB順序ConvertToSPIBits(rgbBuffer[i].r);ConvertToSPIBits(rgbBuffer[i].b);}// 通過SPI+DMA方式高速發送數據HAL_SPI_Transmit_DMA(&hspi1, spiBuffer, SPI_BUFFER_SIZE);
}// 燈效示例
void RainbowEffect()
{static uint8_t hue = 0;hue++;for(uint8_t i = 0; i < LED_NUMBER; i++){// 計算每個LED的色相偏移uint8_t pixelHue = hue + (i * 255 / LED_NUMBER);// 將HSV轉換為RGBColor_t color = HSV2RGB(pixelHue, 255, 128);// 設置RGB緩沖區keyboard.SetRgbBuffer(i, color);}// 同步發送到LEDkeyboard.SyncLights();
}
代碼解析:
- 通過SPI+DMA模擬WS2812B時序,相比傳統位帶操作大幅提高效率
- RGB燈效可以輕松通過修改
rgbBuffer
來實現各種動態效果 - 支持單獨控制每個按鍵的RGB顏色,實現豐富的燈光效果
2.4 3.Software
文件夾
包含鍵盤的PC端配套軟件:
3.Software/
├── 說明.md # 軟件使用說明
├── 修改墨水屏圖片.zip # 墨水屏圖片修改工具
└── HelloWord_plugin.js # 鍵盤插件腳本
功能分析:
- 墨水屏圖片修改工具:允許用戶自定義墨水屏顯示內容
- JavaScript插件:用于擴展鍵盤功能,可能用于自定義快捷鍵或動作
2.5 4.Tools
文件夾
提供開發和使用必要的工具軟件:
4.Tools/
├── 安裝USB驅動/ # USB驅動程序
├── HID Descriptor Tool/ # USB HID描述符工具
└── STM32 ST-LINK Utility v4.5.0.exe # STM32燒錄工具
工具用途:
- ST-LINK Utility:用于將編譯好的固件燒錄到STM32芯片
- USB驅動:確保Windows系統正確識別鍵盤設備
- HID工具:幫助開發者編寫和測試USB HID描述符
2.6 5.3D Model
文件夾
提供鍵盤外殼和機構的3D模型文件:
5.3D Model/
├── 瀚文擴展版/ # 擴展版3D模型文件
├── 瀚文基礎版/ # 基礎版3D模型文件
└── 瀚文全套模型STEP.stp # 完整的STEP格式3D模型
結構特點:
- 模塊化結構設計,包括底座、主鍵盤和左側可更換模塊
- 提供STEP格式文件,兼容大多數3D建模軟件
- 支持3D打印制作,方便DIY愛好者復刻
2.7 5.Docs
文件夾
包含項目相關的參考資料和文檔:
5.Docs/
├── 1.Datasheet/ # 項目中使用的芯片數據手冊
├── 2.Images/ # 項目圖片資源
└── HID用途表1.12.pdf # USB HID協議參考文檔
文檔內容:
- 芯片數據手冊:提供項目使用的電子元器件詳細規格
- 項目圖片:用于README和文檔展示
- HID協議文檔:USB HID通信協議參考
三、技術亮點分析
3.1 移位寄存器按鍵掃描技術
傳統鍵盤通常采用行列式掃描,而瀚文鍵盤使用移位寄存器(74HC165)實現:
// 傳統行列式掃描
void ScanMatrix(uint8_t* keyStates)
{// 逐行掃描for(uint8_t row = 0; row < ROWS; row++){// 設置當前行為低電平SetRowLow(row);// 讀取所有列狀態for(uint8_t col = 0; col < COLS; col++){keyStates[row * COLS + col] = ReadColPin(col);}// 恢復當前行為高電平SetRowHigh(row);}
}// 瀚文的移位寄存器掃描(簡化版)
void ScanShiftRegister(uint8_t* keyStates)
{// 加載按鍵狀態到移位寄存器HAL_GPIO_WritePin(LOAD_GPIO_Port, LOAD_Pin, GPIO_PIN_RESET);HAL_GPIO_WritePin(LOAD_GPIO_Port, LOAD_Pin, GPIO_PIN_SET);// 通過SPI讀取所有按鍵狀態(一次性讀取多個按鍵)HAL_SPI_Receive(&hspi2, keyStates, IO_NUMBER/8, HAL_MAX_DELAY);
}
優勢對比:
- 速度更快:SPI接口可達數MHz,一次讀取多個按鍵
- 完全無沖突(NKRO):每個按鍵都是獨立的,無鬼鍵問題
- 布局靈活:PCB布局與掃描順序解耦,任意布局都可以通過軟件重映射
3.2 FOC力反饋旋鈕實現
Dynamic模塊中實現了基于FOC(Field Oriented Control)的力反饋旋鈕:
// FOC控制核心代碼(簡化版)
void FOC_Controller::update()
{// 1. 讀取編碼器位置float shaftAngle = encoder->getAngle();// 2. 計算電角度float electricalAngle = shaftAngle * pole_pairs;// 3. 計算所需的電機扭矩float torque = calculateTorque();// 4. FOC電流控制float Uq = PID(targetCurrent, measuredCurrent);// 5. 計算三相電壓float Ua, Ub, Uc;SinCos3Phase(electricalAngle, torque, Uq, &Ua, &Ub, &Uc);// 6. 輸出PWMsetPWM(Ua, Ub, Uc);
}// 不同觸感效果實現
void DynamicEffect::detentEffect()
{// 實現齒輪槽卡頓感float angle = encoder->getAngle();float detent = sin(angle * detentsPerRevolution) * detentStrength;motor->setTorque(detent);
}
技術解析:
- 使用AS5047P精密磁編碼器檢測旋鈕位置
- 基于FOC算法控制無刷電機,提供精確的力反饋
- 通過軟件定義不同的力觸感模型,可以模擬機械齒輪、阻尼、彈簧等多種感覺
3.3 模塊化通信架構
鍵盤底座、主鍵盤和左側模塊之間建立了復雜的通信機制:
// 模塊間通信協議(簡化版)
typedef struct {uint8_t header[2]; // 0xAA, 0x55 固定頭uint8_t type; // 消息類型uint8_t length; // 數據長度uint8_t data[32]; // 數據負載uint8_t checksum; // 校驗和
} ModuleMessage_t;// 發送消息到其他模塊
void sendToModule(uint8_t moduleID, uint8_t msgType, uint8_t* data, uint8_t len)
{ModuleMessage_t msg;// 填充消息頭msg.header[0] = 0xAA;msg.header[1] = 0x55;msg.type = msgType;msg.length = len;// 復制數據memcpy(msg.data, data, len);// 計算校驗和msg.checksum = calculateChecksum(&msg);// 根據模塊ID選擇發送接口switch(moduleID) {case MODULE_KEYBOARD:UART_SendData(UART_KEYBOARD, (uint8_t*)&msg, len+5);break;case MODULE_DYNAMIC:UART_SendData(UART_DYNAMIC, (uint8_t*)&msg, len+5);break;// 其他模塊...}
}
架構優勢:
- 基于串口通信的輕量級協議,延遲低,實現簡單
- 模塊可獨立工作,也可協同工作,增強系統彈性
- 標準化消息格式,便于擴展新模塊和功能
四、從0到1的開發指南
4.1 準備開發環境
# 1. 安裝必要軟件
- STM32CubeIDE 或 CLion+OpenOCD (編譯環境)
- STM32 ST-LINK Utility (燒錄工具)
- 立創EDA專業版 (查看或修改硬件)# 2. 克隆代碼倉庫
git clone https://github.com/peng-zhihui/HelloWord-Keyboard.git# 3. 打開項目
# 對于STM32CubeIDE:
- 打開STM32CubeIDE
- File -> Import -> Existing Projects into Workspace
- 選擇HelloWord-Keyboard-fw或HelloWord-Dynamic-fw文件夾# 對于CLion:
- 打開CLion
- File -> Open
- 選擇對應固件文件夾
- 配置CMake和OpenOCD(參考README中提到的教程)
4.2 硬件制作流程
# 1. PCB制作
- 下載PCB源文件(立創EDA格式)
- 通過立創EDA打開項目,查看或修改設計
- 生成Gerber文件,發送給PCB制造商
- 根據BOM表采購電子元器件
- 焊接組裝PCB# 2. 結構件制作
- 下載3D模型文件
- 使用3D打印機打印結構件或
- 將STEP文件發送給CNC加工廠商制作鋁材外殼
4.3 自定義按鍵映射
要修改鍵盤的按鍵映射,需要編輯hw_keyboard.h
文件中的映射數組:
// 步驟1:了解物理按鍵與編號的對應關系
// 按鍵編號是按照74HC165芯片的連接順序確定的// 步驟2:修改第0層映射(硬件映射到標準位置)
const uint8_t keyMap[KEYMAP_NUM][IO_NUMBER] = {{// 這里填入物理按鍵編號,映射到標準鍵盤位置9, 8, 7, 6, 5, /* ... 更多按鍵 */},// 步驟3:修改第1層及更高層(功能映射){ESC, F1, F2, F3, F4, /* ... 更多按鍵 */},// 自定義功能層(如宏、媒體鍵等){/* ... 自定義功能鍵映射 ... */}
};// 步驟4:編譯并燒錄固件
實用技巧:
- 可以先通過調試模式打印出所有按鍵的物理編號,然后逐一確認
- 建議使用枚舉常量定義按鍵功能,增強代碼可讀性
- 不同層可以通過組合鍵(如Fn+其他鍵)切換
4.4 添加自定義RGB燈效
// 步驟1:在hw_keyboard.h中添加新的燈效函數
void MyCustomEffect()
{static uint32_t lastTime = 0;static uint8_t position = 0;// 控制更新速率uint32_t currentTime = HAL_GetTick();if (currentTime - lastTime < 50) return;lastTime = currentTime;// 清空所有LEDfor (uint8_t i = 0; i < LED_NUMBER; i++) {keyboard.SetRgbBuffer(i, {0, 0, 0});}// 設置流動的LEDfor (uint8_t i = 0; i < 3; i++) {uint8_t pos = (position + i) % LED_NUMBER;keyboard.SetRgbBuffer(pos, {0, 0, 255 - i*50});}// 移動位置position = (position + 1) % LED_NUMBER;// 更新LED顯示keyboard.SyncLights();
}// 步驟2:在main循環中調用自定義燈效
int main(void)
{// 初始化代碼...while (1){// 處理按鍵...// 調用自定義燈效MyCustomEffect();// 其他任務...}
}
擴展思路:
- 可以創建燈效庫,通過自定義按鍵切換不同燈效
- 為特定按鍵設置獨特顏色,如WASD按鍵高亮
- 實現與按鍵反饋聯動的燈效,如按下按鍵時產生漣漪效果
4.5 Dynamic模塊APP開發
// 步驟1:在Dynamic-fw中創建新的APP類
class MyCustomApp : public AppBase
{
public:MyCustomApp() {// 初始化}// 繪制墨水屏內容void renderEPaper() override {ePaper.clearBuffer();ePaper.setFont(u8g2_font_ncenB14_tr);ePaper.drawStr(10, 32, "My Custom App");// 繪制更多內容...ePaper.sendBuffer();}// 處理旋鈕事件void onEncoderRotate(int16_t delta) override {// 根據旋轉方向和幅度響應if (delta > 0) {// 順時針旋轉value += delta;} else {// 逆時針旋轉value -= -delta;}// 設置力反饋float torque = sin(value * 0.1) * 0.5;motor->setTorque(torque);}// 處理按鈕事件void onButtonPress(uint8_t buttonId) override {// 處理按鈕按下事件}private:int value = 0;
};// 步驟2:注冊APP到系統
void initApps()
{// 注冊已有APPappsManager.registerApp(new ClockApp());appsManager.registerApp(new VolumeControlApp());// 注冊自定義APPappsManager.registerApp(new MyCustomApp());
}
開發建議:
- 研究現有APP的實現邏輯,掌握系統架構
- 墨水屏更新要謹慎,頻繁刷新會導致閃爍和老化
- 力反饋建議使用自然的物理模型,如彈簧、阻尼等,提升用戶體驗
五、常見問題及解決方案
5.1 硬件問題
Q1: 按鍵無響應或錯誤觸發?
A1: - 檢查74HC165芯片連接是否正確- 驗證焊接質量,排除虛焊問題- 檢查按鍵是否正確安裝到PCB上- 修改濾波時間參數,延長去抖時間Q2: RGB燈不亮或顯示錯誤?
A2: - 檢查WS2812B燈珠焊接方向是否正確- 驗證SPI配置,確保時鐘頻率合適(通常8MHz)- 檢查數據線連接是否完好- 通過逐一點亮測試排查問題燈珠Q3: 力反饋旋鈕不工作?
A3: - 確認電機和編碼器正確安裝- 測量電機驅動電路工作電壓是否正常- 嘗試運行提供的測試固件,執行電機校準- 檢查FPC線纜質量,長度過長會導致壓降
5.2 軟件問題
Q1: 編譯錯誤怎么解決?
A1: - 檢查開發環境配置,確保安裝了正確版本的工具鏈- 驗證所有依賴庫是否正確包含- 檢查項目配置中的芯片型號是否與實際使用的匹配- 查看錯誤日志,針對具體問題解決Q2: 按鍵映射不正確?
A2: - 重新檢查第0層映射與物理按鍵的對應關系- 打印掃描結果,確認每個按鍵被正確識別- 確保keyMap數組維度與實際按鍵數匹配- 驗證多層映射邏輯是否正確Q3: 墨水屏無法更新?
A3: - 檢查SPI通信配置- 驗證墨水屏型號與驅動代碼是否匹配- 墨水屏可能需要上電重置,嘗試重啟設備- 檢查圖像數據格式是否符合要求
六、項目拓展思路
6.1 功能拓展方向
1. 網絡連接能力- 添加ESP32模塊實現Wi-Fi連接- 開發云端配置和同步功能- 實現IoT控制功能2. 高級輸入體驗- 添加熱插拔支持- 實現壓力感應按鍵- 添加觸摸條或觸摸板3. 軟件生態- 開發跨平臺配置軟件- 建立用戶分享鍵位配置的平臺- 開發Dynamic模塊的APP商店
6.2 硬件升級路線
1. 主控升級- 使用STM32F4/F7系列獲得更強性能- 添加藍牙連接模塊實現無線功能- 增加內存和存儲空間支持更多功能2. 顯示升級- 更換為彩色LCD或AMOLED屏幕- 添加更多顯示區域- 實現動態UI界面3. 傳感器增強- 添加環境光傳感器自動調節RGB亮度- 集成IMU實現手勢控制- 添加指紋識別增強安全性
七、總結
瀚文(HelloWord)鍵盤項目是一個集硬件設計、固件開發、結構設計于一體的綜合性項目,其模塊化的設計理念和創新的技術實現使其成為DIY鍵盤領域的杰出案例。無論你是硬件愛好者、嵌入式開發者還是普通用戶,都能從這個項目中獲取有價值的知識和靈感。
通過本文的詳細解析,希望能幫助你從0開始理解瀚文鍵盤的設計理念和技術實現,進而定制或開發出屬于自己的智能鍵盤。開源精神的核心就是分享和創新,期待看到更多基于瀚文的創意項目!
本文檔基于瀚文鍵盤開源項目分析整理,項目地址:HelloWord-Keyboard