ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

QMK 固件背光(Backlight)功能完全指南:PWM 原理、驱动配置与 API 详解

QMK 固件背光(Backlight)功能完全指南:PWM 原理、驱动配置与 API 详解 QMK 固件背光Backlight功能完全指南PWM 原理、驱动配置与 API 详解【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware本文以 QMK Firmware 官方文档 docs/features/backlight.md 为主体结合仓库中 quantum/backlight 与 platforms 下的驱动源码系统讲解 QMK 背光Backlighting特性的启用方式、按键码、配置项、四种驱动pwm/timer/software/custom、AVR 与 ChibiOS/ARM 平台配置以及完整的 C API。读完本文你将能够为自己的键盘正确启用并配置背光、选配合适的驱动、实现多引脚背光与呼吸效果并理解 PWM 调光的底层实现。Backlight 是什么与 RGB 特效的区别QMK 中的Backlighting背光指通过放置在键帽下方或轴体旁边的 LED 为按键提供照明。它通常为每个开关只提供一种颜色虽然你当然可以在同一块键盘上安装多种不同颜色的单色 LED。注意该功能与 RGB Underglow灯带 RGB 底光和 RGB Matrix按键级 RGB 矩阵是两个完全独立的特性。背光强调的是亮度可调的单色照明而非多色动画效果。PWM背光调光的核心原理QMK 通过脉冲宽度调制Pulse Width Modulation, PWM来控制 LED 亮度以极高的频率快速切换 LED 的开关状态通过改变 PWM 信号的占空比duty cycle让 LED 在亮/灭之间快速切换利用人眼的视觉暂留效应形成变暗的错觉。从源码看这一思路贯穿了整个驱动层。例如 AVR 平台 PWM 驱动的实现 platforms/avr/drivers/backlight_pwm.c 中BACKLIGHT_LIMIT_VAL默认255直接对应 8 位定时器 OCR 寄存器可写入的最大占空比值// Maximum duty cycle limit #ifndef BACKLIGHT_LIMIT_VAL # define BACKLIGHT_LIMIT_VAL 255 #endif启用 Backlight大多数支持背光的键盘默认已开启该功能。如果你的键盘背光不工作或者你刚为键盘添加了背光支持请确认rules.mk中包含以下配置BACKLIGHT_ENABLE yes顶层 API 一览启用后quantum/backlight/backlight.c 提供的核心状态机即开始工作。其中backlight_config全局变量由 quantum/backlight/backlight.h 中定义的位域结构体承载并仅占用 EEPROM 中的 1 个字节typedef union backlight_config_t { uint8_t raw; struct { bool enable : 1; bool breathing : 1; bool valid : 1; uint8_t level : 5; // 5 bit上限 31 }; } backlight_config_t; STATIC_ASSERT(sizeof(backlight_config_t) sizeof(uint8_t), Backlight EECONFIG out of spec.);该结构解释了为什么BACKLIGHT_LEVELS的上限是 31level字段只有 5 bit超过 31 会在编译期直接报错。backlight_init()会从 EEPROM 读取配置若校验位无效则写入默认值见 backlight.c。按键码Keycodes在键盘映射keymap中可直接使用以下按键码控制背光。它们定义于 quantum/keycodes.hQK_BACKLIGHT_*系列占位0x7800–0x7806别名BL_*在 quantum/keycodes.h 中给出。按键别名描述QK_BACKLIGHT_TOGGLEBL_TOGG打开/关闭背光QK_BACKLIGHT_STEPBL_STEP循环切换背光亮度档位QK_BACKLIGHT_ONBL_ON将背光设为最大亮度QK_BACKLIGHT_OFFBL_OFF关闭背光QK_BACKLIGHT_UPBL_UP提高背光亮度档位QK_BACKLIGHT_DOWNBL_DOWN降低背光亮度档位QK_BACKLIGHT_TOGGLE_BREATHINGBL_BRTG切换背光呼吸模式按键码的底层调用链按键处理逻辑位于 quantum/process_keycode/process_backlight.c可以看到每个按键码对应的函数调用case QK_BACKLIGHT_ON: backlight_level(BACKLIGHT_LEVELS); return false; case QK_BACKLIGHT_OFF: backlight_level(0); return false; case QK_BACKLIGHT_DOWN: backlight_decrease(); return false; case QK_BACKLIGHT_UP: backlight_increase(); return false; case QK_BACKLIGHT_TOGGLE: backlight_toggle(); return false; case QK_BACKLIGHT_STEP: backlight_step(); return false; #ifdef BACKLIGHT_BREATHING case QK_BACKLIGHT_TOGGLE_BREATHING: backlight_toggle_breathing(); return false; #endif值得注意的是QK_BACKLIGHT_TOGGLE_BREATHING只有在config.h中定义了BACKLIGHT_BREATHING时才会被处理见 process_backlight.c未启用呼吸功能的固件中该键码不会生效。以BL_STEP为例其调用的backlight_step()在 backlight.c 中实现为档位递增超过BACKLIGHT_LEVELS后回绕到 0关闭的循环逻辑void backlight_step(void) { backlight_config.level; if (backlight_config.level BACKLIGHT_LEVELS) { backlight_config.level 0; } backlight_config.enable !!backlight_config.level; eeconfig_update_backlight(backlight_config); backlight_set(backlight_config.level); }基础配置config.h在config.h中添加以下配置项即可调整背光行为。所有默认值与 backlight.h 及 backlight.c 中的定义一一对应定义默认值描述BACKLIGHT_PIN未定义控制 LED 的引脚BACKLIGHT_LEVELS3亮度档位数量最大 31不含关闭档BACKLIGHT_CAPS_LOCK未定义用背光实现 Caps Lock 指示灯适用于没有独立指示灯的键盘BACKLIGHT_BREATHING未定义启用背光呼吸效果若驱动支持BREATHING_PERIOD6一次完整呼吸的时长秒BACKLIGHT_ON_STATE1背光开启时引脚的电平状态——1为高电平0为低电平BACKLIGHT_LIMIT_VAL255背光最大占空比——255允许满亮度调低则降低最大亮度BACKLIGHT_DEFAULT_ONtrue清除 EEPROM 后默认是否开启背光BACKLIGHT_DEFAULT_BREATHINGfalse清除 EEPROM 后默认是否启用呼吸BACKLIGHT_DEFAULT_LEVELBACKLIGHT_LEVELS清除 EEPROM 后默认的亮度档位除非你自己设计键盘一般无需修改BACKLIGHT_PIN和BACKLIGHT_ON_STATE。关于默认值与 EEPROM 重置三个BACKLIGHT_DEFAULT_*配置项只影响清除 EEPROM 之后的初始状态相关逻辑见 backlight.c 的eeconfig_update_backlight_default()void eeconfig_update_backlight_default(void) { backlight_config.valid true; backlight_config.enable BACKLIGHT_DEFAULT_ON; backlight_config.breathing BACKLIGHT_DEFAULT_BREATHING; backlight_config.level BACKLIGHT_DEFAULT_LEVEL; eeconfig_update_backlight(backlight_config); }运行期间通过按键码调整的背光状态会被写回 EEPROM下次上电自动恢复。On 状态高电平/低电平有效大多数背光电路由N 沟道 MOSFET 或 NPN 三极管驱动要让三极管导通并点亮 LED需要把连接到栅极/基极的背光引脚置为高电平。但也有些电路使用P 沟道 MOSFET 或 PNP 三极管此时三极管导通对应的是引脚被拉低。如需配置低电平有效的背光电路在config.h中添加#define BACKLIGHT_ON_STATE 0从 quantum/backlight/backlight_driver_common.c 可以看到BACKLIGHT_ON_STATE直接决定backlight_on()/backlight_off()写入引脚的高低电平static inline void backlight_on(pin_t backlight_pin) { #if BACKLIGHT_ON_STATE 0 gpio_write_pin_low(backlight_pin); #else gpio_write_pin_high(backlight_pin); #endif }多背光引脚Multiple Backlight Pins大多数键盘只有一个背光引脚尤其是当背光接在硬件 PWM 引脚上时。而timer与software驱动允许定义多个背光引脚它们会在 PWM 占空比周期内被同步点亮/熄灭。典型应用场景将 Caps Lock LED或其他可控 LED纳入背光使其亮度与其余背光 LED 一致。例如当你把 Caps 键映射为 Control 时原本开启 Caps Lock 才点亮的独立指示灯 LED 可以改为跟随背光。配置方式——用BACKLIGHT_PINS取代BACKLIGHT_PIN#define BACKLIGHT_PINS { F5, B2 }该宏在 backlight_driver_common.c 中被解析为pin_t数组并通过FOR_EACH_LED宏遍历控制若未显式定义BACKLIGHT_LED_COUNT则自动取引脚数量#if defined(BACKLIGHT_PINS) static const pin_t backlight_pins[] BACKLIGHT_PINS; # ifndef BACKLIGHT_LED_COUNT # define BACKLIGHT_LED_COUNT ARRAY_SIZE(backlight_pins) # endif同时注意 backlight_driver_common.c 的编译期保护BACKLIGHT_PIN与BACKLIGHT_PINS必须至少定义一个否则直接报错 Backlight pin/pins not defined. Please configure.。驱动配置Driver Configuration背光驱动在rules.mk中选择合法取值为pwm默认、timer、software和custom。PWM 驱动pwm默认利用单片机硬件的 PWM 输出能力无需 CPU 干预即可维持 PWM 波形是最推荐的驱动BACKLIGHT_DRIVER pwm其 AVR 实现位于 platforms/avr/drivers/backlight_pwm.c通过#if条件编译把引脚映射到对应定时器的比较输出通道OCR 寄存器例如 ATmega32U4 上B5/B6/B7对应 Timer 1、C6对应 Timer 3。Timer 驱动timer与 PWM 驱动类似但不再直接让引脚输出硬件 PWM 信号而是为定时器挂接中断处理函数在中断里按占空比控制引脚开/关。其优点是任意 GPIO 均可使用但会消耗 CPU 中断资源BACKLIGHT_DRIVER timerAVR 实现见 platforms/avr/drivers/backlight_timer.c。Software 驱动software在这种模式下PWM 在运行其他键盘任务的同时被模拟出来。它提供最大的硬件兼容性无需额外平台配置。代价是不支持呼吸效果且当键盘繁忙时背光可能出现闪烁BACKLIGHT_DRIVER softwareCustom 驱动custom如果以上驱动都不适用于你的板子例如使用独立 IC 控制背光可以实现自定义驱动。启用方式BACKLIGHT_DRIVER custom然后实现如下简单 API 即可三个函数均为可选其中backlight_init_ports、backlight_set、backlight_task在 backlight.c 中提供了弱符号空实现覆写即可生效void backlight_init_ports(void) { // 可选 - 启动时运行 // 通常在这里配置引脚 } void backlight_set(uint8_t level) { // 可选 - 亮度档位变化时运行 // 通常在这里响应新的 level 值 } void backlight_task(void) { // 可选 - 周期性运行 // 注意该函数在主键盘循环中调用 // 若执行耗时操作可能导致性能问题 }AVR 平台配置PWM 驱动支持的引脚下表列出各 AVR MCU 上支持硬件 PWM 输出的背光引脚。只有标注了定时器编号的单元格才具备硬件 PWM 能力其余引脚必须改用timer驱动。背光引脚AT90USB64/128AT90USB162ATmega16/32U4ATmega16/32U2ATmega32AATmega328/PB1Timer 1B2Timer 1B5Timer 1Timer 1B6Timer 1Timer 1B7Timer 1Timer 1Timer 1Timer 1C4Timer 3C5Timer 3Timer 1Timer 1C6Timer 3Timer 1Timer 3Timer 1D4Timer 1D5Timer 1上表与 platforms/avr/drivers/backlight_pwm.c 中的条件编译分支一一对应例如B5/B6/B7在 ATmega16/32U4 上映射到TCCR1A/OCR1A-CTimer 1C6映射到TCCR3A/OCR3ATimer 3。Timer 驱动支持的定时器timer驱动可用任意 GPIO 引脚但需要占用一个硬件定时器AT90USB64/128AT90USB162ATmega16/32U4ATmega16/32U2ATmega32AATmega328/PTimers 1 3Timer 1Timers 1 3Timer 1Timer 1Timer 1以下#define仅对timer驱动生效定义默认值描述BACKLIGHT_PWM_TIMER1使用的定时器编号注意定时器的选择可能与 Audio音频 功能产生冲突两者共用定时器资源时需要统筹规划。ChibiOS/ARM 平台配置PWM 驱动根据 ChibiOS 的板级配置可能需要在键盘层面启用 PWM 外设。对于 STM32在halconf.h与mcuconf.h中做如下配置#pragma once #define HAL_USE_PWM TRUE #include_next halconf.h#pragma once #include_next mcuconf.h #undef STM32_PWM_USE_TIM4 #define STM32_PWM_USE_TIM4 TRUE以下#define仅对pwm驱动生效ARM 实现见 platforms/chibios/drivers/backlight_pwm.c定义默认值描述BACKLIGHT_PWM_DRIVERPWMD4使用的 PWM 驱动BACKLIGHT_PWM_CHANNEL3使用的 PWM 通道BACKLIGHT_PAL_MODE2引脚使用的复用功能AF编号BACKLIGHT_PWM_PERIOD未定义PWM 周期计数器 tick 数默认值取决于平台这些值需参考具体 MCU 的 ST 数据手册确定。例如上述默认值是为Proton-CSTM32F303上的B8引脚使用TIM4_CH3、复用功能 AF2而配置的。除非你自行设计键盘一般不需要修改。Timer 驱动同样地需要在键盘层面启用通用定时器GPT。对于 STM32#pragma once #define HAL_USE_GPT TRUE #include_next halconf.h#pragma once #include_next mcuconf.h #undef STM32_GPT_USE_TIM15 #define STM32_GPT_USE_TIM15 TRUE以下#define仅对timer驱动生效ARM 实现见 platforms/chibios/drivers/backlight_timer.c定义默认值描述BACKLIGHT_GPT_DRIVERGPTD15使用的定时器典型驱动电路示例原理图说明MCU 的 GPIO 引脚能够提供的电流非常有限因此背光通常不能由 MCU 直接供电而是由背光引脚控制一个三极管或 MOSFET 来切换 LED 的电源。典型接法所有背光 LED 并联后接到N 沟道 MOSFET其栅极通过一个470Ω 电阻连接到 MCU 的某个 GPIO 引脚用于抑制振铃同时在栅极与地之间放置一个下拉电阻使引脚未被 MCU 驱动时保持确定的关断状态。上述电阻的具体取值并不苛刻可按常规工程经验选取。背光 API 参考以下 API 全部声明于 quantum/backlight/backlight.h实现在 quantum/backlight/backlight.c可在自定义键码、宏或 自定义量子函数 中直接调用。基础控制void backlight_toggle(void)—— 切换背光开/关实现见 backlight.c本质是依据当前状态调用backlight_enable()或backlight_disable()。void backlight_enable(void)—— 打开背光。若当前enable已为真则直接返回若已启用但level 0会自动把档位置为 1见 backlight.c。void backlight_disable(void)—— 关闭背光内部调用backlight_set(0)见 backlight.c。void backlight_step(void)—— 循环切换亮度档位0 → 1 → … →BACKLIGHT_LEVELS→ 0。void backlight_increase(void)—— 提高一档亮度若已达到BACKLIGHT_LEVELS则保持不变同时将enable置为 1。void backlight_decrease(void)—— 降低一档亮度降到 0 时自动关闭背光enable !!level。void backlight_level(uint8_t level)—— 设置指定亮度档位范围 0 到BACKLIGHT_LEVELS并写回 EEPROM。另有不写 EEPROM 的backlight_level_noeeprom(uint8_t level)版本见 backlight.c两者都会先做越界钳制。状态查询uint8_t get_backlight_level(void)—— 获取当前亮度档位。返回值当前档位范围 0 到BACKLIGHT_LEVELS。bool is_backlight_enabled(void)—— 获取背光当前是否开启。返回值开启返回true。呼吸模式需启用BACKLIGHT_BREATHING以下 API 仅在config.h中定义BACKLIGHT_BREATHING后才可用void backlight_toggle_breathing(void)—— 切换呼吸模式开/关。void backlight_enable_breathing(void)—— 开启呼吸模式。void backlight_disable_breathing(void)—— 关闭呼吸模式。bool is_backlight_breathing(void)—— 获取呼吸模式状态。返回值呼吸开启返回true。呼吸相关状态同样持久化到 EEPROM并由 backlight.c 中标记为__attribute__((weak))的breathing_period_set、breathing_period_inc、breathing_period_dec、breathing_toggle等辅助函数支持运行时调整呼吸周期。关键源码路径速查内容路径背光核心逻辑与 APIquantum/backlight/backlight.c背光配置结构与声明quantum/backlight/backlight.h引脚初始化与开关含多引脚支持quantum/backlight/backlight_driver_common.c按键码处理quantum/process_keycode/process_backlight.c按键码定义与别名quantum/keycodes.hAVR PWM 驱动platforms/avr/drivers/backlight_pwm.cAVR Timer 驱动platforms/avr/drivers/backlight_timer.cChibiOS/ARM PWM 驱动platforms/chibios/drivers/backlight_pwm.cChibiOS/ARM Timer 驱动platforms/chibios/drivers/backlight_timer.c总结背光功能是 QMK 中最实用的特性之一先在rules.mk中通过BACKLIGHT_ENABLE yes启用再按硬件电路在config.h中配置引脚、档位数量与电平极性最后根据 MCU 平台从pwm、timer、software、custom四种驱动中选择合适者。理解了 PWM 占空比调光原理、AVR/ARM 的定时器资源约束以及按键码到 API 的调用链你就能在任意 QMK 键盘上稳定地实现可调亮度、多引脚联动与呼吸效果。【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表