5

您好,感谢您考虑此查询:我正在通过虚拟串行端口从 PC 向嵌入式系统发送命令,当嵌入式系统完成命令时,该命令会回显该命令。

当命令由嵌入式系统完成时,我可以很好地发送命令并看到回显,但是我无法找到合适的方法来等待或延迟程序直到收到回显的命令,以便我可以继续并发送下一个命令。我想它是我正在尝试实现的一种“高级”流控制。代码在 C# 中。我想等待回声并有一个超时,以防PC和嵌入式系统之间的通信丢失,这样程序就不会冻结。有没有可以建议一种巧妙的方法来做到这一点的聪明孩子?我不是一个伟大的 c# 程序员,只是在学习。

这是我拥有的接收功能:

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        // If the com port has been closed, do nothing
        if (!comport.IsOpen) return;

        // This method will be called when there is data waiting in the port's buffer

        // Determain which mode (string or binary) the user is in
        if (CurrentDataMode == DataMode.Text)
        {
            // Read all the data waiting in the buffer
            string data = comport.ReadExisting();

            // Display the text to the user in the terminal
            Log(LogMsgType.Incoming, data);
        }
        else
        {
            // Obtain the number of bytes waiting in the port's buffer
            int bytes = comport.BytesToRead;

            // Create a byte array buffer to hold the incoming data
            byte[] buffer = new byte[bytes];

            // Read the data from the port and store it in our buffer
            comport.Read(buffer, 0, bytes);

            // Show the user the incoming data in hex format
            Log(LogMsgType.Incoming, ByteArrayToHexString(buffer));
            }
    }

这是调用 Transmitt 命令的示例:

     text = "AR" + 50 + "\r";            //transmit a command to move
     this.comport.Write(text);

目前我正在使用时间延迟 [Thread.Sleep(TIMEGAP)] 并假设消息已执行并且从嵌入式系统返回的回声很好但我不检查它并且等待很长时间以确保完成:

     text = "AR" + 50 + "\r";            //transmit a command to move
     this.comport.Write(text);
     Thread.Sleep(TIMEGAP);              //Timegap = 10000ms

我真的很想用一个监视串行端口响应的函数/方法替换时间延迟调用 [Thread.Sleep(TIMEGAP)],检查它是否与发送的相同,然后允许程序代码继续执行下一个命令,并且如果在例如 5 秒内未收到正确的回显 [AR50\r 在上例中],则程序报告错误。

有什么建议么?

谢谢!

4

1 回答 1

6

最简单的方法是不使用DataReceived事件,而是通过设置 aReadTimeout并使用Read方法。

而且由于您正在处理 ASCII,因此您应该查看该ReadLine方法。

在没有传入数据的情况下,两者都会抛出一个TimeoutExceptionif ReadTimeouthas elapsed。

但是,如果嵌入式系统可以发送不请自来的消息,那么您将需要另一种方法。然后,您可以将您期望的回声放在全局字符串变量中,并在收到ManualResetEvent回声时设置接收事件。然后你可以等待ManualResetEvent超时。这也将涉及使用lock语句的线程同步。

如果 GC 不是问题,我可能会从以下内容开始:

using System.Text;
using System.IO.Ports;
using System.Threading;

namespace ConsoleApplication2
{
    class Program
    {
        static string serialBuffer = "";
        static string expectedEcho = null;
        static object expectedEchoLock = new object();
        static ManualResetEvent expectedEchoReceived = new ManualResetEvent(false);
        static SerialPort port = new SerialPort("COM1", 19200, Parity.None, 8, StopBits.One);

        static void Main(string[] args)
        {
            port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
        }

        static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (port.BytesToRead > 0)
            {
                byte[] buffer = new byte[port.BytesToRead];
                int bytesRead = port.Read(buffer, 0, buffer.Length);
                if (bytesRead <= 0) return;
                serialBuffer += Encoding.UTF8.GetString(buffer, 0, bytesRead);
                string[] lines = serialBuffer.Split('\r', '\n');
                // Don't process the last part, because it's not terminated yet
                for (int i = 0; i < (lines.Length - 1); i++)
                {
                    if (lines[i].Length > 0)
                        ProcessLine(lines[i]);
                }
                serialBuffer = lines[lines.Length - 1]; // keep last part
            }
        }

        static void ProcessLine(string line)
        {
            bool unsolicitedMessageReceived = false;
            lock (expectedEchoLock)
            {
                if (line == expectedEcho)
                {
                    expectedEchoReceived.Set();
                }
                else
                {
                    unsolicitedMessageReceived = true;
                }
            }
            if (unsolicitedMessageReceived)
            {
               // Process unsolicited/unexpected messages
            }
        }

        /// <summary>
        /// Send a command and wait for echo
        /// </summary>
        /// <param name="command">The command to send</param>
        /// <returns>True when echo has been received, false on timeout.</returns>
        static bool SendCommand(string command)
        {
            lock (expectedEchoLock)
            {
                expectedEchoReceived.Reset();
                expectedEcho = command;
            }
            port.Write(command);
            return expectedEchoReceived.WaitOne(5000); // timeout after 5 seconds
        }
    }
}
于 2013-04-15T03:55:05.247 回答