如何使用Multimedia Timer替代Thread.Sleep实现串口通信非周期性高精度延时
串口单次高精度延时实现方案
调整AccurateTimer实现单次高精度延时
你只需要对现有封装类做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
相关产品推荐
相关产品推荐

