C# COM:设备仅在情况发生变化时发送数据。如何处理?

C# COM:设备仅在情况发生变化时发送数据。如何处理?,c#,.net,serial-port,C#,.net,Serial Port,因此,我想通过串行连接到一个设备,该设备仅在设备设置发生变化时发送数据(测量设备)。 我使用C#和.Net的SerialPort 我能够读取数据,看起来不错。但是我遇到了一些问题 我实现了我的reading-method(ReadExistingData()),这样当有新数据时,它将不断使用SerialDataReceivedEventHandler。 不幸的是,当我这样读它时(可能是因为不同的包大小),它会读得非常混乱,因此我需要“捕获”第一个起始字节(这里是0xA5)。 这意味着,我总是检查

因此,我想通过串行连接到一个设备,该设备仅在设备设置发生变化时发送数据(测量设备)。 我使用C#和.Net的
SerialPort

我能够读取数据,看起来不错。但是我遇到了一些问题

我实现了我的reading-method(
ReadExistingData()
),这样当有新数据时,它将不断使用
SerialDataReceivedEventHandler
。 不幸的是,当我这样读它时(可能是因为不同的包大小),它会读得非常混乱,因此我需要“捕获”第一个起始字节(这里是
0xA5
)。 这意味着,我总是检查我刚刚收到的字节是否是
0xA5
,如果是,我读取其余的

但我觉得这样我就错过了我的设备发送给我的一些命令,这就是为什么我不能始终正确地显示数据,只是偶尔

旁注:设备发送设备时间和值。这个值是延迟的,有点不准确,但时间总是在现场。它发送的其他参数总是很奇怪,似乎无法识别,因此根本没有改变

为了显示数据,我使用控制台进行测试,整个结构似乎对控制台输出非常被动

下面是一个小代码片段:

类设备
{
私有int stdMessageLengthInBytes=5;
公共设备数据处理数据;
字节[]数据缓冲;
int receivedMessages=0;
公共设备()
{
//初始化基类(串行端口派生)
this.port=new System.IO.Ports.SerialPort();
//初始化设备
this.data=新字节[stdMessageLengthInBytes];
this.processedData=新的P8005_数据();
dataBuffer=新字节[stdMessageLengthInBytes];
}
//应该从串行端口读取数据
受保护的覆盖无效ReadExistingData()
{
//检查缓冲区是否为空->尝试捕获0xA5
如果(数据缓冲[0]==0x00)
{
读取端口(数据缓冲,0,1);
}
//如果未捕获到0xA5,请重新启动
如果(数据缓冲[0]!=0xA5)
{
dataBuffer=新字节[stdMessageLengthInBytes];//重置缓冲区
返回;
}
//读取下一个字节->命令字节
读取端口(数据缓冲区,1,1);
//如果命令为空,请重新启动
如果(数据缓冲[1]==0x00)
{
dataBuffer=新字节[stdMessageLengthInBytes];//重置缓冲区
返回;
}
//如果是通信时间:读取3个字节
如果(数据缓冲[1]==0x06)
{
//似乎需要4毫秒的延迟,否则它无法正常工作
系统。线程。线程。睡眠(5);
端口读取(数据缓冲,2,3);
//将缓冲区写入实际原始数据字节数组
this.data=dataBuffer;
dataBuffer=新字节[stdMessageLengthInBytes];//重置缓冲区
}
//否则:只读取2个字节
System.Threading.Thread.Sleep(5);//需要延迟
读取端口(数据缓冲,2,2);
//将缓冲区写入实际原始数据字节数组
this.data=dataBuffer;
dataBuffer=新字节[stdMessageLengthInBytes];//重置缓冲区
}
//由SerialDataReceiveDevenHandler调用的方法
受保护的覆盖无效DataReceivedOnComPort(对象发送方,SerialDataReceivedEventArgs e)
{
bool valid=false;
ReadExistingData();//从COM端口读取数据
锁(已处理数据)
{
开关(数据[1])//检查命令字节
{
//时间(3 btyes)
案例(0x06):
processedData.currentTime=String.Format(“{0:D2}:{1:D2}:{2:D2}”)、DecodeBcd(数据[2])、DecodeBcd(数据[3])、DecodeBcd(数据[4]);
有效=真;
receivedMessages++;
打破
//值(2字节)
案例(0x0D):
双val=0;
val+=解码BCD(数据[2])*100;
val+=已解码BCD(数据[3]);
val/=10;
processedData.currentValue=val;
有效=真;
receivedMessages++;
打破
//…这里是各种其他十六进制代码,表示来自设备的命令(2 btyes)
违约:
有效=错误;
打破
}
}
//只是为了检查什么时候
如果(有效)
{
WriteLine(“接收到的有效消息:{0}”,receivedMessages);
ConsoleOutput();
}
}
}
注意:端口的初始化在基类的另一个方法中进行,并且工作正常

我有什么遗漏吗?如何处理这样的事情?是否有任何改进有助于提高我的绩效?我曾考虑过用锁线程,但我不认为这是解决办法。。。或者一切都只是控制台的问题


编辑:

我知道我更改了代码(正如@jdweng所建议的),所以我将所有内容都放在一个缓冲区中(基本上是
listmainbuffer
)。然后,我在可能的情况下获取缓冲区中的所有字节,并对它们进行处理,将其略过
0xA5
。找到一个字节后,我阅读命令并根据它确定“消息”的长度(时间->+3个字节,数据->+2个字节,其他->+1个字节)。然后我可以处理这些消息(我将它们放入
列表中
),并确定屏幕上的输出

然而,即使在将切分工作外包到消息中并对消息进行处理之后,我仍然似乎错过了一些消息,因为有些操作没有注册
private const int MESSAGE_LENGTH = 5;
private const int VALUE_COMMAND = 0x0D;
private const int VALUE_SIZE = 4;
private const int TIME_COMMAND = 0x06;
private const int TIME_SIZE = 5;
private byte[] _message = new byte[MESSAGE_LENGTH];
private int _messagePos = 0;
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var data = new byte[_serialPort.BytesToRead];
    _serialPort.Read(data, 0, data.Length);
    foreach (var b in data)
    {
        _message[_messagePos] = b;
        if (_messagePos == 0 && b != 0xa5)
            continue;
        ++_messagePos;
        if (_messagePos > 2)    // if command byte present, process command of any size
            ProcessCommand(_message[1]);
    }
}

private void ProcessCommand(byte command)
{
    if (_messagePos == VALUE_SIZE && command == VALUE_COMMAND)
    {
        // parse value...
        _messagePos = 0;
    }
    else if (_messagePos == TIME_SIZE && _message[1] == TIME_COMMAND)
    {
        // parse time...
        _messagePos = 0;
    }
}