瀚文(HelloWord)智能键盘项目深度剖析:从0到1的全流程解读

瀚文(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组成不同功能模块:

c 复制代码
// 键盘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 按键映射实现
c 复制代码
// 键盘固件中的按键映射方式(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 按键滤波算法
c 复制代码
// 对称延迟独立滤波(简化版)
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灯效控制
c 复制代码
// 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转换为RGB
        Color_t color = HSV2RGB(pixelHue, 255, 128);
        
        // 设置RGB缓冲区
        keyboard.SetRgbBuffer(i, color);
    }
    
    // 同步发送到LED
    keyboard.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)实现:

c 复制代码
// 传统行列式扫描
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);
}

优势对比

  1. 速度更快:SPI接口可达数MHz,一次读取多个按键
  2. 完全无冲突(NKRO):每个按键都是独立的,无鬼键问题
  3. 布局灵活:PCB布局与扫描顺序解耦,任意布局都可以通过软件重映射

3.2 FOC力反馈旋钮实现

Dynamic模块中实现了基于FOC(Field Oriented Control)的力反馈旋钮:

c 复制代码
// 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. 输出PWM
    setPWM(Ua, Ub, Uc);
}

// 不同触感效果实现
void DynamicEffect::detentEffect()
{
    // 实现齿轮槽卡顿感
    float angle = encoder->getAngle();
    float detent = sin(angle * detentsPerRevolution) * detentStrength;
    motor->setTorque(detent);
}

技术解析

  • 使用AS5047P精密磁编码器检测旋钮位置
  • 基于FOC算法控制无刷电机,提供精确的力反馈
  • 通过软件定义不同的力触感模型,可以模拟机械齿轮、阻尼、弹簧等多种感觉

3.3 模块化通信架构

键盘底座、主键盘和左侧模块之间建立了复杂的通信机制:

c 复制代码
// 模块间通信协议(简化版)
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 准备开发环境

bash 复制代码
# 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 硬件制作流程

bash 复制代码
# 1. PCB制作
- 下载PCB源文件(立创EDA格式)
- 通过立创EDA打开项目,查看或修改设计
- 生成Gerber文件,发送给PCB制造商
- 根据BOM表采购电子元器件
- 焊接组装PCB

# 2. 结构件制作
- 下载3D模型文件
- 使用3D打印机打印结构件
  或
- 将STEP文件发送给CNC加工厂商制作铝材外壳

4.3 自定义按键映射

要修改键盘的按键映射,需要编辑hw_keyboard.h文件中的映射数组:

c 复制代码
// 步骤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灯效

c 复制代码
// 步骤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;
    
    // 清空所有LED
    for (uint8_t i = 0; i < LED_NUMBER; i++) {
        keyboard.SetRgbBuffer(i, {0, 0, 0});
    }
    
    // 设置流动的LED
    for (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开发

c 复制代码
// 步骤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()
{
    // 注册已有APP
    appsManager.registerApp(new ClockApp());
    appsManager.registerApp(new VolumeControlApp());
    
    // 注册自定义APP
    appsManager.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

相关推荐
永霖光电_UVLED2 小时前
KAIST 团队研发出高效、超高分辨率的红色微米发光二极管(Micro-LED)显示器
计算机外设
春日见1 天前
车辆动力学:前后轮车轴
java·开发语言·驱动开发·docker·计算机外设
PHOSKEY1 天前
光子精密QM系列闪测仪在鼠标电路板部件质量控制中的核心应用
计算机外设
墩墩冰1 天前
计算机图形学 分析选择缓冲区中的数字
计算机外设
UI设计兰亭妙微1 天前
中车株州所显示器界面设计
计算机外设·界面设计
墩墩冰2 天前
计算机图形学 多视区的显示
计算机外设
墩墩冰2 天前
计算机图形学 GLU库中的二次曲面函数
计算机外设
墩墩冰2 天前
计算机图形学 利用鼠标实现橡皮筋技术
计算机外设
企鹅侠客3 天前
鼠标键盘按键统计工具
计算机外设·键盘·鼠标
华一精品Adreamer4 天前
便携式显示器供应链与成本结构:挑战与机遇
计算机外设