用户GUI活动如何破坏我的串口输入

Maw*_*awg 3 delphi user-interface serial-port corrupt-data android-activity

我正在使用来自"大牌"之一的第三方串口组件(是的,我已经向他们寻求支持,但是存在时区差异,我需要很快解决这个问题).该组件已存在多年,我没有理由相信问题在于它(同上硬件).

h/w规范说如果我将一个字符串写入seial端口,通过回车终止,然后读取,它将回复一个spcifically格式的8字符串,再次通过回车终止.

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

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

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

但是,我只是在拖动TStringGrid的scollbar时也会看到它.

这是代码.有什么建议?


更新:组件是线程化的,供应商同意这里的海报 - 串口是异步设备.我已经更改了代码来编写数据请求并处理组件的OnCharReceived()事件处理程序中的每个已接收字符.Tahnsk提供所有帮助.


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();
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 10

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

  • IOW,摆脱`Application.ProcessMessages`. (5认同)
  • 总结:删除Application.ProcessMessages,或者如果您的GUI必须保持响应,请从线程中的端口读取. (3认同)
  • +1反对手动轮询串口.大多数主要串行端口组件已经在内部实现了线程模型,并在数据可用时提供事件触发器.改用它.另外,你没有提到你正在使用的Delphi版本 - 记住,因为2009年字符串是unicode,而串行数据只是8位.大多数串口命令需要在unicode后更新. (2认同)