版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sensiki/article/details/78132702
说明
- 使用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);
}
//}
}
使用该方法可以有效区分接收一帧数据,但是也存在弊端。如最后一帧数据会有一个定时器定时的时间延时,如果数据包发送比较缓慢,每一帧数据都存在定时器那个时间的延时。