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

如何实现Arduino向C#窗体高效传整数以控制电脑鼠标?

解决VR头显串口传输的两个核心问题

问题1:串口字符串转整数失败

原因

  • Arduino发送的内容可能附带多余的回车/换行符,或者串口传输时出现乱码、不完整数据,导致转换时格式错误
  • 直接读取后转换未处理空白字符,也没有异常捕获机制,遇到无效数据直接崩溃

解决方法

  1. Arduino端确保只发送纯整数(避免额外调试输出),Serial.println默认会在整数后添加\r\n,这部分可以保留,但要保证没有其他冗余输出
  2. C#端读取字符串后先调用Trim()去除首尾空白字符(包括\r、\n),再尝试转换,同时添加try-catch捕获转换异常,避免程序崩溃

问题2:窗体卡顿严重

原因

  • 在UI线程的button1_Click事件里写了while(true)死循环,完全阻塞了UI消息队列,导致窗体无法响应任何更新操作
  • 串口读取操作属于IO操作,放在UI线程执行会拖慢整个界面的响应速度

解决方法

  1. 移除UI线程内的死循环,改用SerialPort的DataReceived事件异步处理串口数据,让UI线程专注于界面更新
  2. 控制Arduino的发送频率,避免短时间内发送大量数据导致串口缓存溢出
  3. 跨线程更新UI控件时,必须使用Invoke方法确保线程安全

修正后的C#代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO.Ports;

namespace MoveMouseAuto
{
    public partial class Form1 : Form
    {
        private bool _isRunning = false;
        private Stopwatch _watch = Stopwatch.StartNew();

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool SetCursorPos(int X, int Y);
        private IKeyboardMouseEvents _events;

        public Form1()
        {
            InitializeComponent();
            // 绑定DataReceived事件
            port.DataReceived += Port_DataReceived;
        }

        private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (!_isRunning) return;

            // 控制读取频率,避免频繁处理
            if (_watch.ElapsedMilliseconds < 200) return;

            try
            {
                string rawData = port.ReadLine().Trim();
                if (int.TryParse(rawData, out int potValue))
                {
                    // 跨线程更新UI或控制鼠标
                    Invoke(new Action(() =>
                    {
                        // 示例:更新标签显示数值
                        label1.Text = potValue.ToString();
                        // 移动鼠标
                        SetCursorPos(MousePosition.X + potValue, MousePosition.Y);
                    }));
                }
                _watch.Restart();
            }
            catch (Exception ex)
            {
                // 捕获异常,避免程序崩溃
                Invoke(new Action(() => label1.Text = $"错误: {ex.Message}"));
            }
        }

        private void Subscribe(IKeyboardMouseEvents events)
        {
            _events = events;
        }

        private void Unsubscribe()
        {
            _events?.Dispose();
            _events = null;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Text == "ON")
            {
                button1.Text = "OFF";
                _isRunning = true;
                _watch.Restart();
            }
            else
            {
                button1.Text = "ON";
                _isRunning = false;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                port.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"串口打开失败: {ex.Message}");
            }
            Unsubscribe();
            Subscribe(Hook.GlobalEvents());
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Unsubscribe();
            port.Close();
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
            {
                Close();
                return true;
            }
            return base.ProcessDialogKey(keyData);
        }
    }
}

修正后的Arduino代码

// 定义电位器引脚,根据实际接线修改
const int potPin = A0;
int val;    

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(10);
}

void loop() {
  val = analogRead(potPin) - 500; 
  Serial.println(val);    
  // 控制发送频率,每20ms发送一次,避免串口过载
  delay(20);
}

内容的提问来源于stack exchange,提问作者Joshua B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:48:24