Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi COM Port Daten auslesen und auf bestimmtes Char reagieren (https://www.delphipraxis.net/188192-com-port-daten-auslesen-und-auf-bestimmtes-char-reagieren.html)

AJ_Oldendorf 8. Feb 2016 12:50

COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Hallo zusammen,
ich habe ein Gerät, welches mir ca. aller 10ms ein Wert über die serielle Schnittstelle liefert.
Dieser String hat immer den gleichen Aufbau und endet mit #13#10.
Das Gerät kann aber auch andere Daten schicken aber es wird immer mit #13#10 abgeschlossen.
In meiner Software habe ich eingestellt, dass ich auf das #10 reagieren möchte und damit das Ende eines Strings erkenne.
Leider wird mir immer der komplette Buffer gefüllt den ich bei ReadFile angegeben habe und nicht nur bis zu dem gesetztem RXFlagChar (#10).

Zum seriellen Gerät:
Baudrate: 19200
Parität: Keine
StopBits: 1

Hier ein Ausschnitt, wie ich die serielle Schnittstelle initialisiere:

Delphi-Quellcode:
  MyHandle := CreateFileA (tmpStr, Generic_Read or Generic_Write, 0, Nil,
                           Open_Existing, FILE_FLAG_OVERLAPPED, 0);
  if MyHandle <> INVALID_HANDLE_VALUE then
  begin
    if SetupComm (MyHandle, 1024, 1024) then  //eigentlich interessiert mich der Buffer nicht da ich immer nur bis #10 erkennen möchte
    begin
      FillChar (DCB, SizeOf(TDCB), 0);
      DCB.DCBlength := SizeOf (TDCB);
      DCB.BaudRate  := 19200;
      DCB.Flags     := $0001;
      DCB.Parity    := 0;
      DCB.ByteSize  := ByteSize;
      DCB.StopBits  := 0;
      DCB.EvtChar   := #10;
      if SetCommState (MyHandle, DCB) then
      begin
        With CommTimeOuts do
        begin                    
          ReadIntervalTimeout        := 10;
          ReadTotalTimeoutMultiplier := 0;
          ReadTotalTimeoutConstant   := 0;
          WriteTotalTimeoutMultiplier := 0;
          WriteTotalTimeoutConstant  := 0;
        end;
        if SetCommTimeouts(SerHandle, CommTimeOuts) then
        begin
          if SetCommMask(SerHandle, EV_RXFLAG) then
....
Die Software läuft soweit und die Kommunikation zum seriellen Gerät ist auch vorhanden nur habe ich wie gesagt das Problem, dass immer der komplette Buffer gefüllt wird, bevor ich ein Event bekomme. Ich hätte gerne ein Event nach jedem #10.

Hier der Ausschnitt vom ReadFile:

Delphi-Quellcode:
rOverlapped.Offset    := 0;
rOverlapped.OffsetHigh := 0;
ReadFile (MyHandle, ReceiveBuffer, 1024, ReceivedBytes, @rOverlapped);
Kann mir da jemand ein Tip geben wo ich weiter suchen könnte?

Viele Grüße

himitsu 8. Feb 2016 13:47

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Lies mal, was SetCommState zum EvtChar sagt. https://msdn.microsoft.com/en-us/lib.../aa363214.aspx

Das steuert nicht was du aussliest.
Mit ReadFile liest man immer so viel aus, wie man angibt.
Willst du das nicht, mußt du Char-Weise auslesen, oder einen Puffer/Zwischenspeicher verwenden.

MSDN-Library durchsuchenWaitCommEvent

Photoner 8. Feb 2016 13:51

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Wie wäre es mit dem lesen von jeweils einem Char? (wie himitsu´s Vorschlag)

Delphi-Quellcode:
 DCB.EvtChar := #0;
Beispiel:

Delphi-Quellcode:

function ReadChar(var MyChar : Char) : boolean;
var
  Buffer : array[0..1] of char;
  nReadChars : dword;

begin

  if not ReadFile (   MyHandle,
         Buffer,
         1,
         nReadChars,
         nil) then begin
    result := false;
    exit;
  end;

  if nReadChars = 0 then
    result := false
  else begin
    result := true;
    MyByte := Buffer[0];
  end;

end;

function GetAnswer(const ATimeOutInMS : Cardinal) : String;
var
 i          : Integer;
 TimeStamp  : Cardinal;
 AnswerChars : Array of Char;
 CurrentChar : Char;
begin
 TimeStamp := GetTickCount;
 Result   := '';
 while True do begin
  if ReadChar(CurrentChar) then begin
   // #13#10 beendet gültige Antwort:
   if CurrentChar=#13 then break;
   SetLength(AnswerChars,Length(AnswerChars)+1);
   AnswerChars[High(AnswerChars)] := CurrentChar;
  end;
  if GetTickCount>TimeStamp+ATimeOutInMS then begin
   //Result := 'Timeout beim Lesen';
   exit;
  end;
 end;
 SetLength(Result,Length(AnswerChars));
 for i:= 1 to Length(AnswerChars) do Result[i] := AnswerChars[i];
end

Verknüpft mit einem "ATimeOutInMS" von 9 (ms) sollte das deinen Zwecken genügen.

Evtl. ist noch was falsch im Code. Nur im Browser getippt; er ist nicht getestet.

AJ_Oldendorf 8. Feb 2016 13:57

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Ok, Zeichenweise auslesen wäre auch noch möglich aber ich dachte das "EvtChar" ist genau dafür da.
Da steht ja:
The value of the character used to signal an event.

Ich bin davon ausgegangen, dass ich ein Event bekomme wenn das entsprechende Char gefunden wurde im Buffer...

Das andere muss ich mir mal genauer angucken von "Photoner"

AJ_Oldendorf 8. Feb 2016 14:18

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Habe anstatt dem ReadFile folgenden Aufruf gemacht:

Delphi-Quellcode:
TmpMask := EV_RXFLAG;
WaitCommEvent(MyHandle, TmpMask, @rOverlapped);
Darauf wird auf alle Fälle reagiert aber wie komme ich jetzt an die Daten? Nach dem ReadFile stehen die Daten ja in dem übergebenen ReceiveBuffer.

Neumann 8. Feb 2016 14:20

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Warum die Comport-Geschichte selber bauen wenn es sie schon fertig gibt?

Komponente TComport Dejan Crnila, kann man mit allen Delphi-Versionen einsetzen und läuft bei mir einwandfrei.

Photoner 8. Feb 2016 14:25

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1329777)
Habe anstatt dem ReadFile folgenden Aufruf gemacht:

Darauf wird auf alle Fälle reagiert aber wie komme ich jetzt an die Daten? Nach dem ReadFile stehen die Daten ja in dem übergebenen ReceiveBuffer.

Du sagst es doch selber. Mach den ReceiveBuffer im ReadFile groß genug und gehe die einzelnen Chars dann durch bis du auf das #13#10 triffst. Alles davor ergibt dir deinen String. Dein Event signalisiert dir doch jetzt ob #10 im Buffer ist
(Zitat MSDN :
"EV_RXFLAG
0x0002
The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function."
)

AJ_Oldendorf 8. Feb 2016 14:46

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Folgendes habe ich vergessen zu sagen:
Ich brauche zu jedem Wert den ich übermittelt bekommen habe sozusagen ein Zeitstempel wann der Wert eingetroffen ist.
Wenn ich jetzt den Buffer sehr groß stelle, dann werden intern "ganz viele" Werte aufgesammelt. Anschließend soll ich die ja einzeln abgrasen und auf das bestimmte Ev_Char prüfen.
Ich will ja keine Verzögerung zwischen dem Eingang des Strings und der Weitergabe habe (also kein Buffer von x Strings).

Und die Länge vor dem #10 ist auch unterschiedlich. Ein String vor dem #10 kann mal 16 Bytes lang sein, mal aber auch nur 4 Byte oder 18 Bytes...

Photoner 8. Feb 2016 15:32

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Bin beim lesen darauf gestoßen:

Zitat MSDN:
------------------------------------------------------------------------------------------------------------------------------
ReadIntervalTimeout

The maximum time allowed to elapse before the arrival of the next byte on the communications line, in milliseconds. If the interval between the arrival of any two bytes exceeds this amount, the ReadFile operation is completed and any buffered data is returned. A value of zero indicates that interval time-outs are not used.

A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received.

------------------------------------------------------------------------------------------------------------------------------

Setz das und lese als Reaktion auf dein Event.

Dein Event "#10 Empfangen" wird gefeuert --> du hast einen kompletten String im Buffer und einen ziemlich exakten Zeitstempel.

Readfile blockiert mit der oben erwähnten Einstellung nicht (Zeitstempel hier ist also auch ok) und kommt sofort zurück (Wenn du 1024 bytes anforderst bekommst du trotzdem nur das was im Buffer -Stichwort ReceivedBytes- ist)

Zufrieden :)?

Sir Rufo 8. Feb 2016 15:36

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Also ich würde so etwas immer aufteilen.

Eine Klasse holt Bytefolgen vom ComPort ab und gibt diese mit dem Zeitstempel weiter.

Eine Klasse nimmt die Bytefolge/Zeitstempel Nachricht und baut bei jedem Vorkommen von #13#10 eine Nachricht mit Bytefolge/Zeitstempel und gibt diese weiter.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:53 Uhr.
Seite 1 von 4  1 23     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz