【问题标题】: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
    相关资源
    最近更新 更多