Serial Port Synchronization in Delphi

后端 未结 5 2036
醉酒成梦
醉酒成梦 2021-01-15 08:18

I am still having issues with the TComPort component but this time is not the component itself is the logic behind it. I have a device witch sends some ascii strings via ser

相关标签:
5条回答
  • 2021-01-15 08:40

    If your protocol has begin/end markers, you can use TComDataPacket to provide you full packets, when they are available.

    0 讨论(0)
  • 2021-01-15 08:41

    Typical handler for OnRXChar event:

    procedure XXX.RXChar(Sender: TObject; Count: Integer);
    begin
      ComPort.ReadStr(s, Count);
      Accumulator := Accumulator + s;
      if not AccumContainsPacketStart then
        Accumulator := ''
      else if AccumContainsPacketEndAfterStart then begin
        ExtractFullStringFromAccum;
        ParseIt;
      end;
    end;
    
    0 讨论(0)
  • 2021-01-15 08:48

    Note. Most com-port components do not have a clue when to report back to the owner. Normally the thread that is responsible to gather the bytes from the port is informed by the OS that one or more bytes are ready to be processed. This information is then simply popped up to your level. So when you expect the message to be transferred, you get what the OS is giving you.

    You have to buffer all incoming characters in a global buffer. When you get the final character in your message string, handle the message.

    Here is an example where the message start is identified with a special character and the end of the message is identified with another character.

    If your message is constructed in another way, I'm sure you can figure out how to adapt the code.

    var
      finalBuf: AnsiString;
    
    {- Checking message }
    Function ParseAndCheckMessage(const parseS: AnsiString) : Integer;
    begin
      Result := 0; // Assume ok
      {- Make tests to confirm a valid message }
      ...
    end;
    
    
    procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer);
    var
      i,err: Integer;
      strBuf: AnsiString;
    begin
      ComPort.ReadStr(strBuf, Count);
      for i := 1 to Length(strBuf) do
        case strBuf[i] of
          '$' : 
            finalBuf := '$';  // Start of package
          #10 :
            begin
              if (finalBuf <> '') and (finalBuf[1] = '$') then  // Simple validate check 
                begin
                  SetLength( finalBuf, Length(finalBuf) - 1); // Strips CR
                  err := ParseAndCheckMessage(finalBuf);
                  if (err = 0) then 
                    {- Handle validated string }
                  else
                    {- Handle error } 
                end;
              finalBuf := '';
            end; 
        else
          finalBuf := finalBuf + strBuf[i];  
        end;
    end;
    
    0 讨论(0)
  • 2021-01-15 08:50

    For certain amount of character we can use delay some miliseconds before ReadStr to make sure the data is completely sent. Example for 4 amount of character:

    procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
    var
      Str: String;
      tegangan : real;
    begin
      sleep(100); //delay for 100ms
      ComPort1.ReadStr(Str, 4);
    

    ...

    0 讨论(0)
  • 2021-01-15 08:51

    After using a number of serial-port-components, I've got the best results until now, by using CreateFile('\\?\COM1',GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0), passing that handle to a THandleStream instance, and starting a dedicated thread to read from it. I know threads take a little more work than writing an event handler, but it still is the best way to handle any synchronization issues that arise from using serial ports.

    0 讨论(0)
提交回复
热议问题