說明
- 使用SerialPort類
- 使用SerialPort.DataReceived 接收事件
- DataReceived事件觸發無規律,不可作爲一幀數據的判斷
- 數據接收也可使用單獨一個線程輪詢判斷,判斷更爲精確,但是要完全佔用一個線程,無堵塞,費資源。
- 歡迎補充指導
開啓串口
SerialPort mySerialPort;//本地串口
mySerialPort = new SerialPort(comName);
mySerialPort.BaudRate = (int)dr.baud;//波特率
mySerialPort.DataBits = Convert.ToInt32(dr.databits);//數據位
mySerialPort.StopBits = (StopBits)Convert.ToInt32(dr.stopbits);//停止位
mySerialPort.Parity = (Parity)Enum.Parse(typeof(Parity), dr.parity);//校驗位
mySerialPort.WriteTimeout = 500;
LocalPort localport = new LocalPort(mySerialPort);
if (mySerialPort.IsOpen == false)
{
Console.Write("open " + comName + " Error.\r\n");
return response; ;
}
else
{
localport.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(ReceiveFromDevice);//打開成功則創建接收數據事件
localport.LocalPortName = comName;
localportList.Add(comName, localport);
Console.Write("open " + comName + " Ok.\r\n");
}
串口接收事件
接收到數據後使用委託處理,更爲高效,也防止堵塞串口接收數據事件
//本地串口事件 接收來自設備發向本地串口的數據
private static void ReceiveFromDevice(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serialPort = (SerialPort)sender;
foreach (string key in localportList.Keys)
{
if (serialPort.PortName == key)
{
LSPReceiveDelegate lsprd = new LSPReceiveDelegate(Receive);
lsprd(localportList[key]);
}
}
}
數據處理判斷
使用類似空閒中斷方法區分一幀數據,對緩存數據大小也做了限制,同時對最後一組數據做了定時器判斷。
public static void Receive(LocalPort localPort)
{
try
{
SerialPort LP = localPort.port;
int revcount_new = LP.BytesToRead;
TimeSpan span;
int oneByteTime = 0;
if (LP.Parity == Parity.None)
oneByteTime = 1000000 / (LP.BaudRate / 10);
else
oneByteTime = 1000000 / (LP.BaudRate / 11);
int diffCount = 0;
try
{
if (localPort.isNewFrame)
localPort.dt = DateTime.Now;
DateTime dt = DateTime.Now;
span = dt - localPort.dt;
localPort.dt = dt;
diffCount = revcount_new - localPort.revcount;
localPort.revcount = revcount_new;
if (span.Ticks > ((diffCount + 3) * oneByteTime * 10))
{
byte[] recvBytes = new byte[LP.BytesToRead];
LP.Read(recvBytes, 0, recvBytes.Length);
//string recvData = LP.ReadExisting();
localPort.revcount = 0;
SendToCloudDelegate stcd = SendToCloud;
stcd("receive", LP.PortName, null, ByteToHexStr(recvBytes));
localPort.isNewFrame = true;
}
else if (localPort.revcount > 2048)
{
byte[] recvBytes = new byte[LP.BytesToRead];
LP.Read(recvBytes, 0, recvBytes.Length);
//string recvData = LP.ReadExisting();
localPort.revcount = 0;
SendToCloudDelegate stcd = SendToCloud;
stcd("receive", LP.PortName, null, ByteToHexStr(recvBytes));
localPort.isNewFrame = true;
}
else
{
localPort.isNewFrame = false;
try
{
localPort.timer.Stop();
localPort.timer.Close();
}
catch
{ }
localPort.timer = new System.Timers.Timer(10);
localPort.timer.Elapsed += new System.Timers.ElapsedEventHandler(LSPTimeOut); //到達時間的時候執行事件;
localPort.timer.AutoReset = false; //設置是執行一次(false)還是一直執行(true);
localPort.timer.Enabled = true; //是否執行System.Timers.Timer.Elapsed事件;
localPort.timer.Start();
}
}
catch
{
Console.WriteLine(LP.PortName + "closed!");
SendToProcess(LP.PortName + "closed!");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//}
}
使用該方法可以有效區分接收一幀數據,但是也存在弊端。如最後一幀數據會有一個定時器定時的時間延時,如果數據包發送比較緩慢,每一幀數據都存在定時器那個時間的延時。