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

C#中如何用Async/Await等待步进电机运动结束的状态变化

解决方案:用TaskCompletionSource实现异步等待电机停止

你的轮询方案虽用了await Task.Delay(1),但本质还是高频检查变量状态,会占用不必要的CPU资源,且不够优雅。更好的方式是用TaskCompletionSource<T>创建可等待任务,当Arduino返回停止信号时主动完成任务,实现真正的异步等待。

修改步骤:

  1. 添加TaskCompletionSource字段
    在窗体类中声明对象跟踪电机运动的完成状态:
private TaskCompletionSource<bool> _motorCompletionTcs;
  1. 修改MoveTheMotor方法
    每次启动电机时重置任务源,确保每次运动对应独立的等待任务:
public void MoveTheMotor(int position)
{
    // 重置任务源,避免之前的任务影响当前操作
    _motorCompletionTcs = new TaskCompletionSource<bool>();
    
    int command = 1000;
    int movement = command + position;
    string com1 = movement.ToString();
    port.Write(com1 + "\n");
    movementFinished = false;
}
  1. 更新Reply方法
    收到Arduino的停止信号(MF1)时,完成任务源:
private void Reply(object sender, EventArgs e)
{
    rispos = rispos.Trim();
    // 先检查字符串长度,避免索引越界
    if (rispos.Length >= 3 && rispos[0] == 'M' && rispos[1] == 'F' && rispos[2] == '1')
    {
        movementFinished = true;
        // 安全标记任务完成,避免重复调用
        _motorCompletionTcs?.TrySetResult(true);
    }
}
  1. 优化Demo方法
    移除轮询逻辑,直接等待任务源的Task完成:
private async void Demo()
{
    MoveTheMotor(800);
    
    try
    {
        // 异步等待电机完成,不会阻塞UI线程
        await _motorCompletionTcs.Task;
        
        // 电机停止后执行后续操作
        // 示例:更新UI、记录日志等
        MessageBox.Show("电机运动已完成");
    }
    catch (Exception ex)
    {
        // 处理异常(比如串口断开、超时等)
        MessageBox.Show($"运动过程中出现错误:{ex.Message}");
    }
}

额外优化建议:

  • 添加超时处理:防止Arduino无响应导致程序一直等待,用Task.WhenAny实现超时:
private async void Demo()
{
    MoveTheMotor(800);
    
    var timeoutTask = Task.Delay(10000); // 10秒超时
    var completedTask = await Task.WhenAny(_motorCompletionTcs.Task, timeoutTask);
    
    if (completedTask == _motorCompletionTcs.Task)
    {
        // 正常完成
        MessageBox.Show("电机运动已完成");
    }
    else
    {
        // 超时处理
        MessageBox.Show("电机运动超时");
        _motorCompletionTcs.TrySetCanceled(); // 清理任务源
    }
}
  • 处理串口异常:在risposta方法中捕获串口操作异常,避免程序崩溃并通知任务源:
private void risposta(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        riceved = port.ReadLine();
        rispos = riceved;
        this.Invoke(new EventHandler(Reply));
    }
    catch (Exception ex)
    {
        // 将异常传递给等待的任务
        _motorCompletionTcs?.TrySetException(ex);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 22:25:17