目录

无线键盘接收器实战:NRF24L01+ 双模设计,低成本自定义输入设备

想不想自己做一个无线键盘接收器?市面上那些几十块的无线键盘,其实核心就是 NRF24L01+ 模块。今天我们来拆解这个黑盒子,用不到 50 元的成本,做一个支持双模切换的无线键盘接收器——既能当普通键盘用,也能当宏键盘使。

这个项目的灵感来自于我工作室里那堆乱七八糟的线缆。每次切换设备都要拔插 USB,烦得要死。索性自己做一个,还能自定义按键映射,简直不要太爽。

需要准备什么?

物品 型号/规格 价格
主控板 Arduino Pro Micro (ATmega32U4) ¥25
无线模块 NRF24L01+ 2.4GHz ¥8
接收端模块 NRF24L01+ (带 PCB 天线) ¥10
按键开关 机械键盘轴体×6 ¥15
PCB 洞洞板 5×7cm ¥5
USB 数据线 Micro USB ¥5
杜邦线 公对公/母对母 ¥5
*总计*\ ¥73

注意: 接收端建议买带 PCB 天线的版本,信号更稳定。发射端用普通天线就行,反正离得近。

步骤 1:硬件连接

先来看发射端(键盘侧)的接线。ATmega32U4 的 SPI 引脚是固定的,别接错了:

NRF24L01+    →    Arduino Pro Micro
---------------------------------------
VCC          →    3.3V  (千万别接 5V,会烧!)
GND          →    GND
CE           →    D9
CSN          →    D10
SCK          →    D15
MOSI         →    D16
MISO         →    D14
IRQ          →    不接(可选)

⚠️ 踩坑提醒: NRF24L01+ 是 3.3V 器件,Pro Micro 虽然有 3.3V 输出,但电流有限。如果供电不稳,模块会反复重启。建议加个 10μF 电容在 VCC 和 GND 之间。

接收端接线类似,只是 CE 和 CSN 引脚可以换:

NRF24L01+    →    Arduino Pro Micro (接收端)
--------------------------------------------
VCC          →    3.3V
GND          →    GND
CE           →    D8
CSN          →    D9
SCK          →    D15
MOSI         →    D16
MISO         →    D14

步骤 2:安装依赖库

打开 Arduino IDE,安装以下库:

# 通过库管理器搜索安装,或用 CLI
arduino-cli lib install "RF24"
arduino-cli lib install "HID-Project"

或者在 IDE 里:

  1. 工具 → 管理库
  2. 搜索 "RF24",安装 by TMRh20
  3. 搜索 "HID-Project",安装 by NicoHood

原理解析: RF24 库负责 NRF24L01+ 的无线通信,HID-Project 让 Arduino 模拟成 USB 键盘。ATmega32U4 原生支持 USB HID,这是它比 Uno/Nano 更适合这个项目的原因。

步骤 3:发射端代码(键盘侧)

#include 
#include 
#include 
#include 

// 引脚定义
#define CE_PIN  9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);

// 通信管道地址
const uint64_t pipes[2] = {0xF0F0F0F0E7LL, 0xF0F0F0F0D2LL};

// 按键映射(自定义)
struct KeyMapping {
  uint8_t pin;
  HIDKeys key;
  bool lastState;
};

KeyMapping keys[] = {
  {2, KEY_F1, HIGH},   // F1 宏键
  {3, KEY_F2, HIGH},   // F2 宏键
  {4, KEY_F3, HIGH},   // F3 宏键
  {5, KEY_F4, HIGH},   // F4 宏键
  {6, KEY_F5, HIGH},   // F5 宏键
  {7, KEY_F6, HIGH},   // F6 宏键
};

void setup() {
  Serial.begin(115200);

  // 初始化按键引脚
  for (int i = 0; i < 6; i++) {
    pinMode(keys[i].pin, INPUT_PULLUP);
  }

  // 初始化 NRF24L01+
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_2MBPS);
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1, pipes[1]);
  radio.startListening();

  // 发送握手信号
  delay(100);
  radio.stopListening();
  uint8_t handshake = 0xAA;
  radio.write(&handshake, sizeof(handshake));
  radio.startListening();

  Serial.println("发射端就绪");
}

void loop() {
  // 扫描按键
  for (int i = 0; i < 6; i++) {
    bool currentState = digitalRead(keys[i].pin);

    if (currentState != keys[i].lastState) {
      delay(20);  // 消抖
      currentState = digitalRead(keys[i].pin);

      if (currentState == LOW) {
        // 按键按下,发送键值
        radio.stopListening();
        uint8_t packet[2] = {0x01, (uint8_t)keys[i].key};
        radio.write(&packet, sizeof(packet));
        radio.startListening();
        Serial.print("发送按键:");
        Serial.println(keys[i].key);
      }

      keys[i].lastState = currentState;
    }
  }

  delay(10);
}

步骤 4:接收端代码(USB 侧)

#include 
#include 
#include 
#include 

// 引脚定义
#define CE_PIN  8
#define CSN_PIN 9

RF24 radio(CE_PIN, CSN_PIN);

const uint64_t pipes[2] = {0xF0F0F0F0E7LL, 0xF0F0F0F0D2LL};

// 模式切换:0=普通键盘,1=宏键盘
uint8_t mode = 0;
#define MODE_SWITCH_PIN A0

void setup() {
  Serial.begin(115200);
  pinMode(MODE_SWITCH_PIN, INPUT_PULLUP);

  // 初始化 NRF24L01+
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_2MBPS);
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1, pipes[0]);
  radio.startListening();

  // 初始化 USB HID
  BootKeyboard.begin();

  Serial.println("接收端就绪,等待连接...");
}

void loop() {
  // 检查模式切换
  if (digitalRead(MODE_SWITCH_PIN) == LOW) {
    mode = 1 - mode;
    delay(300);  // 防抖
    Serial.print("切换到模式:");
    Serial.println(mode ? "宏键盘" : "普通键盘");
  }

  // 接收无线数据
  if (radio.available()) {
    uint8_t packet[2];
    radio.read(&packet, sizeof(packet));

    if (packet[0] == 0x01) {
      // 按键事件
      HIDKeys key = (HIDKeys)packet[1];

      if (mode == 0) {
        // 普通模式:直接转发
        BootKeyboard.press(key);
        delay(50);
        BootKeyboard.release(key);
      } else {
        // 宏模式:执行预设宏
        executeMacro(key);
      }

      Serial.print("收到按键:");
      Serial.println(key);
    }
  }
}

// 宏定义示例
void executeMacro(HIDKeys key) {
  switch (key) {
    case KEY_F1:
      // Ctrl+C 复制
      BootKeyboard.press(KEY_LEFT_CTRL);
      BootKeyboard.press('c');
      delay(50);
      BootKeyboard.releaseAll();
      break;

    case KEY_F2:
      // Ctrl+V 粘贴
      BootKeyboard.press(KEY_LEFT_CTRL);
      BootKeyboard.press('v');
      delay(50);
      BootKeyboard.releaseAll();
      break;

    case KEY_F3:
      // Alt+Tab 切换窗口
      BootKeyboard.press(KEY_LEFT_ALT);
      BootKeyboard.press(KEY_TAB);
      delay(50);
      BootKeyboard.releaseAll();
      break;

    case KEY_F4:
      // Win+D 显示桌面
      BootKeyboard.press(KEY_LEFT_GUI);
      BootKeyboard.press('d');
      delay(50);
      BootKeyboard.releaseAll();
      break;

    default:
      BootKeyboard.press(key);
      delay(50);
      BootKeyboard.release(key);
  }
}

步骤 5:测试验证

烧录代码后,按以下步骤测试:

  1. 配对测试: 同时给发射端和接收端上电,观察串口输出

    发射端:发射端就绪
    接收端:接收端就绪,等待连接...
    接收端:收到按键:KEY_F1
  2. 距离测试: 在空旷环境下,NRF24L01+ 的有效距离约 50-100 米(带 PCB 天线)。室内隔墙约 10-20 米。

  3. 延迟测试: 用示波器或逻辑分析仪测量按键到 USB 输出的延迟,通常在 5-10ms,完全满足打字需求。

效果展示: 我在工作室测试,发射端放在工作台上,接收端插在客厅的 HTPC 上,隔了两堵墙还能稳定使用。

常见问题排查

问题 1: 接收端收不到数据

  • 原因: 管道地址不匹配或供电不足
  • 解决: 检查 pipes[] 数组在两端是否一致;用万用表测 VCC 是否稳定在 3.3V;加 10μF 电容

问题 2: 电脑识别不到 USB 键盘

  • 原因: ATmega32U4 固件问题或 USB 线质量问题
  • 解决: 换一根能传数据的 USB 线(有些只能充电);重新烧录 Bootloader

问题 3: 按键延迟明显

  • 原因: 无线速率设置过低或消抖时间太长
  • 解决:setDataRate 改为 RF24_2MBPS;消抖时间从 50ms 降到 20ms

问题 4: 宏按键执行多次

  • 原因: 按键消抖逻辑有问题
  • 解决: 确保 lastState 状态机正确更新;在宏执行后加 100ms 延时

进阶玩法

这个项目只是个开始,你可以:

  1. 加 OLED 屏幕: 显示当前模式、电量、信号强度
  2. 加锂电池: 做成真正无线的,加 TP4056 充电模块
  3. 多设备切换: 用拨码开关切换不同接收端,一套键盘控制多台电脑
  4. RGB 灯效: 每个按键加 WS2812B,自定义灯效
  5. 摇杆支持: 加 analog stick,模拟游戏手柄

总结

用 70 块钱的成本,我们做了一个支持双模切换的无线键盘接收器。核心就是 NRF24L01+ 模块 + ATmega32U4 的组合。这个项目最大的价值不在于省钱,而在于完全可控——你想加什么功能就加什么功能,不用看厂商脸色。

我已经在考虑下一代设计了:用 ESP32-C3 做主控,支持 WiFi 和蓝牙双模,还能通过 OTA 更新固件。到时候再和大家分享。

希望这篇博客文章对您有所帮助!


相关资源:

更多关于 的文章
关注创客出手公众号

关注创客出手