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

如何使用Multimedia Timer替代Thread.Sleep实现串口通信非周期性高精度延时

串口单次高精度延时实现方案

调整AccurateTimer实现单次高精度延时

你只需要对现有封装类做2处核心修改即可实现单次触发能力:

  1. 新增单次触发常量,替换原有事件类型参数
  2. 回调执行完成后自动销毁定时器,避免资源泄漏

修改后的完整代码如下:

// AccurateTimer.cs 单次触发版本
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace YourProjectsNamespace
{
    class AccurateTimer
    {
        private delegate void TimerEventDel(int id, int msg, IntPtr user, int dw1, int dw2);
        // 新增单次触发常量
        private const int TIME_ONESHOT = 0;
        private const int TIME_PERIODIC = 1;
        // 事件类型改为单次触发
        private const int EVENT_TYPE = TIME_ONESHOT;
        [DllImport("winmm.dll")]
        private static extern int timeBeginPeriod(int msec);
        [DllImport("winmm.dll")]
        private static extern int timeEndPeriod(int msec);
        [DllImport("winmm.dll")]
        private static extern int timeSetEvent(int delay, int resolution, TimerEventDel handler, IntPtr user, int eventType);
        [DllImport("winmm.dll")]
        private static extern int timeKillEvent(int id);

        Action mAction;
        Form mForm;
        private int mTimerId;
        private TimerEventDel mHandler;  // 注意:需声明为类成员避免GC回收

        public AccurateTimer(Form form,Action action,int delay)
        {
            mAction = action;
            mForm = form;
            timeBeginPeriod(1);
            mHandler = new TimerEventDel(TimerCallback);
            mTimerId = timeSetEvent(delay, 0, mHandler, IntPtr.Zero, EVENT_TYPE);
        }

        public void Stop()
        {
            if (mTimerId != 0)
            {
                timeKillEvent(mTimerId);
                mTimerId = 0;
                timeEndPeriod(1);
                System.Threading.Thread.Sleep(1);// 避免残留回调触发
            }
        }

        private void TimerCallback(int id, int msg, IntPtr user, int dw1, int dw2)
        {
            if (mTimerId != 0)
            {
                mForm.BeginInvoke(mAction);
                // 单次触发完成后自动停止定时器
                Stop();
            }
        }
    }
}

业务代码调用示例

替换你原有enableRemoteMode方法中的Thread.Sleep部分即可:

private void enableRemoteMode()
{
    if (serialPort2.IsOpen)
    {
        byte[] byteRemoteEnable = new byte[] { 0xAA, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB};

        serialPort2.Write(byteRemoteEnable, 0, 26);
        // 单次高精度延时55ms后执行读取逻辑
        _ = new AccurateTimer(this, () => 
        {
            byte[] buffer = new byte[26];
            serialPort2.Read(buffer, 0, 26);
            dataIn2 = BitConverter.ToString(buffer);
            Debug.WriteLine("");
            Debug.WriteLine("");
            Debug.WriteLine("Debug: Enable Remote Mode Command Response Packet");
            Debug.WriteLine(dataIn2);
        }, 55);
    }
}

更适配串口场景的优化建议

你后续发现的FIFO缓冲区机制完全正确,针对串口通信场景,还有比高精度延时更稳定的写法,完全不需要依赖定时精度:

serialPort2.Write(byteRemoteEnable, 0, 26);
// 等待缓冲区收到完整26字节再读取,超时时间可自行设置
int timeout = 200;
var start = Environment.TickCount;
while(serialPort2.BytesToRead < 26 && Environment.TickCount - start < timeout)
{
    Thread.Sleep(1);
}
if (serialPort2.BytesToRead >= 26)
{
    byte[] buffer = new byte[26];
    serialPort2.Read(buffer, 0, 26);
    // 后续业务逻辑
}
else
{
    // 超时异常处理
}

这种写法可以兼容设备响应延迟波动的场景,稳定性远高于固定延时方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 15:39:04