Announcement

Collapse
No announcement yet.

Hexwerte über ComPort ?!!?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hexwerte über ComPort ?!!?

    Hallo!<p>
    Ich glaube zwar, dass ich das folgende Problem schoneinmal gepostet habe, aber es bereitet mir eben wirklich Kummer!!<br>
    Und zwar kommuniziere ich mit meinem Delphi 5-Pogramm über die RS232 mit einem Pic. Dieser Pic schickt mir Hex-Werte und 'verlangt' von mir Hex-Werte, die ich senden soll!<br>
    Nun klappt das aber in meinem Programm nicht, ich empfange nur ASCII-Werte, wenn ich diese umwandle (->Ord) dann stimmen sie nicht mit denen des Pics überein und zum Zweiten 'verschluckt' mein Programm z.B. auch die empfangenen Nuller!<p>
    Ist es möglich eine Kommunikation aufzubauen, die nur mit Hex-Werten kommuniziert oder welche Möglichkeiten gibt es dieses Problem zu lösen?<p>
    Für jegliche Hilfe wäre ich riesig dankbar,<br>
    Markus

  • #2
    Hallo,<p>so wie sich das anhört, liegt es eventuell daran, wie du die Daten von der Schnittstelle abholst und auf die Schnittstelle sendest. Wie sieht der Quelltext senden/empfangen aus

    Comment


    • #3
      Hallo,<P>
      so sieht mein Quelltext aus:<P>
      <B>Senden:</B><BR>
      var dwError : DWord;<BR>
      aCOMStat : TCOMSTAT;<BR>
      dwBytes : DWord;<BR>
      dwRead : DWord;<BR>
      begin<BR>
      repeat<P>

      ClearCommError(hCOM, dwError, @aCOMStat);<BR>
      dwBytes := aCOMStat.cbInQue;<BR>
      if dwBytes > 0 then begin<BR>

      SetLength(sResult, dwBytes);<BR>
      ReadFile(hCOM, PChar(sResult)^, dwBytes, dwRead, nil);<BR>
      SetLength(sResult, StrLen(PChar(sResult)));<P>

      sString := sString + PChar(sResult);<P>

      end;<P>

      until (hCom = INVALID_HANDLE_VALUE;<BR>
      end;<P>
      <B>Empfangen:</B><BR>
      function TWriteComThread.WritePort(sData : String) : Boolean;<BR>
      var dwBytes : DWord;function TWriteComThread.WritePort<BR>
      begin<BR>
      If WriteFile(hCOM, PChar(sData)^, Length(sData), dwBytes, nil)<BR>
      then Result := true<BR>
      else Result := false;<BR>
      end<P>
      (Quelltext in Anlehnung an A. Koschs Win32-Lösung)<BR>
      Ich hoffe Du kannst mir helfen,<P>
      Marku

      Comment


      • #4
        Hallo,<p>so wie es aussieht, hast du Senden/Empfangen oben vertauscht. Oberer Teil ist Empfangen, unterer Teil ist Senden.<br>Nun noch eine Frage, wie wird das Empfangen realisiert (über einen Timer)? Es geht mir darum, in welcher Zeit wird der Eingangspuffer der Schnittstelle überprüft, ob Daten vorhanden sind.<p>Ich schau mal über Ostern den Code genauer an. Kann ein paar Tage dauern

        Comment


        • #5
          Hmm, das ist wohl richtig, hab ich in der Eile wohl vertauscht!<p>
          Also, es sieht so aus, dass Senden und Empfangen jeweils in einem eigenen Thread ablaufen. Diese Threads werden beim Öffnen der Schnittstelle erstellt und "resumed" sobald eine Aufgabe des Ports ansteht, danach wieder "suspended".<br>
          Nun kann man ja (denke ich jedenfalls) die Zeit, in der die Schnittstelle überprüft wird über die Threadpriorität bzw. auch über die PriorityClass steuern (überpüft werden Sie sowieso dauernd, es ist ja eine Schleife, aber somit könnte er dann öfter bzw. weniger oft überprüft werden). In Versuchen habe ich aber bemerkt, dass das kaum etwas bringt.<br>
          Während einer Aufgabe am Ports (Schreibe Befehl und erwarte danach die entsprechenden Daten: Echo, eingespeicherte Werte des Pics...) laufen "gleichzeitig" 3 Threads, während das Formular "gedisabled" wird. Vom Benutzer werden also keinerlei andere Aufgaben mehr angenommen, lediglich die aktuelle Anzeige des Status wird noch angezeigt.<p>
          So, ich hoffe sehr, dass Dir die Angaben weiterhelfen und Du mir vielleicht helfen kannst! (Vielleicht auch mit den Hex-Werten!!!)<p>
          Marku

          Comment


          • #6
            Hallo Markus,<p>
            dein Pic sendet und empfängt Hexwerte. Du schreibst die Daten als einen String zur Schnittstelle und liest die Daten über einen String wieder ein. Jetzt zum Problem: Wenn du die empfangenen Daten mit Hilfe von Ord<br> in einen numerischen Wert umwandelst, erhältst du nicht einen Hexwert sondern den Wert des ASCII-Zeichen.<br> Bei dem Zeichen "A" würde das so aussehen:
            <pre>
            Hex -> Ord -> Hex
            $A 41 $29
            </pre>
            Beim Schreiben ist es natürlich das gleiche. Angenommen du sendest den String "A". <br>Es wird nun nicht der Hexwert "$A" übertragen sondern das Zeichen "A". Dein Pic liest das Zeichen "A" als "$29" bzw "$41". Und das ist Falsch! Richtig wäre:
            <pre>
            Hex = Dez
            $A = 10
            </pre>
            Nun, entwerder du sendest/empfängst anstatt einem String einen Integerwert oder du wandelst den String richtig um. <br>Folgende Funktionen stehen dafür bereit: <b>InToStr</b>, <b>InToHex</b>, <b>StrToInt</b>, <b>StrToIntDel</b><br><p>
            Was die Sache mit den Nullern angeht: $00A4B = $A4B. <br>Die Nuller vorne können weggelassen werden. Sollten Nuller hinten verschluckt werden, hängt dies möglicherweise mit dem String zusammen.<p>
            Mein Tipp zum Thema "Empfangen":<br>
            Vorsicht! Bei langsamer Datenübertragung ist das Programm schneller als die ankommenden Daten. Ich habe das so gelöst: Wenn Daten im Eingangspuffer sind, lese ich nur immer ein Zeichen aus. Je nach Datenübertragung ist eine Zeitverzögerung eingebaut, die dann wieder (in einer Schleife) überprüft ob ein weiters Zeichen im Eingangspuffer ist. So kann es nicht vorkommen, dass z.B. nur ein Teil eines Hexwertes gelesen wird.<p>
            Fazit. Es liegt also nur daran, dass eine falsche "Umrechnung" verwendet wird.<p>
            Das nachfolgende Beispiel demonstriert die falsche Umrechnung mit Ord. In dem Forumlar befindet sich ein Button.
            <pre>uses
            Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
            StdCtrls;<p>
            type
            TForm1 = class(TForm)
            Button1: TButton;
            procedure Button1Click(Sender: TObject);
            private
            { Private-Deklarationen }
            public
            HexInteger: Integer;
            HexChar: Char;
            end;<p>
            var
            Form1: TForm1;<p>
            implementation<p>
            {$R *.DFM}<p>
            procedure TForm1.Button1Click(Sender: TObject);
            var
            NewHexStr: string;
            HexOrd: Integer;
            HexString: string;
            begin
            // 1. Schritt: Integer und String festlegen
            HexInteger := $A;
            HexChar := 'A';
            MessageBox(Handle, PChar(Format('HexInteger: "%x"; HexString: "%s"', [HexInteger, HexChar])),
            '1. Schritt: Grunddaten', mb_ok or MB_ICONINFORMATION);<p>
            // 2. Schritt Umwandlung:
            // HexInteger -> String;
            NewHexStr := IntToHex(HexInteger, 1);
            // HexString -> Ord;
            HexOrd := Ord(HexChar);
            MessageBox(Handle, PChar(Format('NewHexStr: "%s"; HexOrd: "%x"', [NewHexStr, HexOrd])),
            '2. Schritt: Umwandlung', mb_OK or MB_ICONINFORMATION);<p>
            //3. Schritt Umwandlung:
            //NewHexStr wieder in Integer
            HexInteger := StrToInt('$' + NewHexStr);
            //HexOrd wieder in String
            HexString := IntToHex(HexOrd, 1);
            MessageBox(Handle, PChar(Format('HexInteger: "%x"; HexString: "%s"', [HexInteger, HexString])),
            '3. Schritt: Grunddaten wieder?', mb_ok or MB_ICONINFORMATION);
            end;<p>
            end.
            </pre>
            Ich hoffe, das ist eine Hilfe für dich.<br>Viel Spass

            Comment


            • #7
              Vielen herzlichen Dank für die umfangreiche Hilfe!!!<p>

              Sie wird mir auf jeden Fall nützlich sein.<p>

              Nun aber noch zu 2 weiteren Fragen:<br>
              1. Wie sieht der Quelltext aus, wenn ich einen Integerwert über die Schnittstelle schicke/empfange? (-> Pointer bei ReadFile und WriteFile)<br>
              2. Weniger wichtig: Hast Du Source zu Deinem 'Tip zum Thema Empfangen'?<p>
              Hoffe ich nerve nicht,<p>
              nochmals vielen Dank<br>
              Marku

              Comment


              • #8
                Hallo,<p>
                zu Frage 1. Das hab ich mal wieder leichter gesagt als es ist. Um Integerwerte zu Senden/Empfangen fallen mir nur zwei Möglichkeiten ein.<br>
                1. Möglichkeit. Ich habe diese allerdings nur so ausprobiert indem ich die Daten in eine Datei geschrieben habe. Ob es mit deinem Pic funktioniert ist fraglich.
                <pre>
                var
                I: Integer;
                dwBytes: DWORD;
                begin
                WriteFile(hCOM, PChar(I), SizeOf(I), dwBytes, nil);
                end;<p>
                begin
                ReadFile(hCOM, PChar(I), dwBytes, dwRead, nil);
                end;
                </pre>
                2. Möglichkeit (etwas Umständlich) - sollte funktionieren:
                <pre>
                type
                THexArray = array[0..9] of Char;<p>
                var
                HexArray: THexArray;
                dwBytes: DWORD;
                L: Integer;
                begin
                HexArray[0] := #10; //Zeichen A (10)
                HexArray[1] := #11; //Zeichen B (11)
                L := 2;
                WriteFile(hCOM, HexArray, L, dwBytes, nil);
                end;<p>
                begin
                ReadFile(hCOM, HexArray, dwBytes, dwRead, nil);
                end;
                </pre>
                Zur Erklärung: Ich habe ein festes Array von 10 Stellen. Dieses Array füllst du mit dem entsprechenden Hexwert (Tabelle siehe unten). L steht für Länge des Array. D.h. werden z.B. nur zwei Stellen gefüllt, dann sollen bei WriteFile auch nur zwei Bytes übertragen werden.
                <pre>
                Hex Dez Char
                0 0 #0
                1 1 #1
                2 2 #2
                3 3 #3
                4 4 #4
                5 5 #5
                6 6 #6
                7 7 #7
                8 8 #8
                9 9 #9
                10 A #10
                11 B #11
                12 C #12
                13 D #13
                14 E #14
                15 F #15
                </pre>
                Es kann natürlich sein, dass dein Pic evtl. auch mit anderen Chars arbeitet. Es gibt auch noch eine dritte Mögichkeit, dass ganze mit einem dynamischen Array zu realisieren. (SetLength, usw)<p>
                Soll im Beispielsweise bei Möglichkeit 2 der Hexwert $3A übertragen werden, dann müsste das ganze so aussehen:
                <pre>
                HexArray[0] := #3;
                HexArray[1] := #10;
                WriteFile(hCOM, HexArray, 2, dwBytes, nil);
                </pre>
                Beim Lesen ist das ganze natürlich das Gleiche.<p>
                Fazit: Am besten Hexwert "zerlegen", in einem Array ablegen und absenden.
                <p>
                Zu Frage 2: Quellbeispiel kommt in ein paar Tagen noch nach.<p>
                Achso, nein, du nervst nicht. Egal, wie du diese Aufgabe dann gelöst hast, es würde mich interessieren. Bei allen Komponenten, die ich kenne (für serielle Schnittstelle) werden die Daten entweder als String oder als Array zur Schnittstelle übertragen

                Comment


                • #9
                  Hallo Elmar,<p>
                  auch ich hab' mal experimentiert und bei meinen Versuchen über ein Nullmodemkabel und dem HyperTerminal hat folgender Code wunderbar funktioniert (hat mich gewundert!!):<p>

                  var dwBytes : DWord;<br>
                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iVariable : Integer;<br>
                  begin<br>
                  &nbsp;&nbsp;iVariable := $FF; // zum Bsp!<br>
                  &nbsp;&nbsp;If not WriteFile(hCom, PByte(iVariable), 1, dwBytes, nil)<br>
                  &nbsp;&nbsp;then ShowMessage('Fehler beim Schreiben auf ' + cCOM);<br>
                  end;<p>

                  So, das war das Schreiben. Das Lesen funktioniert aber nicht ganz so einfach, glaub' ich. Das ist momentan noch mein Problem. Wenn ich das gelöst habe sieht's super aus!!! Vielleicht hast du mir ja noch einen Tip dazu.<br>
                  Also, ich studiere jetzt einmal genau deinen letzten Kommentar, vielleicht komme ich dann auf eine Lösung.<p>
                  Bis dann,<br>
                  Marku

                  Comment


                  • #10
                    Hallo Markus,<p>hier der Quelltext (Frage 2 vom 16.04.2001).
                    <pre>
                    var
                    hCOM: THandle;
                    I: Integer;
                    <p>
                    const
                    cBaud: array[0..13] of Cardinal = (110, 300, 600, 1200, 2400, 4800,
                    9600, 14400, 19200, 56000, 57600, 115200, 128000, 256000);
                    cSleep: array[0..13] of Integer = (250, 200, 180 ,160, 140, 120,
                    100, 80, 70, 50, 30, 10, 0, 0)
                    <p>
                    function OpenCom: Boolean;
                    var
                    hDBC: TDCB;
                    begin
                    Result := False;
                    cCOM := TStrings[I]; //Wie du die Anzahl der COM-Ports festellen kannst,
                    findest du einige Fragen weiter unten in diesem Ornder
                    hCOM := CreateFile(PChar(cCOM), GENERIC_READ or GENERIC_WRITE, 0, nil,
                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
                    if hCOM = INVALID_HANDLE_VALUE then Exit;
                    if GetCommState(hCOM, hDBC) then begin
                    with hDBC do begin
                    BaudRate := cBaud[I]; //Baudrate durch den Anwender
                    ByteSize := 8;
                    Parity := NOPARITY;
                    StopBits := ONESTOPBIT;
                    Flags := 0;
                    end;
                    if SetCommState(hCOM, hDBC) then Result := True;
                    end;
                    end;
                    <p>
                    procedure CloseCom;
                    begin
                    if hCOM <> INVALID_HANDLE_VALUE then CloseHandle(hCOM);
                    hCOM := INVALID_HANDLE_VALUE;
                    end;
                    <p>
                    function WriteData(P: Pointer): Integer;
                    begin
                    if WriteFile(hCOM, PChar(P)^,
                    SizeOf(P), dwBytes, nil) then
                    Result := dwBytes else Result := -1;

                    end;
                    <p>
                    function ReadData: Pointer;
                    var
                    P, Px: Pointer;
                    begin
                    ClearCommError(hCOM, dwError, @aCOMStat);
                    dwBytes := aCOMStat.cbInQue;
                    while dwBytes > 0 do
                    begin
                    ReadFile(hCOM, PChar(P), 1, dwRead, nil);
                    Sleep(cSleep[I]) //Integerwert ist gleicher wie bei cBaud
                    Px := Px + P; //Steht symbolisch hier und soll bedeuten, hier wird
                    das ausgelesen Byte in einen Buffer kopiert.
                    end;
                    Result := Px; //Rückgabewert der Funktion
                    end;
                    </pre>
                    Diese Methode liest immer nur ein Zeichen von der Schnittstelle. Durch Sleep wird das Programm für cSleep[i] Millisekunden angehalten (mit diesen Werten kommt man mit allen Rechner recht gut hin). So ist der Rechner auch bei sehr langsamen Baudraten nicht schneller als das Schreiben und das Lesen von der Schnittstelle. Diese Funktion ist immer dann nötig, wenn man ein Datenmege die von der Schnittstelle bekommt und dies auswerten muss. Bei vielen Komponenten und auch dem Windows Hyperterminal wird ebenfalls immer nur ein Byte von der Schnittstelle abgeholt und sofort auf dem Monitor ausgegeben.<br>
                    Also dein Pic schickt dir Daten. Selbst bei einer langsamen Baudrate bekommst du den gesamten Hexwert zurückgeliefert. Ein "Trennen" des Werts ist so nicht möglich.<br>
                    Das Lesen von der Schittstelle habe ich über einen Timer gelöst. So können in der Zwischenzeit andere Aufgaben erledigt werden, und eine Fehlanzeige "Programm reagiert nicht mehr" vermieden werden

                    Comment


                    • #11
                      Hallo Elmar,<p>
                      folgende Neuigkeiten:<p>
                      1. Habe vielleicht eine Lösung des Problems gefunden. Da der Pic wohl einen anderen Zeichensatz hat, sind alle Ansätze mit string oder char zwecklos. Bin jetzt auf Integer- bzw. Bytezahlen umgestiegen. Wenn mein Programm einwandfrei läuft poste ich hier die Lösung!<p>
                      2. Zu 'Sleep': Je länger meine Sleeppause ist, desto mehr Zeichen verschluckt mein Programm. (Genau das Gegenteil Deiner Erfahrungen. Ich bin etwas verwirrt!!!) Hast Du eine Erklärung???<p>
                      3. Hast Du bei Deinem Quellcodeauszug (vom 21. Apr.) etwas vergessen (-> <tt>function ReadData: Pointer</tt>)? Dadurch, dass keine Abfrage von <tt>dwBytes</tt> in der Schleife gemacht wird ist dies wohl eine Endlosschleife!?!<p>
                      Ich wäre Dir sehr dankbar wenn Du mir noch einen Tip hättest bezüglich den 'verschluckenden Zeichen'. Das ist momentan noch mein Problem. Hängt es vielleicht mit dem Thread zusammen???<p>
                      Also, ich mach mich wieder an die Arbeit,<br>
                      Marku

                      Comment


                      • #12
                        Hallo Markus,<p>
                        zu Frage 1: So etwas in dieser Richtung habe ich vermutet....<p>
                        zu Frage 2: Mit Thread habe ich leider keine Erfahrung. Meine Projekte habe ich bisher immer über einen Timer programmiert. Und da hats funktioniert.<p>
                        zu Frage 3: Uuupppppsss!<br>
                        Ja, da habe ich eine paar Zeile vergessen (der ursprüngliche Code hat etwas anders ausgesehen). Danke. Hier kommt der komplette Code:
                        <pre>
                        function ReadData: Pointer;
                        var
                        P, Px: Pointer;
                        begin
                        ClearCommError(hCOM, dwError, @aCOMStat);
                        dwBytes := aCOMStat.cbInQue;
                        while dwBytes > 0 do
                        begin
                        ReadFile(hCOM, PChar(P), 1, dwRead, nil);
                        Sleep(cSleep[I]) //Integerwert ist gleicher wie bei cBaud
                        Px := Px + P; //Steht symbolisch hier und soll bedeuten, hier wird
                        das ausgelesen Byte in einen Buffer kopiert.
                        ClearCommError(hCOM, dwError, @aCOMStat);
                        dwBytes := aCOMStat.cbInQue;
                        end;
                        Result := Px; //Rückgabewert der Funktion
                        end;
                        </pre&gt

                        Comment


                        • #13
                          Hallo,

                          Für das Senden/ Empfangen über WriteFile und ReadFile wird nicht
                          unbedingt ein Array of Char benötigt. Definiert man ein
                          Array of Byte so können Hexdaten direkt empfangen bzw. gesendet werden.

                          var Buffer : Array[0..1023] of Byte;
                          Haswritten: cardinal;
                          WriteFile(HCOM,Buffer,sizeof(buffer),HasWritten,ni l)

                          Comment

                          Working...
                          X