简体   繁体   English

C# 串口读取数据不一致

[英]C# data reading from serial port inconsistent

I need to read data of length of 18 bytes from serial port in .NET 5我需要从 .NET 5 的串口读取长度为 18 字节的数据

My problem is, when I'm reading 18 bytes, then almost everytime it reads 17 bytes into my 18 bytes buffer.我的问题是,当我读取 18 个字节时,几乎每次它都会将 17 个字节读取到我的 18 个字节缓冲区中。 So the data looks like所以数据看起来像

F1-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
DD-0F-08-7C-23-2E-3C-95-11-00-01-00-02-00-0A-00-07-00

but it should look like:但它应该看起来像:

F1-DD-0F-08-7C-23-2E-3C-95-11-00-01-00-02-00-0A-00-07

first 2 bytes is header - to validate start of data sequence - always same前 2 个字节是 header - 验证数据序列的开始 - 始终相同

second byte is length of data - 0x0f - we expect 15 data bytes following第二个字节是数据长度 - 0x0f - 我们预计后面有 15 个数据字节

The code is basic:代码是基本的:

_readPort = new SerialPort("COM8", 115200, Parity.None, 8);
_readPort.Open();
_readPort.DiscardOutBuffer();
_readPort.DiscardInBuffer();

while (_continue == true)
{
    //Thread.Sleep(1000);
    byte[] buffer = new byte[18];

    try
        {
            _readPort.Read(buffer, 0, 18);
            Console.WriteLine(BitConverter.ToString(buffer));
    }
    catch (TimeoutException) {}
}

Console.ReadLine();
_readPort.Close();

It works if I sleep the thread for 1 second, but thats not the solution I want.如果我让线程休眠 1 秒,它会起作用,但这不是我想要的解决方案。 I think it should load data correctly.我认为它应该正确加载数据。 If i tried to load data by 2 bytes in buffer, it behaved very similarly.如果我尝试在缓冲区中加载 2 个字节的数据,它的行为非常相似。 Doesn't matter, if I try it on real device or if on virtual COM ports - result is same.没关系,如果我在真实设备上或在虚拟 COM 端口上尝试 - 结果是一样的。 So I guess there is something wrong with code, but I do not know what, since I'm not experienced with serial port communication.所以我猜代码有问题,但我不知道是什么,因为我没有串口通信的经验。

The length of data for now is 18 bytes, but it can differ in the future.目前的数据长度为 18 个字节,但将来可能会有所不同。 I have a second question, which would help me a lot.我有第二个问题,这对我很有帮助。 Is it correct to load all 18 bytes or should I read just 3 and then load dependently on the lengh of data byte?加载所有 18 个字节是否正确,或者我应该只读取 3 个然后根据数据字节的长度加载? How to synchronize on that header bytes?如何在 header 字节上同步? This would help me a lot.这对我有很大帮助。

Thanks for any answer.感谢您的任何回答。

edit after help of Frenchy:在 Frenchy 的帮助下编辑:

Tried this and it feels for me kinda slow when loading data even when not checking header bytes.试过这个,即使不检查 header 字节,我在加载数据时也感觉有点慢。 But the result is not achieved anyway.但结果无论如何都达不到。 Data received:收到的数据:

Header: F1-DD-0F Data: 08-7C-23-2E-24-95-11-00-01-00-02-00-0A-00-07
Header: F1-DD-0F Data: 08-7C-23-2E-22-95-11-00-01-00-02-00-0A-00-07
Header: F1-DD-0F Data: 08-7C-23-2E-2A-95-11-00-01-00-02-00-0A-00-07
Throwing invalid header: F1-00-00

Code:代码:

static void Main(string[] args)
        {
            // prepare thread for reading data from read port
            _readPort = new SerialPort("COM8", 115200, Parity.None, 8);
            _readPort.DataReceived += new SerialDataReceivedEventHandler(PortDataReceived);
            _readPort.ReadTimeout += 1000;
            _readPort.Open();

            Console.ReadKey();
            _readPort.Close();
        }

        static void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //if (_readPort.IsOpen) return;

            SerialPort port = (SerialPort)sender;

            byte[] headerBuffer = new byte[3];
            port.Read(headerBuffer, 0, 3);

            if (headerBuffer[0] != 0xf1 || headerBuffer[1] != 0xdd)
            {
                Console.WriteLine("Throwing invalid header: " + BitConverter.ToString(headerBuffer));
                return;
            }

            byte[] dataBuffer = new byte[headerBuffer[2]];
            port.Read(dataBuffer, 0, headerBuffer[2]);

            Console.WriteLine("Header: " + BitConverter.ToString(headerBuffer) + " Data: " + BitConverter.ToString(dataBuffer));
        }

Trying to load 3 bytes to check header validity and data length, but after few reads it fails and over and over reads wrong data.尝试加载 3 个字节来检查 header 的有效性和数据长度,但在几次读取后它失败并且一遍又一遍地读取错误数据。 :-( :-(

--- edit 2 --- 编辑 2

I've made it work with the following:我已经使它与以下工作:

static void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort port = (SerialPort)sender;

    byte[] headerBuffer = new byte[3];
    port.Read(headerBuffer, 0, 3);

    if (headerBuffer[0] != 0xf1 || headerBuffer[1] != 0xdd)
    {
        Console.WriteLine("Throwing invalid header: " + 
                BitConverter.ToString(headerBuffer));
                port.DiscardInBuffer();
                return;
    }

    byte[] dataBuffer = new byte[headerBuffer[2]];

    for (int i = 0; i < headerBuffer[2]; i++) {
        dataBuffer[i] = (byte)port.ReadByte();
    }

    Console.WriteLine("Header: " + BitConverter.ToString(headerBuffer) + " Data: " + BitConverter.ToString(dataBuffer));
     }

First I read 3 bytes of data.首先我读取了 3 个字节的数据。 If first and second byte matches the header value, then we take third byte, which identifies length of data.如果第一个和第二个字节与 header 值匹配,那么我们取第三个字节,它标识数据的长度。 Then read single bytes in foreach with length received from header.然后在 foreach 中读取从 header 接收到的长度的单个字节。 If header is not matched, then throw data away.如果 header 不匹配,则丢弃数据。

It's working, but still there might be a better solution, to read data faster and not to throw 4 out of 5 buffer reads.它正在工作,但仍然可能有更好的解决方案,更快地读取数据,而不是在 5 次缓冲区读取中抛出 4 次。 For now it's enough for me to test.现在我测试一下就足够了。 Optimization will come later.稍后会进行优化。 Thanks frenchy to helping me!感谢法国人帮助我!

just one idea, instead of looping why not use the event like this: maybe a better result.只是一个想法,而不是循环为什么不使用这样的事件:也许是一个更好的结果。 Qome questions: are you sure to not have the header FF-DD in your datas, either big risk of desynch? Qome 问题:您确定您的数据中没有 header FF-DD,或者不同步的大风险? try to decrease the speed..尝试降低速度..

_readPort = new SerialPort("COM8", 115200, Parity.None, 8);
_readPort.Open();
_readPort.DiscardOutBuffer();
_readPort.DiscardInBuffer();
_readPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (!_readPort.IsOpen) return;
    int bytes = _readPort.BytesToRead;
    byte[] buffer = new byte[bytes];
    _readPort.Read(buffer, 0, bytes);
    Console.WriteLine(BitConverter.ToString(buffer));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM