当前位置: 代码迷 >> 综合 >> C# SerialPort 使用DataReceived接口利用空闲中断原理接收完整一帧数据
  详细解决方案

C# SerialPort 使用DataReceived接口利用空闲中断原理接收完整一帧数据

热度:64   发布时间:2024-01-18 19:08:58.0

说明

  • 使用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);elseoneByteTime = 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);}//}}

使用该方法可以有效区分接收一帧数据,但是也存在弊端。如最后一帧数据会有一个定时器定时的时间延时,如果数据包发送比较缓慢,每一帧数据都存在定时器那个时间的延时。