3

我正在使用来自“大牌”之一的第三方串行端口组件(是的,我已经要求他们提供支持,但是存在时区差异,我需要要很快解决这个问题)。该组件已存在多年,我没有理由相信问题在于它(与硬件相同)。用户界面活动如何破坏我的串口输入

h/w规范说如果我向seial端口写入一个特定的字符串,以回车符结束,然后读取,它将以特殊格式化的8个字符的字符串进行回复,再次以回车结束。

代码可以正常运行几个小时,并根据它读取的内容更新GUI。

但是,当在GUI上有任何用户活动时,我从串口读取垃圾。

我第一次注意到它时,点击一个按钮,导致模态窗体打开,然后关闭窗体。

但是,当我简单地拖动TStringGrid的scollbar时,我也会看到它。

这是代码。有什么建议?


更新:组件是线程化的,供应商同意这里的海报 - 串行端口是异步设备。我更改了代码以编写数据请求并处理组件的OnCharReceived()事件处理程序中的每个接受字符。塔恩斯克所有的帮助。


function TForm1.ReadChannelValueFromSerialPort(
         device_number : String; channel_number : String) : Real; 
    const SLEEP_TIME = 50;   // ms 
     NUM_READ_ATTEMPTS = 10; 

    var serialPortInput : String; 
     read_attempt_counter : Integer; 
     messageString : String; 
begin 
    WriteToSerialPort('#' + device_number + channel_number + #13); 

    serialPortInput := ''; 
    read_attempt_counter := 0; 

    while Length(serialPortInput) = 0 do 
    begin 
     try 
     Application.ProcessMessages(); 
     serialPortInput := serialPortInput + SerialPort.ReadText(); 

     except 
     on E: Exception do 
     begin 
      messageString := 'Can''t read from serial port' ; 
      MessageDlg(messageString, mtError, [mbOK], 0); 
      Halt(0); 
     end; 
     end; 

     Inc(read_attempt_counter); 

     if (read_attempt_counter = NUM_READ_ATTEMPTS) 
     and (Length(serialPortInput) = 0) then 
     begin 
     messageString := 'Can''t read from serial port after trying ' + 
        IntToStr(NUM_READ_ATTEMPTS) + ' times in ' + 
      FloatToStr((SLEEP_TIME * NUM_READ_ATTEMPTS)/1000) + ' seconds'; 
     MessageDlg(messageString, mtError, [mbOK], 0); 
     Halt(0); 
     end; 

     if (Length(serialPortInput) = 0) then 
     Sleep(SLEEP_TIME); 
    end; 

    if Copy(serialPortInput, 1, 1) <> '>' then 
    begin 
     DebugBreak(); 
     MessageDlg('Invalid value read from serial port "' + 
        serialPortInput + '"', mtError, [mbOK], 0); 
     Halt(0); 
    end; 

    // drop the3 leading > 
    serialPortInput := Copy(serialPortInput, 2, Length(serialPortInput) - 1); 
    serialPortInput := TrimRight(serialPortInput); // just in case 
    Result := StrToFloat(serialPortInput); 
end; // ReadChannelValueFromSerialPort(); 
+1

当serialPortInput <>''做'时,有没有什么理由使用效率较低的'while Length(serialPortInput)= 0 do'而不是''? –

+0

不,没有: - /(+1) – Mawg

回答

10

没有你实际使用的是哪个组件,或者它在内部做什么了解,就很难说了。但是用户活动会经过主消息队列,并且您的代码会手动抽取队列中的新消息,因此可能与您的问题有关。您允许在您的写入和读取之间处理用户活动。您是否尝试将串行端口逻辑移入单独的工作线程?

+5

IOW,摆脱'Application.ProcessMessages'。 –

+0

Remy(+1),我宁愿不公开地说 - 我正在使用哪个第三方组件,因为它已经过时,经过测试并且来自“其中一个大个子”,所以我确信这个问题是我的而不是他们的。命名他们可能会被视为批评,我不希望这样。我相信这个问题是我的。 – Mawg

+0

“您的代码正在手动抽取新邮件队列,因此可能与您的问题有关”。我同意我的代码可能存在错误 - 但不知道错误是什么。当我写入请求数据的串口时,我怀疑我无法立即读取,所以我试图通过睡眠和处理消息来“礼貌”。也许如果我删除一个/这两个问题可能会消失?毕竟,它应该只需要几分之一秒的时间以紧密的循环读取串行端口,直到出现一些数据,而滚动条等的WM_才会排队......您怎么看? – Mawg

2

串行通信通常涉及发送/接收缓冲区以及流量控制。由于您的实施,正常流量显然中断。

我建议你将访问端口的代码迁移到后台线程,并在适当的时候对客户端GUI进行某种同步回调。 (一个选项是简单的Synchronize()调用)

+0

+1感谢您的反馈。串口组件是带螺纹的。我想我应该写一个请求,然后处理它的OnDataReceieve()事件。 – Mawg

0

它记得我几年前有同样的问题:单击鼠标中断与PLC的串行通信(严重!)。

并不确切地知道我们是如何固定的,但我认为它有一些东西需要用USB鼠标,接地不当和/或串行电缆的电/磁屏蔽,过长串行电缆,双绞线USB的组合/串行电缆或类似的东西(是的,在R & D工作区有点杂乱...)

所以也许你可以尝试改变和/或检查一些硬件?