工業現場長期使用 VB/VC/C 串口程式碼,C# 缺乏成熟對應版本。針對 Moxa 設備於 WinCE 5.0 開發,擴充完善串口操作類,特別強化 SendCommand 同步收發模式,避免事件/執行緒非同步複雜度。
public PortData(string portName, int baudRate, Parity parity, SerialMode mode)
{
port = new SerialPort(portName, baudRate, parity, 8, StopBits.One);
port.RtsEnable = true;
port.ReadTimeout = 3000;
port.DataReceived += DataReceived;
port.ErrorReceived += ErrorEvent;
}
public int SendCommand(byte[] sendData, ref byte[] receiveData, int overtime)
{
if (!port.IsOpen) return -1;
ReceiveEventFlag = true; // 暫停事件接收
port.DiscardInBuffer(); // 清空接收緩衝區
port.Write(sendData, 0, sendData.Length);
int num = 0, ret = 0;
while (num++ < overtime)
{
if (port.BytesToRead >= receiveData.Length) break;
Thread.Sleep(1);
}
if (port.BytesToRead >= receiveData.Length)
ret = port.Read(receiveData, 0, receiveData.Length);
ReceiveEventFlag = false; // 恢復事件接收
return ret;
}
設計精華:透過 ReceiveEventFlag 暫停事件驅動接收,改用輪詢方式在指定逾時內同步等待預期長度資料,適合主從式請求-回應協定。
public void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (ReceiveEventFlag) return; // 命令模式下忽略事件
byte[] data = new byte[port.BytesToRead];
port.Read(data, 0, data.Length);
if (Received != null) Received(sender, new PortDataReciveEventArgs(data));
}
public class PortData
{
public event PortDataReceivedEventHandle Received;
public event SerialErrorReceivedEventHandler Error;
public SerialPort port;
public bool ReceiveEventFlag = false;
// 建構子、Open/Close、SendData、SendCommand、ErrorEvent、DataReceived、IsOpen
// ... 完整程式碼見原文 ...
}
public delegate void PortDataReceivedEventHandle(object sender, PortDataReciveEventArgs e);
public class PortDataReciveEventArgs : EventArgs
{
public byte[] Data { get; set; }
public PortDataReciveEventArgs() { }
public PortDataReciveEventArgs(byte[] data) { this.Data = data; }
}
COM1~COM9 使用
"COMx:";COM10 以上舊版用\\.\COMx:,但 Moxa 661 需用$device\COM{PortNo}\0格式,可能因驅動程式差異所致。