c#等待串口回显,检查并等待超时

时间:2013-04-15 03:35:39

标签: c#

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

当命令由嵌入式系统完成时,我可以发送命令并查看echo,但是我无法找到合适的方法来等待或延迟程序,直到收到echoed命令,这样我就可以继续并发送下一个命令。我想它是一种我想要实现的“高级”流控制。 代码在C#中。 我想等待回声并暂停,以防PC和嵌入式系统之间的通信丢失,这样程序就不会冻结。 任何wizz孩子在那里,可以建议一个巧妙的方式来做到这一点? 我不是一个优秀的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));
            }
    }

这是调用传输命令的示例:

     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)],检查它是否与发送的一样,然后允许程序代码进入下一个命令,如果没有收到正确的回声[例如上例中的AR50 \ r],例如5秒,则程序报告错误。

有什么建议吗?

谢谢!

1 个答案:

答案 0 :(得分:6)

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

由于你正在处理ASCII,你应该查看ReadLine方法。

如果在没有传入数据的情况下经过ReadTimeout,两者都会抛出TimeoutException

但是,如果嵌入式系统可以发送未经请求的消息,那么您需要采用其他方法。然后,您可以在全局字符串变量中放置您期望的回声,并在收到回声时将接收事件设置为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
        }
    }
}