首页 > 解决方案 > 写入串口后如何读取串口直到超时?

问题描述

我需要从串口向我的设备写入和读取数据。我已经测试了某些方法,起初我正在使用接收数据SerialDataReceivedEventArgs,我觉得很难读取我需要定义发送命令的端口,因为命令几乎是 200 个命令。

我的第一种方法是使用:-

private void ObjCom_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (!ObjCom.IsOpen) return;
            byte[] data = new byte[ObjCom.BytesToRead];
            ObjCom.Read(data, 0, data.Length);
            RaiseEventMsg("Buffer String: " + BitConverter.ToString(data).Replace("-", " "));
        }

RaiseEventMsg是一个将当前信息传递给主 UI 的委托事件。第二种方法是:-

private long lngTickCount = Convert.ToInt64(1000L);
public void StartWriteToPort()
{
    byte[] Cmd = null;
    string strCmd = string.Empty;
    string strMsg = null;
    bool bCont = true;
    long lngCurrent = 0;
    long lngNow = 0;
    try
    {
        RaiseEventMsg("Start Write To Port");
        ObjCom.DiscardOutBuffer();
        ObjCom.DiscardInBuffer();

        GetFullCommandByte(ref Cmd, Convert.ToByte(123)); // Referencing Cmd with return and pass Command List(various set of command)
        ObjCom.Write(Cmd, 0, Cmd.Length);
        strCmd = ByteArrayToString(Cmd); // Convert byte array to Hex string
        RaiseEventMsg("Send: " + strCmd);
        bool bTimeout = false;
        lngCurrent = DateTime.Now.Ticks;
        while (!bTimeout)
        {
            lngNow = DateTime.Now.Ticks;
            if (lngNow > (lngCurrent + (3 * lngTickCount)))
            {
                bTimeout = true;
                break;
            }
        }

        lngCurrent = DateTime.Now.Ticks;
        while (ObjCom.BytesToRead <= 0)
        {
            lngNow = DateTime.Now.Ticks;
            if (lngNow > (lngCurrent + (1000 * lngTickCount)))
            {
                bCont = false;
                break;
            }
        }
        if (!bCont)
        {
            strMsg = "Error - Timeout Hit";
            RaiseEventMsg(strMsg);
            return;
        }

        int Idx = 0;
        string strASCIIFull = string.Empty;
        if ((ObjCom.BytesToRead > 0) & (bCont == true))
        {
            while (ObjCom.BytesToRead > 0)
            {
                var strASCII = ObjCom.ReadByte();
                var TmpHex = System.Convert.ToString(strASCII, 16).ToUpper();
                if (TmpHex.Length == 1)
                {
                    strASCIIFull += (" 0" + TmpHex);
                }
                else
                {
                    strASCIIFull += (" " + TmpHex);
                }
                lngCurrent = DateTime.Now.Ticks;
                while (ObjCom.BytesToRead <= 0)
                {
                    lngNow = DateTime.Now.Ticks;
                    if (lngNow > (lngCurrent + (2 * lngTickCount)))
                    {
                        bCont = false;
                        break;
                    }
                }
                Idx += 1;
            }
        }

        RaiseEventMsg("Recv: " + strASCIIFull);
    }
    catch (System.Exception ex)
    {
        string error = $"Exception on StartWriteToPort. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
    }
}

第二种方法的问题是,当我第二次调用此函数时,超时将命中。但是对于串行事件,它没有问题,超时协议设置为1秒。我的设备当前使用没有转换器的 USB 连接。设备的输入电缆是 B 型端口(如标准打印机端口)。

是否有任何其他方式可以直接从端口读取或对当前代码进行任何改进?

标签: c#serial-portcctalk

解决方案


您需要学习如何分层代码。目前你有一个很长的函数试图做所有的事情。

如果您有几个较小的函数来执行特定的操作,例如读取或写入大量信息,那么它将使您尝试做的事情变得更简单。

例如,串行通信通常有某种协议来封装信息包的存储方式。假设协议是“”,那么您知道每个数据包都以一个 STX 字节(0x01)开头,一个长度字节,它告诉您该部分中有多少字节,并且末尾必须有一个 ETX 字节(0x02)。您可以编写一个函数,该函数将返回一个字节数组,因为该函数将解释流并提取相关部分。

那么它可能很简单:

var packet1 = ReadPacket();
WritePacket(outputData);
var packet2 = ReadPacket();

推荐阅读