3

我正在使用来自“大牌”之一的第 3 方串行端口组件(是的,我已向他们寻求支持,但存在时区差异,我需要尽快解决此问题)。该组件已经存在多年,我没有理由相信问题出在它身上(硬件同上)。

硬件规范说,如果我将某个字符串写入串行端口,以回车终止,然后读取,它将以特定格式的 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();
4

3 回答 3

10

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

于 2011-09-21T00:50:14.570 回答
2

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

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

于 2011-09-21T03:21:31.437 回答
0

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

不知道我们是如何解决这个问题的,但我认为这与 USB 鼠标、串行电缆的接地不当和/或电子/磁屏蔽、串行电缆过长、USB/串行电缆扭曲或类似的东西(是的,研发车间有点乱……)

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

于 2011-09-21T06:06:36.310 回答