You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Digispark(类Arduino)上检测F15按键是否被按住

解决Digispark检测主机按键状态的问题

首先得明确一个关键限制:Digispark作为USB HID从设备(模拟键盘/鼠标),它只能向主机发送按键/鼠标事件,没办法主动读取主机上的按键状态——USB HID的基础通信是单向的(设备→主机),除非你把它配置成支持双向通信的自定义HID设备。你想用F15作为程序运行的状态标识,这个思路本身没法直接实现,因为Digispark根本“看不到”主机上F15的按下状态。

不过没关系,我们有两个可行的替代方案,既能满足你的需求,又不需要复杂的硬件改动:


方案1:自定义双向HID通信(推荐,最可靠)

这个方案让Digispark支持接收来自C#程序的状态指令,彻底解决通信问题:

步骤1:修改Digispark的USB固件

你需要修改Digispark的USB描述符,让它支持自定义HID报告(实现双向通信)。找到Digispark核心库的usbconfig.h文件,替换HID报告描述符为:

#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 34
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
    0x06, 0x00, 0xFF,  // 自定义厂商使用页
    0x09, 0x01,        // 自定义使用项
    0xA1, 0x01,        // 应用集合
    0x15, 0x00,        // 逻辑最小值0
    0x26, 0xFF, 0x00,  // 逻辑最大值255
    0x75, 0x08,        // 报告长度8位
    0x95, 0x01,        // 报告数量1
    0x09, 0x01,        // 自定义使用项
    0x81, 0x02,        // 输入(数据、可变、绝对)
    0x09, 0x01,        // 自定义使用项
    0x91, 0x02,        // 输出(数据、可变、绝对)
    0xC0               // 结束集合
};

步骤2:Digispark端代码

这段代码会监听来自C#程序的状态指令,根据指令切换旋转编码器的功能:

#include <DigiKeyboard.h>

// 旋转编码器引脚(根据你的接线调整)
#define ENC_A 2
#define ENC_B 3

bool programRunning = false;
int lastEncA = HIGH;

void setup() {
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  lastEncA = digitalRead(ENC_A);
}

void loop() {
  DigiKeyboard.update(); // 必须调用,才能接收主机的HID报告
  
  // 读取C#程序发送的状态(0x01=程序运行,0x00=未运行)
  uint8_t status = DigiKeyboard.getHIDReport(0);
  programRunning = (status == 0x01);
  
  // 处理旋转编码器
  int currentEncA = digitalRead(ENC_A);
  if (currentEncA != lastEncA) {
    if (digitalRead(ENC_B) != currentEncA) {
      // 顺时针旋转
      if (programRunning) {
        DigiKeyboard.sendKeyStroke(KEY_F13);
      } else {
        DigiKeyboard.sendKeyStroke(0, MODIFIERKEY_NONE, MEDIA_VOLUME_UP);
      }
    } else {
      // 逆时针旋转
      if (programRunning) {
        DigiKeyboard.sendKeyStroke(KEY_F14);
      } else {
        DigiKeyboard.sendKeyStroke(0, MODIFIERKEY_NONE, MEDIA_VOLUME_DOWN);
      }
    }
    lastEncA = currentEncA;
  }
  
  delay(20); // 防抖
}

步骤3:C#程序端代码

用HidLibrary库(NuGet可以安装)向Digispark发送状态指令:

using HidLibrary;
using System.Linq;

class VolumeControllerBridge
{
    static void Main(string[] args)
    {
        // 匹配Digispark的VID和PID(默认是0x16C0和0x05DF)
        var digispark = HidDevices.Enumerate(0x16C0, 0x05DF).FirstOrDefault();
        
        if (digispark == null)
        {
            System.Console.WriteLine("未找到Digispark设备!");
            return;
        }

        digispark.Open();
        System.Console.WriteLine("程序已运行,按任意键退出...");

        // 发送"程序运行"状态
        byte[] report = new byte[2]; // 第一个字节是报告ID,固定为0
        report[1] = 0x01;
        digispark.Write(report);

        System.Console.ReadKey();

        // 发送"程序退出"状态
        report[1] = 0x00;
        digispark.Write(report);

        digispark.Close();
    }
}

方案2:利用键盘LED状态(无需修改固件,简单快速)

如果不想折腾自定义HID,可以用主机的键盘LED(比如Caps Lock)作为状态标识:

  • C#程序运行时,自动开启Caps Lock;退出时关闭。
  • Digispark通过读取Caps Lock的LED状态,判断程序是否在运行。

Digispark端代码

#include <DigiKeyboard.h>

#define ENC_A 2
#define ENC_B 3

bool programRunning = false;
int lastEncA = HIGH;

void setup() {
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  lastEncA = digitalRead(ENC_A);
}

void loop() {
  DigiKeyboard.update();
  
  // 读取Caps Lock LED状态(0x02对应Caps Lock)
  programRunning = (DigiKeyboard.getLEDs() & 0x02) != 0;
  
  // 旋转编码器处理逻辑
  int currentEncA = digitalRead(ENC_A);
  if (currentEncA != lastEncA) {
    if (digitalRead(ENC_B) != currentEncA) {
      programRunning ? DigiKeyboard.sendKeyStroke(KEY_F13) : DigiKeyboard.sendKeyStroke(0, MODIFIERKEY_NONE, MEDIA_VOLUME_UP);
    } else {
      programRunning ? DigiKeyboard.sendKeyStroke(KEY_F14) : DigiKeyboard.sendKeyStroke(0, MODIFIERKEY_NONE, MEDIA_VOLUME_DOWN);
    }
    lastEncA = currentEncA;
  }
  
  delay(20);
}

C#程序端代码

using System.Windows.Forms; // 需要引用System.Windows.Forms

class VolumeControllerBridge
{
    static void Main(string[] args)
    {
        bool originalCapsState = Control.IsKeyLocked(Keys.CapsLock);
        
        // 开启Caps Lock作为状态标识
        if (!originalCapsState)
        {
            SendKeys.SendWait("{CAPSLOCK}");
        }

        System.Console.WriteLine("程序已运行,按任意键退出...");
        System.Console.ReadKey();

        // 恢复原始Caps Lock状态
        if (!originalCapsState)
        {
            SendKeys.SendWait("{CAPSLOCK}");
        }
    }
}

注意事项

  • 方案1需要重新上传Digispark固件,可能需要重新安装驱动,但通信最可靠,不会影响用户的日常操作。
  • 方案2简单,但会占用Caps Lock,可能会给用户带来小困扰,适合临时测试或个人使用。
  • 旋转编码器的防抖逻辑可以根据实际情况调整延迟时间。

内容的提问来源于stack exchange,提问作者SenaCarbtc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:24:06