Arduino Uno PS/2转USB仅在串口监视器可用,如何实现HID键盘功能?
解决方案:将Arduino Uno配置为HID键盘以支持PS/2键盘
核心限制说明
Arduino Uno的USB接口由独立串口芯片(如ATmega16U2/8U2或CH340)提供,默认固件仅支持USB转串口通信,因此只能在Arduino IDE串口监视器中接收输入,无法直接模拟HID键盘设备。要实现Windows应用通用的键盘功能,需要通过以下方案改造:
方案1:重刷ATmega16U2固件(针对带ATmega16U2/8U2的Uno)
如果你的Uno采用ATmega16U2/8U2作为USB转串口芯片,可以重刷其固件,让它同时支持HID键盘模拟与串口功能:
- 准备工具:Arduino IDE、杜邦线
- 操作步骤:
- 将Uno连接电脑,在Arduino IDE中选择对应板型与端口。
- 短接Uno靠近USB口的
RESET与GND引脚1秒后断开,使ATmega16U2进入DFU模式。 - 使用
dfu-programmer工具刷入HID键盘固件(可使用Arduino官方适配的HID兼容固件)。 - 刷写完成后,电脑会将Uno识别为HID键盘设备。
方案2:V-USB库软件模拟HID(适配所有Uno,推荐初学尝试)
无需修改USB芯片固件,通过V-USB库在ATmega328P上软件模拟USB HID,结合你已使用的PS2Keyboard库读取按键信号并转换为HID报告发送:
操作步骤:
- 在Arduino IDE库管理器中搜索并安装
V-USB库。 - 按PS2Keyboard库规范接线:PS/2键盘的
CLK接Uno D3、DATA接D2、VCC接5V、GND接GND(注意避开V-USB占用的引脚,可按需调整库引脚定义)。 - 编写适配代码(框架示例):
#include <ps2.h> #include <usbdrv.h> #define PS2_CLK 3 #define PS2_DATA 2 PS2Keyboard keyboard; // HID报告描述符 PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { 0x05, 0x01, // 用途页:通用桌面设备 0x09, 0x06, // 用途:键盘 0xa1, 0x01, // 集合:应用层 0x05, 0x07, // 用途页:键盘 0x19, 0xe0, // 用途最小值:左Ctrl 0x29, 0xe7, // 用途最大值:右GUI 0x15, 0x00, // 逻辑最小值:0 0x25, 0x01, // 逻辑最大值:1 0x75, 0x01, // 报告大小:1位 0x95, 0x08, // 报告数量:8 0x81, 0x02, // 输入:数据、变量、绝对 0x95, 0x01, // 报告数量:1 0x75, 0x08, // 报告大小:8位 0x81, 0x03, // 输入:常量、变量、绝对 0x95, 0x06, // 报告数量:6 0x75, 0x08, // 报告大小:8位 0x15, 0x00, // 逻辑最小值:0 0x25, 0x65, // 逻辑最大值:101 0x05, 0x07, // 用途页:键盘 0x19, 0x00, // 用途最小值:保留位 0x29, 0x65, // 用途最大值:应用键 0x81, 0x00, // 输入:数据、数组 0xc0 // 结束集合 }; uint8_t reportBuffer[8] = {0}; void sendReport() { usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); } // PS/2扫描码转HID扫描码映射(需补充全按键) uint8_t ps2ToHid(uint8_t ps2Code) { switch(ps2Code) { case 0x1C: return 0x04; // A case 0x32: return 0x05; // B case 0x21: return 0x06; // C // 其他按键映射请自行补充 default: return 0; } } void setup() { keyboard.begin(PS2_CLK, PS2_DATA); usbInit(); usbDeviceDisconnect(); delay(250); usbDeviceConnect(); } void loop() { usbPoll(); if (keyboard.available()) { uint8_t code = keyboard.read(); if (code == 0xF0) { // 处理按键释放 uint8_t keyCode = keyboard.read(); uint8_t hidCode = ps2ToHid(keyCode); for (int i=2; i<8; i++) { if (reportBuffer[i] == hidCode) { reportBuffer[i] = 0; break; } } } else { // 处理按键按下 uint8_t hidCode = ps2ToHid(code); if (hidCode != 0) { for (int i=2; i<8; i++) { if (reportBuffer[i] == 0) { reportBuffer[i] = hidCode; break; } } } } sendReport(); } }
注意事项:
- 需完整补充PS/2与HID扫描码的映射关系,可参考通用扫描码对照表完善。
- V-USB对引脚有特定要求,若PS/2接线冲突,可修改库中引脚定义。
方案3:更换原生USB Arduino板(最简方案)
如果不想折腾固件或软件模拟,直接更换为Arduino Leonardo、Micro或Nano Every这类主芯片带原生USB功能的板卡。这类板可直接使用官方Keyboard库,配合PS2Keyboard库快速实现功能:
示例代码:
#include <PS2Keyboard.h> #define PS2_CLK 3 #define PS2_DATA 2 PS2Keyboard keyboard; void setup() { keyboard.begin(PS2_CLK, PS2_DATA); Keyboard.begin(); } void loop() { if (keyboard.available()) { char c = keyboard.read(); if (c != 0) { Keyboard.print(c); } } }
内容的提问来源于stack exchange,提问作者Khabarkhaan
相关产品推荐
相关产品推荐

