尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

QMK Firmware ADC 驱动实战指南:在键盘中读取电位器、电池电压与 RP2040 温度传感器

发布时间:2026/9/13 17:14:03

资讯中心
01
ARTICLE

QMK Firmware ADC 驱动实战指南:在键盘中读取电位器、电池电压与 RP2040 温度传感器

QMK Firmware ADC 驱动实战指南:在键盘中读取电位器、电池电压与 RP2040 温度传感器
QMK Firmware ADC 驱动实战指南在键盘中读取电位器、电池电压与 RP2040 温度传感器【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmwareQMK 固件在支持 ADC模数转换器的 MCU 上提供了一套统一的analog.h抽象接口让键盘开发者可以像调用数字引脚一样读取模拟引脚电压。本篇指南基于 QMK 仓库的 ADC 驱动文档 与platforms/avr/drivers/analog.c、platforms/chibios/drivers/analog.c 等源码实现完整覆盖如何在rules.mk中启用驱动、AVR/STM32/RP2040 各系列的引脚-通道映射表、analogReadPin()等 API 的精确行为以及 ARM 平台 5 个可调#define的底层解析逻辑。读完后你可以在自己的 QMK 键盘/键位代码中实现电位器音量旋钮、滑条 MIDI 控制、蓝牙键盘电量指示等典型的模拟量功能并理解每次采样背后寄存器与 ChibiOS 驱动的调用链。驱动概述能做什么、返回什么QMK 的 ADC 驱动用于测量指定引脚上的电压典型用途包括蓝牙键盘的电池电量指示通过分压电路读取电池电压用电位器实现音量/参数调节作为旋转编码器之外的另一种连续量输入方案读取 RP2040 内置温度传感器、实现电位器滑条如 Keebwerk Nano Slider 键位 中将其映射为 MIDI CC 控制。返回值与参考电压驱动当前同时支持AVR与部分 ARMSTM32 各子系列、RP2040 等设备返回值为10 位整数0–1023在 0V 与 VCC 之间线性映射VCC 通常为AVR 是 5V 或 3.3VARM 一般是 3.3VARM 平台上可以通过若干#define更精细地控制采样率、分辨率、缓冲深度等操作参数见文末“ARM 配置”一节。启用方式rules.mk 头文件在键盘或键位的rules.mk中加入ANALOG_DRIVER_REQUIRED yes然后在你的 C 代码顶部引入#include analog.h从源码结构看这条开关在 builddefs/common_features.mk 中被消费ifeq ($(strip $(ANALOG_DRIVER_REQUIRED)), yes) OPT_DEFS -DHAL_USE_ADCTRUE QUANTUM_LIB_SRC analog.c endif即启用后会做两件事为 ChibiOS 的 HAL 定义HAL_USE_ADCTRUEARM 平台的 ADC 实现依赖 ChibiOS 的 ADC 驱动层并把对应平台的analog.c加入编译源列表。仓库中 AVR 与 ChibiOS 平台各有一份实现platforms/avr/drivers/analog.cplatforms/chibios/drivers/analog.canalog.h头文件按平台选择函数签名两平台保持一致ARM 版多一个analogReadPinAdc()。仓库里已有多块成品键盘使用该开关例如 keyboards/keebwerk/nano_slider/rules.mk、keyboards/drop/ctrl/v2/rules.mk 等可参照它们的目录组织方式。注意ChibiOS 版本在编译期还有硬性检查platforms/chibios/drivers/analog.chalconf.h中必须HAL_USE_ADCTRUE且mcuconf.h中至少有一个xxx_ADC_USE_ADCx为 TRUE另外目前不支持 STM32 ADC Dual Mode定义STM32_ADC_DUAL_MODE会直接编译报错。通道与引脚映射表AVR 通道表ChannelAT90USB64/128ATmega16/32U4ATmega32AATmega328/P0F0F0A0C01F1F1A1C12F2A2C23F3A3C34F4F4A4C45F5F5A5C56F6F6A6*7F7F7A7*8D49D610D711B412B513B6* ATmega328/P 实际还有两个额外的 ADC 通道但 DIP 封装没有对应引脚、也不与任何 GPIO 引脚共享如需使用可以直接调用adc_read()传入原始 mux 值。这段映射在源码中的实现见 platforms/avr/drivers/analog.c 的pinToMux()以 ATmega32U4 为例F0→ADC0mux0、D4→ADC8MUX5、B6→ADC13所有不支持的引脚统一回落到 “0V (GND)” 的 mux 值因此误传引脚不会触发 ADC 转换而是读到接近 0 的值——这正是文档中“unsupported pin returns 0V mux”说法的来源。ARM 通道表STM32注意两点表中一些引脚在多个 ADC 上“复用”同一通道号因为这些引脚可以接给任意一个 ADCF0 与 F3 的通道编号规则不同F0 只有一个 ADC通道从 0 开始编号F3 有 4 个 ADC通道从 1 开始编号。原因是 F0 使用ADCv1硬件实现F3 使用ADCv3。ADCChannelSTM32F0xxSTM32F1xxSTM32F3xxSTM32F4xx10A0A0A011A1A1A0A112A2A2A1A213A3A3A2A314A4A4A3A415A5A5F4A516A6A6C0A617A7A7C1A718B0B0C2B019B1B1C3B1110C0C0F2C0111C1C1C1112C2C2C2113C3C3C3114C4C4C4115C5C5C511620A0¹A0²21A1¹A4A1²22A2¹A5A2²23A3¹A6A3²24A4¹A7A4²25A5¹C4A5²26A6¹C0A6²27A7¹C1A7²28B0¹C2B0²29B1¹C3B1²210C0¹F2C0²211C1¹C5C1²212C2¹B2C2²213C3¹C3²214C4¹C4²215C5¹C5²21630A0¹A0²31A1¹B1A1²32A2¹E9A2²33A3¹E13A3²34F6¹F6²35F7¹B13F7²36F8¹E8F8²37F9¹D10F9²38F10¹D11F10²39D12F3²310C0¹D13C0²311C1¹D14C1²312C2¹B0C2²313C3¹E7C3²314E10F4²315E11F5²316E1241E1442E1543B1244B1445B1546E847D1048D1149D12410D13411D14412D8413D9414415416¹ 截至 ChibiOS 20.3.4STM32F1xx 的 ADC 驱动只支持 ADC1因此涉及 ADC2/ADC3 的配置实际不可用尤其是F6…F10至少存在于部分 STM32F103x[C-G] 设备上因为该驱动限制无法作为 ADC 输入。² 并非所有 STM32F4xx 都有 ADC2 和/或 ADC3因此表中部分配置可能不存在尤其在没有 ADC3 的设备上F4…F10不能用作 ADC 输入。请以器件数据手册为准。这些限制在源码中有对应佐证platforms/chibios/drivers/analog.c 中注释明确写道 “STM32F103x[C-G] in 144-pin packages also have analog inputs on F6...F10, but they are on ADC3, and the ChibiOS ADC driver for STM32F1xx currently supports only ADC1, therefore these pins are not usable.”而 F4 的F3…F10引脚则包在#if STM32_ADC_USE_ADC3条件编译中analog.c只有在mcuconf.h里开启了 ADC3 才会生效。RP2040RP2040 只有一个 ADCChibiOS 中的ADCD1在 QMK API 中其索引为 0ChannelPin0GP261GP272GP283GP294Temperature sensor** 温度传感器默认关闭需要通过 RP2040 专用函数adcRPEnableTS(ADCD1)使能。调用前必须先完成 ADC 初始化——一个简单可靠的办法是先做一次“哑转换”dummy conversion例如先调用一次analogReadPin()。对应实现见 analog.cRP2040 分支将26U/27U/28U/29U这四个 GPIO 编号直接映射为通道 0–3pin_t在 RP2040 上就是裸 GPIO 号。API 函数一览AVRFunctionDescriptionanalogReference(mode)设置模拟电压参考源。取值必须是ADC_REF_EXTERNAL、ADC_REF_POWER或ADC_REF_INTERNAL之一。analogReadPin(pin)读取指定引脚的值例如 ATmega32U4 的 ADC6 就传F6。pinToMux(pin)把引脚翻译为 mux 值。传入不支持的引脚时返回 0V (GND) 的 mux 值。adc_read(mux)按给定 mux 值从 ADC 读取。详见 MCU 数据手册。参考电压常量定义在 platforms/avr/drivers/analog.h#define ADC_REF_EXTERNAL 0 // AREF, Internal Vref turned off #define ADC_REF_POWER _BV(REFS0) // AVCC with external capacitor on AREF pin #define ADC_REF_INTERNAL (_BV(REFS1) | _BV(REFS0)) // Internal 2.56V Voltage Reference with external capacitor on AREF pin (1.1V for 328P)即外部参考AREF 引脚、AVCC 电源参考、内部 2.56V 参考ATmega328P 上是 1.1V。AVR 实现的adc_read()流程analog.c置位ADEN并按F_CPU自动选择分频见 analog.h 的ADC_PRESCALER例如 16MHz 时钟选 /64配置ADHSM高速模式与ADMUX多路选择然后置位ADSC启动转换、轮询等待完成必须先读 ADCL 再读 ADCH10 位结果拼合最后关闭 ADC。整个读取是阻塞式的。ARMFunctionDescriptionanalogReadPin(pin)读取指定引脚的值例如 STM32F0 的A0对应通道 0STM32F3 上对应 ADC1 通道 1。若同一引脚可接多个 ADC本函数固定选择编号较小的那个 ADC。例如C0即使可以接 ADC2也会读 ADC1 通道 6。analogReadPinAdc(pin, adc)读取指定引脚指定 ADC 的值例如C0, 1会读 ADC20-indexed通道 6 而不是 ADC1。pinToMux(pin)把引脚翻译为通道, ADC组合。传入不支持的引脚时返回 0V (GND) 的 mux 值。adc_read(mux)按给定引脚ADC 组合读取。详见 MCU 数据手册。从源码结构看ARM 的 “mux” 是一个adc_mux结构体而非单个整数platforms/chibios/drivers/analog.htypedef struct { uint16_t input; // 通道 uint8_t adc; // ADC 实例编号0-indexed } adc_mux; #define TO_MUX(i, a) (adc_mux) { i, a }调用链为analogReadPin(pin)→palSetLineMode(pin, PAL_MODE_INPUT_ANALOG)把引脚切到模拟输入模式→pinToMux(pin)→adc_read(mux)。其中pinToMux()声明为__attribute__((weak))意味着用户空间可以用自己的实现覆盖它为映射表未收录的引脚/ADC 组合提供逃生通道——仓库示例 keyboards/handwired/onekey/keymaps/adc/keymap.c 末尾就保留了这样的注释模板// adc_mux pinToMux(pin_t pin) { // return TO_MUX(ADC_CHANNEL_IN1, 0); // };adc_read(adc_mux)内部通过intToADCDriver()把 0/1/2/3 索引翻译成 ChibiOS 的ADCD1…ADCD4驱动实例未启用的 ADC 返回 NULL此时adc_read直接返回 0按需调用adcStart()做惰性初始化再用adcConvert()执行单次转换并返回sampleBuffer中的结果。对于ADCv2与 RP2040 的实现实际转换始终按 12 位采样再右移缩放到你请求的ADC_RESOLUTIONanalog.c#if defined(USE_ADCV2) || defined(RP2040) // fake 12-bit - N-bit scale return (sampleBuffer[ADC_DUMMY_CONVERSIONS_AT_START]) (12 - ADC_RESOLUTION); #else // already handled as part of adcConvert return sampleBuffer[ADC_DUMMY_CONVERSIONS_AT_START]; #endifARM 平台高级配置项ARM 版 ADC 实现提供若干可在键盘/键位的rules.mk或源码中覆盖的选项用于改变驱动行为。更详细的选项说明请查阅你所用 MCU 对应的 ChibiOShal_adc_lld.h#defineTypeDefaultDescriptionADC_CIRCULAR_BUFFERboolfalse为true时实现使用环形缓冲。ADC_NUM_CHANNELSint1设置一次 ADC 操作扫描的通道数。当前实现只支持1。ADC_BUFFER_DEPTHint2每个结果的深度。默认 10 位结果需要 2 字节存放一个值如果改用 8 位或更低分辨率可设为 1。ADC_SAMPLING_RATEintADC_SMPR_SMP_1P5ADC 采样率。默认取最快设置。ADC_RESOLUTIONintADC_CFGR1_RES_10BIT或ADC_CFGR_RES_10BITS结果分辨率。默认 10 位可选 12、10、8、6 位。不同 MCU 的分辨率常量命名略有差异。这些默认值在 platforms/chibios/drivers/analog.c 中可以看到完整的解析逻辑值得注意的几个细节ADC_NUM_CHANNELS ! 1会直接触发#error“currently only supports reading one channel at a time”与文档说明一致ADC_SAMPLING_RATE的默认值按硬件代数自动选择优先ADC_SMPR_SMP_1P51.5 周期最快其次是 STM32L4XX/G4XX/WBXX 的ADC_SMPR_SMP_2P5以及 STM32G0XX 的ADC_SMPR1_1P5对 ADCv2 芯片驱动还做了一层“bodge”映射如ADC_SMPR_SMP_1P5 → ADC_SAMPLE_3、ADC_SMPR_SMP_239P5 → ADC_SAMPLE_480统一了 v1/v2/v3/v4 硬件的命名差异ADC_RESOLUTION默认按ADC_CFGR_RES_10BITSADCv3/v4或ADC_CFGR1_RES_10BITADCv1/v5 及 v2 的 bodge 层取值对 v2 硬件则被定义为纯数字 10/12/8/6用于上面的右移缩放另外还有一个文档未展开的隐含行为若启用了STM32_ADCV3_OVERSAMPLING驱动会定义ADC_DUMMY_CONVERSIONS_AT_START 1在每次转换前先做一次丢弃结果的哑转换以规避 STM32L4xx/G4xx/WBxx 等芯片上“校准或前次转换后首次转换结果错误”的 errataanalog.c。实战示例一键采样并输出 ADC 值仓库中 keyboards/handwired/onekey/keymaps/adc 提供了一个最小可运行的 ADC 用法配合 其 rules.mk 里的ANALOG_DRIVER_REQUIRED yes与ADC_PIN定义完整源码如下可作为你自己的电位器/滑条功能模板#include QMK_KEYBOARD_H #include analog.h #include stdio.h enum custom_keycodes { ADC_SAMPLE SAFE_RANGE, }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] { LAYOUT_ortho_1x1(ADC_SAMPLE) }; bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case ADC_SAMPLE: if (record-event.pressed) { int16_t val analogReadPin(ADC_PIN); char buffer[50]; sprintf(buffer, ADC:%u\n, val); #ifdef CONSOLE_ENABLE uprintf(%s, buffer); #else send_string(buffer); #endif } break; } return false; };按下按键时读取ADC_PIN并把结果经串口控制台启用CONSOLE_ENABLE时用uprintf调试打印或作为字符串键入输出方便用硬件回环快速验证引脚接线与分压电路。类似地Keebwerk Nano Slider 的键位把滑条值右移 3 位压缩到 7 位后发送为 MIDI CC 2Data Source展示了 ADC 值与外部控制协议的衔接方式midi_send_cc(midi_device, 2, 0x3E, 0x7F - (analogReadPin(SLIDER_PIN) 3));已知限制与排错清单结合文档与源码使用本驱动前请核对以下前提AVR 平台ADC_REF_INTERNAL内部参考值因芯片而异2.56VATmega328P 为 1.1V若使用内部参考计算电压需注意换算ATmega328/P 的通道 6/7 无 GPIO 引脚只能通过adc_read()直接指定 mux 访问。STM32F1xxChibiOS 驱动仅支持 ADC1涉及 ADC2/ADC3 的引脚如 F103x[C-G] 144 脚封装的F6…F10不可用。STM32F4xx部分型号没有 ADC2/ADC3F3…F10能否作 ADC 输入取决于mcuconf.h中是否开启STM32_ADC_USE_ADC3以及具体型号。Dual Mode 不支持定义STM32_ADC_DUAL_MODE会导致编译失败analog.c。RP2040 温度传感器通道 4 的温感需要显式调用adcRPEnableTS(ADCD1)且需先完成一次 ADC 初始化做一次哑转换即可保证。阻塞式采样两平台的adc_read()都是同步轮询完成适合低频轮询场景如每几毫秒读一次旋钮若需要连续流式采样或更高吞吐需要考虑 ChibiOS ADC 的转换回调能力当前 QMK 封装默认是单次转换模式ADC_NUM_CHANNELS仅支持 1。引脚不在映射表中pinToMux()对未知引脚返回 0V muxadc_read读到接近 0 的值此时应确认引脚定义、mcuconf.h的 ADC 使能项或自行实现 weak 的pinToMux()覆盖默认映射。小结QMK 的 ADC 驱动以极小的 API 面analog.h四五个函数 一个ANALOG_DRIVER_REQUIRED开关覆盖了 AVR 与主流 ARM 系列的模拟量读取需求引脚-通道映射、参考电压、采样率、分辨率均被封装为与数据手册对齐的参数。当你的键盘项目需要电位器音量、滑条输入或电池/温度监测时按本文的启用方式与映射表选对引脚再对照各芯片的已知限制F1 仅 ADC1、F4 的 ADC3 依赖、RP2040 温感使能逐项核对即可在键位代码中以analogReadPin()拿到 0–1023 的稳定采样值并投入实际功能开发。【免费下载链接】qmk_firmwareOpen-source keyboard firmware for Atmel AVR and Arm USB families项目地址: https://gitcode.com/GitHub_Trending/qm/qmk_firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。