Pergunta

I am using a 3rd party serial port component from one of "the big names" (yes, I have asked them for support, but there is a time zone difference and I need to fix this really quickly). The component has been around for years and I have no reason to believe that the problem lies with it (ditto the harwdware).

The h/w spec says that if I write a certain string to the seial port, terminated by carriage return, and then read, it will reply with a spcifically formatted 8 character string, again terminated by carriage return.

The code can run for hours doing this correctly and updating the GUI based on what it reads.

However, when there is any user activity on the GUI, I read junk from the serial port.

I first noticed it when clicking a button which caused a modal form to open and then closing the form.

However, I also see it when simply dragging the scollbar of a TStringGrid.

Here is the code. Any advice?


Update: the component is threaded and the suppliers agree with the posters here - a serial port is an asynchrnonous device. I have changed the code to write a request for data and handle each receied character in the component's OnCharReceived() event handler. Tahnsk for all of the help.


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();
Foi útil?

Solução

Without knowing which component you are actually using, or what it does internally, it is hard to say. But user activity goes through the main message queue, and your code is manually pumping the queue for new messages, so that is likely related to your problem. You are allowing user activity to be processed in between your writes and reads. Have you tried moving the serial port logic into a separate worker thread?

Outras dicas

Serial comm usually involves send/receive buffers along with flow control. The normal flow is apparently being interrupted due to your implementation.

I suggest you migrate the code accessing the port into a background thread and have some sort of synchronized callback to the client GUI when appropriate. (one option being the simple Synchronize() call)

It remembers me having the same problem some years ago: clicking the mouse interrupted the serial communication with a PLC (serious!).

Don't know exactly how we fixed that, but I think it had something to do with the combination of an USB mouse, improper grounding and/or electronic/magnetic shielding of serial cable, too long serial cable, twisted USB/serial cable or something like that (yes it was a bit messy at the R&D workfloor...)

So maybe you can try changing and/or checking some hardware?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top