【问题标题】:Waiting for a serial port response using timercallback使用 timercallback 等待串口响应
【发布时间】:2018-02-16 22:29:04
【问题描述】:

我正在使用 .NET 4.0 开发一个项目。我有一个通过串行端口连接的设备,我向它发送命令,然后等待响应。收到响应后,我会检查响应以确保其有效,然后发送下一条命令。

主要问题是我发送的命令有很大不同的响应时间。一个命令的响应可能需要 30 毫秒或 30 秒。因此,我实现了 TimerCallback 以每 500 毫秒检查一次来自串行端口的响应。我已经发布了下面的代码以及我得到的输出。

// From different class
private string SendCommandAwaitResponse(string command)
    {
        // Set timeout to 30 seconds.
        this.port.ReadTimeout = 30000;
        // Clears existing
        this.port.ReadExisting();
        this.port.Write(command);

        var autoEvent = new AutoResetEvent(false);
        var responseTimer = new ResponseTimer(port, command);
        var timer = new Timer(responseTimer.GetResponse, autoEvent, 0, 500);

        autoEvent.WaitOne();
        Trace.WriteLine(string.Format("AutoEvent Set: {0}", command));
        timer.Dispose();

        return responseTimer.Response;
    }

public class ResponseTimer
{
    private ISerialPort serialPort;
    private string command;
    private bool isAttemptingRead;

    public string Response
    {
        get { return this.response; }
        set
        {
            if (this.response == value)
                return;
            this.response = value;
        }
    }
    private string response;

    public ResponseTimer(ISerialPort port, string command)
    {
        Trace.WriteLine("Constructor Created");
        this.isAttemptingRead = false;
        this.serialPort = port;
        this.command = command;
        Response= string.Empty;
    }

    public void GetResponse(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;

        try
        {
            if (!isAttemptingRead)
            {
                Trace.WriteLine("Initiating ReadLine");
                Response= serialPort.ReadLine();
                isAttemptingRead = true;
            }
            Trace.WriteLine("Try: " + Response);
        }
        catch (TimeoutException ex)
        {
            Trace.WriteLine(String.Format("EX: TIMED OUT: Response {0}", Response));
            autoEvent.Set();
        }

        Trace.WriteLine(String.Format("CURRENT Response {0}", Response));

        if (Response == command)
        {
            Trace.WriteLine(string.Format("COMMAND: {0}", command));
            Trace.WriteLine(string.Format("Clearing Buffer: {0}", Response));
            Response= string.Empty;
            isAttemptingRead = false;
        }
        else if (!string.IsNullOrEmpty(Response))
        {
            Trace.WriteLine(String.Format("Got Response - {0}", Response));
            autoEvent.Set();
        }
        else if (string.IsNullOrEmpty(Response))
            Trace.WriteLine("Empty or Null read");
    }
}

代码适用于较短的响应时间(30 毫秒),但是当它到达响应时间为 30 秒的命令时,我得到以下输出(大部分)。

WriteLine(#XSFCD)

  1. 已创建构造函数
  2. 启动 ReadLine
  3. 尝试:#XSFCD
  4. 当前响应 #XSFCD
  5. 命令:#XSFCD
  6. 清除缓冲区:#XSFCD
  7. 启动 Readline
  8. 启动 Readline
  9. 正在启动 Readline 等...

然后我通常只是结束程序。我是否缺少 TimerCallback 方法的某些内容?

【问题讨论】:

    标签: c# serial-port


    【解决方案1】:

    来自 MSDN 页面:

    serialport.readline

    将一直等到它在串行端口上看到行尾字符或直到 ReadTimeout 已过。

    ...

    默认情况下,ReadLine 方法将阻塞,直到收到一行。如果不希望出现这种行为,请将 ReadTimeout 属性设置为任何非零值,以强制 ReadLine 方法在端口上没有可用线路时抛出 TimeoutException。

    对于System.Threading.Timer:

    提供一种机制,用于以指定的时间间隔在线程池线程上执行方法。

    因此,每个计时器回调可能位于单独的线程上,并且每个 readline() 调用都会暂停当前线程,直到它看到行尾字符。无论发生什么其他情况,您的计时器每 500 毫秒触发一次。所以第一个调用 readline() 并在那里等待行尾字符。它没有看到一个,所以它一直在等待。 500 毫秒后,另一个线程做同样的事情。 500 毫秒后,同样的事情发生了,等等。所以你正在堆积所有这些 readline() 调用等待 readline() 完成。最终你厌倦了等待并终止程序。代替 readLine() 您可以执行 readExisting() 来读取当前缓冲区,但您必须自己找到行尾字符的位置。要么这样,要么您可以完全摆脱计时器并使用串行端口事件(例如DataReceived)来告诉您何时获得了一些数据。

    【讨论】:

    • 啊,这让事情变得更清楚了。我将尝试事件处理程序,看看情况如何。非常感谢!
    猜你喜欢
    • 2012-07-31
    • 2013-05-15
    • 1970-01-01
    • 2015-11-18
    • 2014-08-20
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 2020-09-19
    相关资源
    最近更新 更多