c#异步串口读取
本文关键字:读取 串口 异步 | 更新日期: 2023-09-27 18:06:35
我有一个类,使用c#中的DataReceived事件处理程序从串行端口读取。当我接收数据时,我知道头将有5个字节,所以我不想对数据做任何事情,直到我至少有。我当前的代码如下:
while (serialPort.BytesToRead<5)
{
//Do nothing while we have less bytes than the header size
}
//Once at least 5 bytes are received, process header
据我所知,这段代码是阻塞的,需要改进。我在征求如何做这件事的建议。DataReceived事件处理程序中的另一个事件处理程序是否合适?
使用异步编程(不要忘记首先将应用程序定位于。net Framework 4.5)
这是我的实现作为SerialPort
的扩展方法。
using System;
using System.IO.Ports;
using System.Threading.Tasks;
namespace ExtensionMethods.SerialPort
{
public static class SerialPortExtensions
{
public async static Task ReadAsync(this SerialPort serialPort, byte[] buffer, int offset, int count)
{
var bytesToRead = count;
var temp = new byte[count];
while (bytesToRead > 0)
{
var readBytes = await serialPort.BaseStream.ReadAsync(temp, 0, bytesToRead);
Array.Copy(temp, 0, buffer, offset + count - bytesToRead, readBytes);
bytesToRead -= readBytes;
}
}
public async static Task<byte[]> ReadAsync(this SerialPort serialPort, int count)
{
var buffer = new byte[count];
await serialPort.ReadAsync(buffer, 0, count);
return buffer;
}
}
}
和这里如何阅读:
public async void Work()
{
try
{
var data = await serialPort.ReadAsync(5);
DoStuff(data);
}
catch(Exception excepcion)
{
Trace.WriteLine(exception.Message);
}
}
这会烧掉100%的core,你不会想那样做的。正确的方法是让程序阻塞Read()调用。你可以这样写:
private byte[] rcveBuffer = new byte[MaximumMessageSize];
private int rcveLength;
void ReceiveHeader() {
while (rcveLength < 5) {
rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
}
}
或者如果你使用DataReceived事件,那么它看起来像这样:
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) {
if (e.EventType != System.IO.Ports.SerialData.Chars) return;
if (rcveLength < 5) {
rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
}
if (rcveLength >= 5) {
// Got the header, read the rest...
}
}
不要忘记在您获得整个消息并处理它之后将rcveLength设置回0。