如何通过C# WinForms控制Arduino UNO实现鼠标光标移动模拟?
Arduino UNO模拟鼠标 + WinForms C#控制实现方案
前提说明
Arduino UNO主芯片(ATmega328P)无原生USB控制器,无法直接使用官方Mouse库(该库适用于Leonardo/Micro等带原生USB的板子),需通过V-USB库模拟USB HID设备实现鼠标功能。
Arduino UNO端实现
1. 准备工作
- 安装V-USB库:在Arduino IDE的库管理器中搜索"V-USB"并安装,或手动下载源码导入。
- 硬件接线:将UNO的D2引脚接USB D-,D3引脚接USB D+,同时在D+引脚和VCC之间接一个1.5kΩ电阻(具体接线参考V-USB官方文档)。
2. 示例代码
该代码实现串口接收坐标指令、计算相对位移并发送HID鼠标报告:
#include "usbdrv.h" // HID报告描述符,定义鼠标设备 PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xc0, // END_COLLECTION 0xc0 // END_COLLECTION }; static uchar reportBuffer[4]; // 鼠标报告:按键状态 + X/Y位移 void buildReport(char xDelta, char yDelta) { reportBuffer[0] = 0; // 无按键按下 reportBuffer[1] = xDelta; reportBuffer[2] = yDelta; } usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (usbRequest_t *)data; if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ if(rq->bRequest == USBRQ_HID_GET_REPORT){ usbMsgPtr = reportBuffer; return sizeof(reportBuffer); } } return 0; } int currentX = 0; int currentY = 0; void setup() { usbInit(); usbDeviceDisconnect(); delay(250); usbDeviceConnect(); Serial.begin(9600); // 开启串口接收C#指令 } void loop() { usbPoll(); if (Serial.available() > 0) { String data = Serial.readStringUntil('\n'); int commaIdx = data.indexOf(','); if (commaIdx != -1) { int targetX = data.substring(0, commaIdx).toInt(); int targetY = data.substring(commaIdx + 1).toInt(); // 限制位移在HID允许的范围(-127~127) char deltaX = constrain(targetX - currentX, -127, 127); char deltaY = constrain(targetY - currentY, -127, 127); buildReport(deltaX, deltaY); usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); currentX = targetX; currentY = targetY; delay(10); } } }
C# WinForms端实现
1. 核心依赖
使用.NET自带的System.IO.Ports库操作串口,无需额外安装。
2. 示例代码
创建WinForms项目,添加两个文本框(输入X/Y坐标)和一个发送按钮,代码如下:
using System; using System.IO.Ports; using System.Windows.Forms; namespace ArduinoMouseControl { public partial class MainForm : Form { private readonly SerialPort _serialPort; public MainForm() { InitializeComponent(); // 替换为你的Arduino COM端口号 _serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One); try { _serialPort.Open(); } catch (Exception ex) { MessageBox.Show($"串口打开失败:{ex.Message}"); } } private void btnSendCoords_Click(object sender, EventArgs e) { if (!_serialPort.IsOpen) { MessageBox.Show("串口未连接"); return; } if (int.TryParse(txtXCoord.Text, out int targetX) && int.TryParse(txtYCoord.Text, out int targetY)) { _serialPort.WriteLine($"{targetX},{targetY}"); } else { MessageBox.Show("请输入有效的整数坐标"); } } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { if (_serialPort.IsOpen) _serialPort.Close(); } } }
注意:需在设备管理器中查看Arduino对应的COM端口,替换代码中的COM3。
所需库汇总
- Arduino端:
- V-USB:用于UNO模拟USB HID设备;若使用Leonardo/Micro,直接用官方
Mouse库即可。
- V-USB:用于UNO模拟USB HID设备;若使用Leonardo/Micro,直接用官方
- C#端:
- System.IO.Ports:.NET内置串口操作库。
资料获取渠道
- Arduino官方文档:查阅HID设备开发规范、V-USB库的接线与使用说明。
- Arduino社区:搜索"UNO USB HID mouse"获取实操案例与问题排查方案。
- .NET官方文档:查看
SerialPort类的API细节,掌握串口读写的最佳实践。 - 开源代码仓库:参考已有的Arduino鼠标模拟项目和C#串口控制项目,完善实现逻辑。
内容的提问来源于stack exchange,提问作者Dobroslav
相关产品推荐
相关产品推荐

