【问题标题】:C# data reading from serial port inconsistentC#从串口读取的数据不一致
【发布时间】:2021-02-19 07:57:06
【问题描述】:

我需要从.NET 5中的串口读取长度为18字节的数据

我的问题是,当我读取 18 个字节时,几乎每次它都会将 17 个字节读取到我的 18 个字节缓冲区中。所以数据看起来像

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

但它应该看起来像:

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

前 2 个字节是标头 - 验证数据序列的开始 - 始终相同

第二个字节是数据长度 - 0x0f - 我们预计后面有 15 个数据字节

代码是基本的:

_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();

如果我让线程休眠 1 秒,它会起作用,但这不是我想要的解决方案。我认为它应该正确加载数据。如果我尝试在缓冲区中加载 2 个字节的数据,它的行为非常相似。没关系,如果我在真实设备上或在虚拟 COM 端口上尝试 - 结果是一样的。所以我猜代码有问题,但我不知道是什么,因为我没有串口通信的经验。

目前的数据长度为 18 字节,但将来可能会有所不同。我有第二个问题,这对我很有帮助。加载所有 18 个字节是否正确,或者我应该只读取 3 个然后根据数据字节的长度加载?如何同步该标头字节?这对我很有帮助。

感谢您的任何回答。

在 Frenchy 的帮助下编辑:

试过这个,即使不检查标题字节,我在加载数据时也感觉有点慢。但结果无论如何都达不到。收到的数据:

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

代码:

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));
        }

尝试加载 3 个字节以检查标头有效性和数据长度,但在几次读取后它失败并且一遍又一遍地读取错误数据。 :-(

--- 编辑 2

我已经使它与以下内容一起工作:

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));
     }

首先我读取了 3 个字节的数据。如果第一个和第二个字节与标头值匹配,那么我们取第三个字节,它标识数据的长度。然后在 foreach 中读取具有从标头接收到的长度的单个字节。如果 header 不匹配,则丢弃数据。

它正在工作,但仍然可能有更好的解决方案,更快地读取数据,而不是在 5 次缓冲区读取中抛出 4 次。现在我测试一下就足够了。稍后会进行优化。感谢法国人帮助我!

【问题讨论】:

  • 如果您确定我们必须接收的数据,请尝试将速度降低到 9600 波特,看看是否有更好的结果.. 您的 c# 程序似乎没问题
  • 您确定不能在您的数据中包含序列 F1-DD 吗?这可以解释一些不同步,您必须确保标题 F1-DD 不能存在于您的数据中。检查我是否建议您在没有测试标头的情况下获取大量存储桶数据并查看..

标签: c# serial-port


【解决方案1】:

只是一个想法,而不是循环为什么不使用这样的事件:也许是一个更好的结果。 Qome 问题:您确定您的数据中没有标题 FF-DD,否则会有很大的不同步风险吗?尝试降低速度..

_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));
}

【讨论】:

  • 编辑了我的帖子。不知道如何在 stackoverflow 中做出正确的反应。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2014-02-28
  • 2011-12-24
  • 1970-01-01
相关资源
最近更新 更多