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

C# UDP与Arduino通信异常:程序冻结、接收无响应问题求助

问题解决:C#与Arduino UDP通信冻结及接收失效问题

问题根源

  1. 程序冻结:原代码同步执行UDP操作,无超时机制,无响应时阻塞UI线程;异步方法调用未正确使用await,导致线程混乱
  2. 接收失效:接收消息时未切换到UI线程更新控件,UDP客户端实例复用不当;Arduino引脚模式设置错误,导致按钮状态判断逻辑异常

解决方案(持续监听+随时发送模式)

1. 修复C#端代码

以下代码实现异步收发,避免UI冻结,确保消息接收正常:

using System.Net;
using System.Net.Sockets;
using System.Text;

namespace control_drone
{
    public partial class Form1 : Form
    {
        private UdpClient? _udpListener;
        private readonly IPEndPoint _arduinoEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.126"), 1234);
        private CancellationTokenSource? _listenTokenSource;

        public Form1()
        {
            InitializeComponent();
            StartUdpListening();
        }

        // 后台异步启动UDP监听
        private async void StartUdpListening()
        {
            _listenTokenSource = new CancellationTokenSource();
            _udpListener = new UdpClient(1234);
            try
            {
                while (!_listenTokenSource.Token.IsCancellationRequested)
                {
                    var receivedResult = await _udpListener.ReceiveAsync(_listenTokenSource.Token);
                    string text = Encoding.ASCII.GetString(receivedResult.Buffer);
                    // 切换到UI线程更新控件
                    this.Invoke(() => this.Text = text);
                }
            }
            catch (OperationCanceledException) { }
            catch (Exception ex)
            {
                MessageBox.Show($"监听出错: {ex.Message}");
            }
            finally
            {
                _udpListener?.Close();
            }
        }

        // 异步发送消息,带超时处理
        public async Task SendMessageAsync(string textToSend)
        {
            using var sendingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            sendingSocket.SendTimeout = 200; // 设置200ms超时,避免无响应阻塞
            byte[] sendBuffer = Encoding.ASCII.GetBytes(textToSend);
            try
            {
                await sendingSocket.SendToAsync(sendBuffer, SocketFlags.None, _arduinoEndPoint);
            }
            catch (SocketException ex)
            {
                MessageBox.Show($"发送失败: {ex.Message}");
            }
        }

        // 窗体关闭时停止监听
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _listenTokenSource?.Cancel();
        }

        // 按钮点击事件改为异步调用
        private async void D1H_Click(object sender, EventArgs e) => await SendMessageAsync("Yellow hovering");
        private async void D1RTH_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERPR");
        private async void D2H_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERYH");
        private async void D2RTH_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERYR");
        private async void D3H_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERGH");
        private async void D3RTH_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERGR");
        private async void D4H_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERWH");
        private async void D4RTH_Click(object sender, EventArgs e) => await SendMessageAsync("COMPUTERWR");

        private void Green(object sender, PaintEventArgs e) => splitContainer1.Panel2.BackColor = Color.AliceBlue;
        private void split2_panel1_new_colour(object sender, PaintEventArgs e) => splitContainer2.Panel2.BackColor = Color.Blue;
        private void split2_panel2_new_colour(object sender, PaintEventArgs e) { }
    }
}

2. 修正Arduino端代码

修复引脚模式错误,调整按钮状态判断逻辑:

#include "WiFi.h"
#include "AsyncUDP.h"

const char *ssid =  "你的WiFi名称";
const char *password = "你的WiFi密码";

const int button1 = 3;
const int button2 = 2;
const int relay = 9;

AsyncUDP udp;

void setup() {
  // 修正引脚模式:按钮设为输入上拉,继电器设为输出
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(relay, OUTPUT);

  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed");
    while (1) delay(1000);
  }
  if (udp.listen(1234)) {
    Serial.print("UDP Listening on IP: ");
    Serial.println(WiFi.localIP());
    udp.onPacket([](AsyncUDPPacket packet) {
      Serial.print("Received: ");
      Serial.write(packet.data(), packet.length());
      Serial.println();

      int state1 = digitalRead(button1);
      int state2 = digitalRead(button2);
      String response;

      // INPUT_PULLUP模式下,按钮按下时引脚为LOW
      if (state1 == LOW && state2 == HIGH) {
        response = "first side is pressed";
      } else if (state2 == LOW && state1 == HIGH) {
        response = "button number 2";
      } else {
        response = "No button pressed";
      }

      // 回复客户端
      packet.print(response);
    });
  }
}

void loop() {
  delay(1000);
  Serial.println("Running...");
}

关键修改说明

  • C#端:异步执行UDP收发,设置发送超时避免冻结;用Invoke确保UI更新在主线程;窗体关闭时释放监听资源
  • Arduino端:修正按钮引脚模式,调整状态判断逻辑(适配INPUT_PULLUP特性);增加串口打印方便调试

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 22:14:52