Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Ergebnis 1 bis 10 von 10

Thema: libnodave: Drehen von Bytes nicht immer nötig?!

  1. #1
    Registriert seit
    30.08.2007
    Beiträge
    207
    Danke
    16
    Erhielt 22 Danke für 17 Beiträge

    Pfeil


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hallo,

    ich habe in VB.net eine kleine Anwendung geschrieben, mit der ich einzelne Datenbereiche aus der S7-300 via MPI-RS232-Adapter auslesen kann.
    Damit ich sehe, was auf der RS232-Leitung passiert, zeichnet ein Serial-Monitor die Daten auf.

    Nun habe ich ein Problem mit der Interpretation der Daten, jedenfalls weiß ich nicht, wann ich Bytes drehen muss und wann nicht.
    Ich lese später nur die Bytes ein, die ich dann ein wenig umher schieben muss! Das Zielsystem arbeitet mit little endian.

    Dazu zwei Beispiele (die relevanten "Datenbytes" sind fett markiert):

    Ich lese das EW0 aus:
    ... 0xFF 0x04 0x00 0x10 0x10 0x01 0x80 0x10 0x03 ...
    Folgende Eingänge sind aktiv: E0.0 und E1.7
    Macht in Dual: 00000001 10000000 = 1 und 128 in Dezimal.
    Die Bytes werden getauscht und zu einem 16bit-Wert zusammengefasst:
    10000000 00000001 = 32769 in Dezimal
    Hier muss getauscht werden!

    Nun lese ich ein INT aus:
    ... 0xFF 0x04 0x00 0x10 0x10 0x7F 0xFF 0x10 0x03 ...
    Als Dezimalwert erwarte ich 32767.
    Macht in Dual: 01111111 11111111 = 127 und 255 in Dezimal.
    Die Bytes werden getauscht und zu einem 16bit-Wert zusammengefasst:
    11111111 01111111 = 65407 in Dezimal
    Das passt nicht, da 65407 ungleich 32767 ist!
    Drehe ich nicht:
    01111111 11111111 = 32767 in Dezimal
    Hier darf nicht getauscht werden!

    Wenn ich mir das INT in dualer Schreibweise angucke, sieht man auf dem ersten Blick, dass man nicht drehen darf, da ich eine positive Zahl erwarte und das höchstwertigste Bit 0 sein muss.

    Zu guter Letzt habe ich einen Zähler erstellt, der in einen DB den Zählerstand schreibt.
    Als Datentyp im DB habe ich WORD genommen und mir mal in der Online-Beobachtung die Änderung des Wertes im DB angeguckt.
    Was aufgefallen ist, ist, dass das zweite Datenbyte zuerst hochgezählt wird, danach das erste Datenbyte.
    Also:
    Zählerstand 255 = 0x00 0xFF = 00000000 11111111
    Zählerstand 256 = 0x01 0x00 = 00000001 00000000
    Hier darf auch nicht getauscht werden!

    So, warum muss man nun beim Eingangswort die Bytes tauschen und z.B. bei einem Zählwert (als WORD) nicht?

    Und allgemein: Wie erkennt man, ob man die "Datenbytes" drehen muss oder nicht?

    Gruß,
    poppycock
    Mit einem Computer löst man die Probleme, die man ohne einen Computer nicht hätte.
    Zitieren Zitieren libnodave: Drehen von Bytes nicht immer nötig?!  

  2. #2
    Registriert seit
    12.04.2010
    Beiträge
    300
    Danke
    22
    Erhielt 54 Danke für 52 Beiträge

    Standard

    Hallo,

    eventuell interpretierst du die Quelle falsch?
    Wenn die Quelle ein Byte ist (also 1 Byte breit) dann nicht tauschen, wenn du 2 x 1 Byte bekommst, nicht tauschen, wenn du 1 x 2 Byte bekommst, dann tauschen.


    Tauschen muss du folgendes

    Code:
    BYTE (1 Byte) .... nein
    WORD (2 Byte)  HB, LB --> LB, HB
    INT  (4 Byte) HHB, HB, LB, LLB --> LLB, LB, HB, HHB

  3. #3
    Avatar von poppycock
    poppycock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    30.08.2007
    Beiträge
    207
    Danke
    16
    Erhielt 22 Danke für 17 Beiträge

    Ausrufezeichen

    Hallo bits'bytes!

    Zitat Zitat von bits'bytes Beitrag anzeigen
    eventuell interpretierst du die Quelle falsch?
    Da ist was dran! Ich muss ja selber entscheiden, wie ich die Quelle zu interpretieren habe.

    Wichtiger Hinweis: Das Zielsystem ist ein 8bit-Mikrocontroller.
    Daher muss ich mit jeweils einem Byte "rechnen" und dieses auch verschieben, wenn nötig!


    Ich habe ein paar Mitschnitte von der seriellen Schnittstelle erstellt.
    Die Bytes, die ich zu interpretieren habe, sind farbig und fett gekennzeichnet:

    Eingangsbyte 0:
    Code:
    Request: 01.06.2011 12:52:35.11864 (+158.8985 seconds)
     02
    Answer: 01.06.2011 12:52:35.11864 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:52:35.12864 (+0.0100 seconds)
     04 82 80 0C 03 14 F1 01 32 01 00 00 00 00 00 0E 
     00 00 04 01 12 0A 10 10 02 00 01 00 00 81 00 00
     00 10 03 5C
    Answer: 01.06.2011 12:52:35.13864 (+0.0100 seconds)
     10 02
    Request: 01.06.2011 12:52:35.15864 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:52:35.16864 (+0.0100 seconds)
     04 82 80 0C 14 03 B0 01 01 10 03 BE
    Request: 01.06.2011 12:52:35.17864 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:52:35.17864 (+0.0000 seconds)
     02
    Request: 01.06.2011 12:52:35.17864 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:52:35.18864 (+0.0100 seconds)
     04 82 80 0C 14 03 F1 01 32 03 00 00 00 00 00 02
     00 05 00 00 04 01 FF 04 00 08 01 10 03 3F
    Request: 01.06.2011 12:52:35.19864 (+0.0000 seconds)
     10 02
    Answer: 01.06.2011 12:52:35.19864 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:52:35.19864 (+0.0000 seconds)
     04 82 80 0C 03 14 B0 01 01 10 03 BE
    Answer: 01.06.2011 12:52:35.20864 (+0.0100 seconds)
     10
    Hier kann natürlich nicht getauscht werden!

    -

    Eingangsbyte 1:
    Code:
    Request: 01.06.2011 12:52:53.40364 (+17.1947 seconds)
     02
    Answer: 01.06.2011 12:52:53.40364 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:52:53.41364 (+0.0100 seconds)
     04 82 80 0C 03 14 F1 02 32 01 00 00 00 01 00 0E
     00 00 04 01 12 0A 10 10 02 00 01 00 00 81 00 00
     08 10 03 56
    Answer: 01.06.2011 12:52:53.41364 (+0.0000 seconds)
     10 02
    Request: 01.06.2011 12:52:53.44364 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:52:53.44364 (+0.0000 seconds)
     04 82 80 0C 14 03 B0 01 02 10 03 BD
    Request: 01.06.2011 12:52:53.45364 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:52:53.46364 (+0.0100 seconds)
     02
    Request: 01.06.2011 12:52:53.46364 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:52:53.46364 (+0.0000 seconds)
     04 82 80 0C 14 03 F1 02 32 03 00 00 00 01 00 02
     00 05 00 00 04 01 FF 04 00 08 80 10 03 BC
    Request: 01.06.2011 12:52:53.47364 (+0.0000 seconds)
     10 02
    Answer: 01.06.2011 12:52:53.48364 (+0.0100 seconds)
     10
    Request: 01.06.2011 12:52:53.48364 (+0.0000 seconds)
     04 82 80 0C 03 14 B0 01 02 10 03 BD
    Answer: 01.06.2011 12:52:53.48364 (+0.0000 seconds)
     10
    Auch hier kann natürlich nicht getauscht werden!

    -

    Eingangswort 0:
    Code:
    Request: 01.06.2011 12:53:11.61964 (+18.1361 seconds)
     02
    Answer: 01.06.2011 12:53:11.62964 (+0.0100 seconds)
     10
    Request: 01.06.2011 12:53:11.63964 (+0.0100 seconds)
     04 82 80 0C 03 14 F1 03 32 01 00 00 00 02 00 0E
     00 00 04 01 12 0A 10 10 02 00 02 00 00 81 00 00
     00 10 03 5F
    Answer: 01.06.2011 12:53:11.63964 (+0.0000 seconds)
     10 02
    Request: 01.06.2011 12:53:11.66964 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:53:11.66964 (+0.0000 seconds)
     04 82 80 0C 14 03 B0 01 03 10 03 BC
    Request: 01.06.2011 12:53:11.67964 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:53:11.68964 (+0.0100 seconds)
     02
    Request: 01.06.2011 12:53:11.68964 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:53:11.68964 (+0.0000 seconds)
     04 82 80 0C 14 03 F1 03 32 03 00 00 00 02 00 02
     00 06 00 00 04 01 FF 04 00 10 10 01 80 1003 B4
    Request: 01.06.2011 12:53:11.69964 (+0.0000 seconds)
     10 02
    Answer: 01.06.2011 12:53:11.70964 (+0.0100 seconds)
     10
    Request: 01.06.2011 12:53:11.70964 (+0.0000 seconds)
     04 82 80 0C 03 14 B0 01 03 10 03 BC
    Answer: 01.06.2011 12:53:11.70964 (+0.0000 seconds)
     10
    Hier muss ich jedes Byte einzeln interpretieren, da ich 2x ein Byte einlese!
    Ein Byte gehört EB0 und ein Byte EB1, also tauschen!


    -

    DB11.DBW2:
    Code:
    Request: 01.06.2011 12:53:47.19264 (+36.4825 seconds)
     02
    Answer: 01.06.2011 12:53:47.19264 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:53:47.20264 (+0.0100 seconds)
     04 82 80 0C 03 14 F1 04 32 01 00 00 00 03 00 0E
     00 00 04 01 12 0A 10 10 02 00 02 00 0B 84 00 00
     10 10 10 03 57
    Answer: 01.06.2011 12:53:47.21264 (+0.0100 seconds)
     10 02
    Request: 01.06.2011 12:53:47.23264 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:53:47.23264 (+0.0000 seconds)
     04 82 80 0C 14 03 B0 01 04 10 03 BB
    Request: 01.06.2011 12:53:47.25264 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:53:47.25264 (+0.0000 seconds)
     02
    Request: 01.06.2011 12:53:47.25264 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:53:47.25264 (+0.0000 seconds)
     04 82 80 0C 14 03 F1 04 32 03 00 00 00 03 00 02
     00 06 00 00 04 01 FF 04 00 10 10 80 00 10 03 B3
    Request: 01.06.2011 12:53:47.27264 (+0.0000 seconds)
     10 02
    Answer: 01.06.2011 12:53:47.27264 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:53:47.27264 (+0.0000 seconds)
     04 82 80 0C 03 14 B0 01 04 10 03 BB
    Answer: 01.06.2011 12:53:47.28264 (+0.0100 seconds)
     10
    Ich erware die dezimale Zahl -32768.
    0x8000 = 0b1000000000000000 -> passt, hier darf nicht getauscht werden!


    -

    DB11.DBD4:
    Code:
    Request: 01.06.2011 12:54:06.88964 (+18.6068 seconds)
     02
    Answer: 01.06.2011 12:54:06.88964 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:54:06.89964 (+0.0100 seconds)
     04 82 80 0C 03 14 F1 05 32 01 00 00 00 04 00 0E
     00 00 04 01 12 0A 10 10 02 00 04 00 0B 84 00 00
     20 10 03 77
    Answer: 01.06.2011 12:54:06.90964 (+0.0100 seconds)
     10 02
    Request: 01.06.2011 12:54:06.92964 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:54:06.93964 (+0.0100 seconds)
     04 82 80 0C 14 03 B0 01 05 10 03 BA
    Request: 01.06.2011 12:54:06.94964 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:54:06.94964 (+0.0000 seconds)
     02
    Request: 01.06.2011 12:54:06.94964 (+0.0000 seconds)
     10
    Answer: 01.06.2011 12:54:06.95964 (+0.0100 seconds)
     04 82 80 0C 14 03 F1 05 32 03 00 00 00 04 00 02
     00 08 00 00 04 01 FF 04 00 20 07 5B CD 15 10 03
     9F
    Request: 01.06.2011 12:54:06.96964 (+0.0000 seconds)
     10 02
    Answer: 01.06.2011 12:54:06.96964 (+0.0000 seconds)
     10
    Request: 01.06.2011 12:54:06.96964 (+0.0000 seconds)
     04 82 80 0C 03 14 B0 01 05 10 03 BA
    Answer: 01.06.2011 12:54:06.97964 (+0.0100 seconds)
     10
    Ich erwarte den Wert 123456789 -> passt.
    Auch hier darf ich nicht tauschen!

    -

    Wie ich das auf dem Mikrocontroller (als Fake-Code) berechne:
    Code:
    // EB0:
    wert = byte[0];  // 0x01
    
    // EB1:
    wert = byte[1];  // 0x80
    
    // EW0:
    wert = (byte[1]<<8) + byte[0];  // 0x8000 + 0x01 = 0x8001
    
    usw...
    Was mich jetzt nur wundert, ist, dass ich die Bytes (wenn ich das richtig verstanden habe) nur bei Eingängen oder Ausgängen drehen muss und als x mal ein Byte interpretieren muss.
    Denn ansonsten muss die Bytereihenfolge so bestehen bleiben.
    Denkfehler meinerseits?

    Ich habe leider keine analogen Ein- und Ausgänge, aber ich denke, dass ich wie bei EW oder AW (nicht PEW oder PAW) die Bytereihenfolge drehen muss. Kann jemand mal bitte den Datenverkehr wie ich aufzeichnen und hier posten?
    Ich habe das Programm Free Serial Port Monitor von der Firma HHD benutzt.

    Gruß,
    poppycock
    Mit einem Computer löst man die Probleme, die man ohne einen Computer nicht hätte.
    Zitieren Zitieren Zielsystem: 8bit-Mikrocontroller  

  4. #4
    Registriert seit
    19.06.2003
    Beiträge
    2.200
    Danke
    85
    Erhielt 259 Danke für 175 Beiträge

    Standard

    Du hast mich gebeten, mir den Thread anzusehen. Ich "sehe" aber auch nicht auf einen Blick, wo dein Problem liegt.

    Ein 8-Bit-Mikrocontroller hat erstmal gar keine "Endianness".
    Du kannst Assembler-Programme schreiben, die die 16-Bit-Zahl 16394 als
    01000000 00001010 (big)
    oder
    00001010 01000000 (little)
    im Speicher ablegen.

    Die 32-Bit-Zahl 16394 ist dann:
    00000000 00000000 01000000 00001010 (big)
    oder
    00001010 01000000 00000000 00000000 (little)

    Wenn du eine höhere Programmiersprache verwendest, z.B. C, so legen der Compiler und die Laufzeitbiliothek fest, an welche Konvention sie sich halten.
    und erhälst
    Die S7 verwendet big endian und wenn es dein Compiler/bibliothek anders halten, mußt du Mehrbyte-Variablen konvertieren.

    Wenn du in der S7 ausführst:
    L +66
    T MD 6
    so werden MB6,7,8 und 9 verändert
    und es steht
    0 0 0 66 darin.
    Du kannst das MW8 laden und erhälst gleichfalls 66. Das Laden von MW6 liefert hingegen 0.

    In C sieht das so aus
    int32 * zeiger; // Ein Zeiger. Hier verwendet, um absolute //Speicheradressen zu erzwingen
    int16 * zeiger6;
    int16 * zeiger8;
    zeiger=6;
    // Der Zeiger zeigt jetzt auf Byte 6
    zeiger6=6; zeiger8=8;
    *zeiger=66;
    // Lade Speicherstelle 6 mit 66
    //Auf einem "little endian"-System steht nun
    // 66 0 0 0 in Speicherstellen 6,7,8,9
    //Auf einem "big endian"-System steht nun
    // 0 0 0 66 in Speicherstellen 6,7,8,9
    printf("%d %d\n",*zeiger6,*zeiger8 );
    // druckt 66 0 auf dem LE-System
    // druckt 0 66 auf dem BE-System

    Libnodave transferiert eine Folge von Bytes vom Speicher der S7 zum Speicher des Rechners. Welche Byte-Sequenzen auf einem "little endian" Rechner zu tauschen sind, hängt davon ab, wie der S7-Speicher genutzt wird, d.h. wo Mehrbyte-Zahlen beginnen.

    HTH
    Geändert von Zottel (01.06.2011 um 20:53 Uhr)

  5. #5
    Avatar von poppycock
    poppycock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    30.08.2007
    Beiträge
    207
    Danke
    16
    Erhielt 22 Danke für 17 Beiträge

    Standard

    Hallo Zottel!

    Zitat Zitat von Zottel Beitrag anzeigen
    Du hast mich gebeten, mir den Thread anzusehen.
    Ja, vielen Dank, dass du dir die Mühe gemacht hast!

    Zitat Zitat von Zottel Beitrag anzeigen
    Ich "sehe" aber auch nicht auf einen Blick, wo dein Problem liegt.
    Mein Problem lieg in der Interpretation der (einzelnen) einzulesenden Bytes.

    Zitat Zitat von Zottel Beitrag anzeigen
    Ein 8-Bit-Mikrocontroller hat erstmal gar keine "Endianness".
    Ja, das stimmt! Ich betrachte die "wichtigen" Bytes einzeln, quasi jeweils als 8bit-Wert.

    Zitat Zitat von Zottel Beitrag anzeigen
    Wenn du eine höhere Programmiersprache verwendest, z.B. C, so legen der Compiler und die Laufzeitbiliothek fest, an welche Konvention sie sich halten.
    Ich verwende AVR-GCC und das AVR Studio von Atmel.
    In der Regel sollte der AVR die shorts und longs etc. als little endian betrachten, jedenfalls zeigt es mir so das Display an und habe auch nichts anderes darüber gelesen.

    Zitat Zitat von Zottel Beitrag anzeigen
    Libnodave transferiert eine Folge von Bytes vom Speicher der S7 zum Speicher des Rechners. Welche Byte-Sequenzen auf einem "little endian" Rechner zu tauschen sind, hängt davon ab, wie der S7-Speicher genutzt wird, d.h. wo Mehrbyte-Zahlen beginnen.
    Ja, genau, und da liegt auch das Problem.

    Ich lese jedes Byte einzeln ein und speichere das in einem char-Array.

    Ich beziehe mich jetzt auf die Eingänge EB0 und EB1.
    So wird es über die serielle Schnittstelle transportiert: ... 0x01 0x80 ...
    EB0 hat den Wert 0x01 -> z.B. gespeichert in byte[26]
    EB1 hat den Wert 0x80 -> z.B. gespeichert in byte[27]
    Im EB0 ist E0.0 gesetzt: macht in dezimal: 1
    Im EB1 ist E1.7 gesetzt: macht in dezimal: 128
    Betrachte ich das EW0 dual: 0b0000000110000000 = 384 = falsch!
    Ich muss rechnen: 2^16 + 2^0 = 65537, also die Bytes tauschen!
    D.h. ich caste das char vom EB1 zum unsigned short und schiebe den Wert um 8 stellen nach links.
    Den Wert vom EB0 addiere ich einfach dazu.
    Als Ergebnis erhalte ich: 0b1000000000000001, und das ist richtig.
    Somit habe ich quasi die Bytes getauscht!

    Nun beziehe ich mich auf das DB11.DBW2:
    DB11.DBW
    wird so über die serielle Schnittstelle transportiert: ... 0x80 0x00 ...
    Also:
    byte[26] = 0x80
    byte[27] = 0x00
    Binär ausgedrückt: 0b
    1000000000000000
    Das ist schon das richtige Endergebnis, da ich
    -32768 erwarte.
    Wenn ich aber so vorgehe wie beim EW0, dann wird 0x00 als unsigned short gecastet, um 8 Stellen nach links verschoben und 0x80 hinzuaddiert.
    Als duales Ergebnis bekomme ich 0b0000000010000000, und das ist falsch!

    In beiden Fällen lese ich ein WORD (Oder etwa nicht?) aus, muss aber jeweils die Bytes anders interpretieren!
    Das "warum das so ist" verstehe ich nicht, sorry.
    Kann ich generell davon ausgehen, dass EW und AW prinzipiell als x mal ein Byte zu interpretieren sind?

    Gruß,
    poppycock
    Mit einem Computer löst man die Probleme, die man ohne einen Computer nicht hätte.

  6. #6
    Registriert seit
    19.06.2003
    Beiträge
    2.200
    Danke
    85
    Erhielt 259 Danke für 175 Beiträge

    Standard

    Zitat Zitat von poppycock Beitrag anzeigen
    Ich verwende AVR-GCC und das AVR Studio von Atmel.
    In der Regel sollte der AVR die shorts und longs etc. als little endian betrachten, jedenfalls zeigt es mir so das Display an und habe auch nichts anderes darüber gelesen.
    Ok
    Zitat Zitat von poppycock Beitrag anzeigen
    Ich beziehe mich jetzt auf die Eingänge EB0 und EB1.
    So wird es über die serielle Schnittstelle transportiert: ... 0x01 0x80 ...
    EB0 hat den Wert 0x01 -> z.B. gespeichert in byte[26]
    EB1 hat den Wert 0x80 -> z.B. gespeichert in byte[27]
    Im EB0 ist E0.0 gesetzt: macht in dezimal: 1
    Im EB1 ist E1.7 gesetzt: macht in dezimal: 128
    So. Und hier beginnen die verschiedenen Interpretationsmöglichkeiten:
    Ein BE-System interpretiert den 16-Bit-Wert als 256*EB0+EB1, also 384.
    Ein LE-System interpretiert den 16-Bit-Wert als 256*EB1+EB0. Was das ist, hängt auch noch davon ab, ob das höchste Bit als Vorzeichen angesehen wird.
    Zitat Zitat von poppycock Beitrag anzeigen
    Ich muss rechnen: 2^16 + 2^0 = 65537
    Nein, nicht rechnen! Kann mir mal ein Mensch erklären, warum soviele Leute dazu Potenzrechnungen anstellen wollen?
    Zitat Zitat von poppycock Beitrag anzeigen
    , also die Bytes tauschen!
    Eben. "Die Bytes tauschen" ist viel einfacher (Geschwindigkeit) und liefert IMMER das richtige Ergebnis. Beim Potenzrechnen hängt es von der Zahlendarstellung ab: float a=2^31; float b=2^0; a=a+b; und schon fällt die Eins aus der 23-Bit-Mantisse einfach raus...
    Zitat Zitat von poppycock Beitrag anzeigen
    D.h. ich caste das char vom EB1 zum unsigned short und schiebe den Wert um 8 stellen nach links.
    Den Wert vom EB0 addiere ich einfach dazu.
    Hoffe, dein Compiler ist so schlau, den Spezialfall "8 Stellen schieben" durch "tausche Bytes" zu ersetzen! Sonst packt er dir da womöglich 8 mal
    LSL r0
    ROL r1
    in den Maschinencode...
    Schau dir die Tauschfunktionen in Libnodave an. Die machen das mit unions aus Byte-Array und Zielformat.
    Zitat Zitat von poppycock Beitrag anzeigen
    Also:
    byte[26] = 0x80
    byte[27] = 0x00
    Binär ausgedrückt: 0b
    1000000000000000
    Das ist schon das richtige Endergebnis, da ich
    -32768 erwarte.

    Nee, auf einem LE-System ist der 16Bit-Wert ab Byte 26
    256*[byte27]+[byte26], also 256*0+128 !!!!!!!!!!!!!!!!!!!!!
    Zitat Zitat von poppycock Beitrag anzeigen
    Kann ich generell davon ausgehen, dass EW und AW prinzipiell als x mal ein Byte zu interpretieren sind?
    Die Regeln sind für DW, MW, AW, EW absolut gleich. Eine andere Frage ist, ob es sinnvoll ist, EWs oder AWs als Zahlen zu interpretieren statt als unabhängige Bits. Das muß man aber auch schon beim S7-Programmieren beachten: Ob etwa L EW0, L 5, -I etwa eine sinnvolle Anweisungsfolge seien könnte, hängt von der Umgebung ab. Wenn an E0.0 bis E1.7 etwas angschlossen ist, das Binärzahlen über parallele Leitungen liefert, dann ja.

    Nehmen wir an, es hängt tatsächlich so ein Ding an E0.0 bis E1.7. Nehmen wir an, dieses Ding sei eine Waage.

    L EW0 liefert dir in der S7 eine Zahl, ein Bruttogewiicht, z.B. 666.
    L EW0, L 5, -I, T DB11.DBW2 errechnet das Netto, weil da z.B. ein Behälter 5kg Tara hat.
    Du hast nun: EW0=666,EB0=2,EB1=154, DB11.DBW2=661, DB11.DBB2=2, DB11.DBB3=149
    Das kannst du bis hierher alles mit Step7 nachvollziehen.

    Nun liest du 2 Bytes ab EB0 mit Libnodave: Aus deinen Beispielen scheint hervorzugehen, daß die Ergebnisbytes bei dir ab byte 26 gespeichert werden. In Byte 26 steht also 2 und in Byte 27 154.
    Dein LE-System würde diese Bytes als (usigned)16-Bit-Wert als 256*154 +2 interpretieren. Du mußt die Bytes tauschen.
    Nun liest du 2 Bytes ab DB11.DBB2 mit Libnodave. Wieder stehn die Ergebnisbytes ab byte 26. In Byte 26 steht also 2 und in Byte 27 149.
    Dein LE-System würde diese Bytes als (usigned)16-Bit-Wert als 256*149 +2 interpretieren. Du mußt die Bytes tauschen.

    Nun soll deine S7 noch die verarbeiteten Gewichte aufsummieren. Dazu diene der folgende Code:
    L DB11.DBD4
    L DB11.DBW2
    +D
    T DB11.DBD4
    Du willst auch die Summe in deinem Rechner haben und liest jetzt 6 Bytes ab DB11.DBB2 mit Libnodave. Wieder stehen die Ergebnisbytes ab byte 26. Byte 26 und 27 haben denselben Inhalt wie im vorigen Beispiel.
    Du mußt Bytes 26 und 27 tauschen.
    Ab Byte 28 steht aber jetzt ein 32-Bit-Wert. Damit dein System diesen richtig interpretiet, mußt du so tauschen:
    Byte 28 mit Byte 31, Byte 29 mit Byte 30.

    Nun ändere ich aus Bosheit den S7-Code wie folgt:
    L DB11.DBD5
    L DB11.DBW2
    +D
    T DB11.DBD5
    Die Summe steht jetzt in DBD5. Das ist ungewöhnlich, aber nicht verboten. Es mag langsamer sein, als wenn die Adressen durch 2 oder 4 teilbar wären.
    DBB4 ist einfach unbenutzt. Die Übertragung der 7 Bytes, die DBW2 und DBD5 enthalten, ist erheblich schneller als DBW2 und DBD5 nacheinander zu lesen.

    Du liest also 7 Bytes ab DB11.DBB2 mit Libnodave. Wieder stehen die Ergebnisbytes ab byte 26. Byte 26 und 27 haben denselben Inhalt wie in den vorigen 2 Beispielen.
    Du mußt Bytes 26 und 27 tauschen.
    In Byte 28 steht der jetzt sinnlose Inhalt von DBB4.
    Ab Byte 29 steht der 32-Bit-Wert. Damit dein System diesen richtig interpretiert, mußt du so tauschen:
    Byte 29 mit Byte 32, Byte 30 mit Byte 31.

    Aus diesen Beispielen sollst Du erkennen, daß man wissen muß, welche Datentypen an welcher Stelle im Speicher der S7 stehen, um zu entscheiden, welche Bytes zu tauschen sind.

    Das Tauschen selbst kannst du den Funktionen daveGet<TypeName> oder daveGet<TypeName>At überlassen. Die machen das effizient. Oder hat AVRGcc damit Probleme? Spätestens bei Fließkommazahlen (S7:REAL, C:float) kommt die Fummelei mit 2^x, Schieben und AND und OR an ihre Grenzen (Ja, mir hat schon mal einer geschrieben, daß er REALs so bearbeitet...).

  7. #7
    Avatar von poppycock
    poppycock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    30.08.2007
    Beiträge
    207
    Danke
    16
    Erhielt 22 Danke für 17 Beiträge

    Standard

    Hallo Zottel und vielen Dank für deinen ausführlichen Text!

    Zitat Zitat von Zottel Beitrag anzeigen
    Und hier beginnen die verschiedenen Interpretationsmöglichkeiten:
    Ein BE-System interpretiert den 16-Bit-Wert als 256*EB0+EB1, also 384.
    Ein LE-System interpretiert den 16-Bit-Wert als 256*EB1+EB0. Was das ist, hängt auch noch davon ab, ob das höchste Bit als Vorzeichen angesehen wird.
    Also kommt es dabei drauf an, was ich da interpretieren möchte?!
    Ich muss hier wie für ein LE-System darauf reagieren und das EB1 um 8 Stellen nach links schieben. Ich betrachte die Bytes EINZELN!

    Zitat Zitat von Zottel Beitrag anzeigen
    Nein, nicht rechnen! Kann mir mal ein Mensch erklären, warum soviele Leute dazu Potenzrechnungen anstellen wollen?
    Um Gottes willen, ich rechne NICHT mit Potenzen, das sollte nur ein Beispiel sein, wie man von der binären Zahl die dezimale Zahl errechnet.
    Ich schiebe die Bytes!

    Zitat Zitat von Zottel Beitrag anzeigen
    "Die Bytes tauschen" ist viel einfacher (Geschwindigkeit) und liefert IMMER das richtige Ergebnis. Beim Potenzrechnen hängt es von der Zahlendarstellung ab: float a=2^31; float b=2^0; a=a+b; und schon fällt die Eins aus der 23-Bit-Mantisse einfach raus...
    Darum werden auch die Bytes geschoben!

    Zitat Zitat von Zottel Beitrag anzeigen
    Schau dir die Tauschfunktionen in Libnodave an. Die machen das mit unions aus Byte-Array und Zielformat.
    Habe bisher weder unions noch structs verwendet. Da muss ich mich erstmal einlesen!
    Aus deinem Code von sourceforge habe ich folgendes entnommen:

    nodave.h / Revision 1.4:
    Code:
    static inline float daveGetFloat(daveConnection * dc) {
    union {
     float a;
     int b;
     } f;
    f.b=(bswap_32(* ( ((int*)( (int*)dc->dataPointer)++) )));
    return (f.a);
    } 
    
    static inline float toPLCfloat(float ff) {
    union {
     float a;
     int b;
     } f;
     f.a=ff;
     f.b=(bswap_32(f.b));
     return (f.a);
    } 
    
    static inline int daveGetInteger(daveConnection * dc){
     return (bswap_32(* (((int*)( (int*)dc->dataPointer)++) )));
    }
    
    static inline int daveGetDWORD(daveConnection * dc) {
     return (bswap_32(* ( ((int*)( (int*)dc->dataPointer)++) )));
    }
    
    static inline unsigned int daveGetUnsignedInteger(daveConnection * dc) {
     return (bswap_32(* ( ((unsigned int*)( (unsigned int*)dc->dataPointer)++) )));
    }
    
    static inline unsigned int daveGetWORD(daveConnection * dc) {
     return (bswap_16(* ( ((short*)( (short*)dc->dataPointer)++) ))); 
    }
    Und die test.c / Revision 1.3:
    Code:
    a=daveGetDWORD(dc);
    b=daveGetDWORD(dc);
    c=daveGetDWORD(dc);
    d=daveGetFloat(dc);
    e=daveGetFloat(dc);
    f=daveGetFloat(dc);
    Da ich mit einem 8bit-Controller arbeite, funktioniert das Byteswap ohne Anpassung nicht!
    Allerdings muss ich mir nun genauer angucken, wie du das genau machst und evtl. für einen 8biter umschreiben.

    Zitat Zitat von Zottel Beitrag anzeigen
    Nee, auf einem LE-System ist der 16Bit-Wert ab Byte 26 256*[byte27]+[byte26], also 256*0+128 !!!!!!!!!!!!!!!!!!!!!
    Hhm, wenn ich das so rechne, kommt ein falsches Ergebnis raus!
    byte[26] = 0x80
    byte[27] = 0x00
    Binär ausgedrückt: 0b
    1000000000000000
    Nun rechne ich 256*[byte27]+[byte26] = 0x0080 = 128 dezimal.
    Das ist das Ergebnis, das auch du bekommst.
    Aber ich erwarte doch den Wert -32768.
    Wie komme ich nun von 128 auf -32768?
    Das ist ja gerade das, was mich verwundert.

    Zitat Zitat von Zottel Beitrag anzeigen
    Die Regeln sind für DW, MW, AW, EW absolut gleich. Eine andere Frage ist, ob es sinnvoll ist, EWs oder AWs als Zahlen zu interpretieren statt als unabhängige Bits.
    Ich könnte EWs oder AWs byteweise betrachten!
    Somit entfällt das "kuriose" Schieben.
    Als Ergebnis könnte ich folgendes auf dem Display bei EWs und AWs beispielsweise anzeigen:
    Code:
    EB0 = 00101101
    EB1 = 10110010
    EB2 = 11010111
    EB3 = 10000100
    Also quasi:
    Code:
    utoa(byte[26],buff26,2) für EB0
    utoa(byte[27],buff27,2) für EB1
    utoa(byte[28],buff28,2) für EB2
    utoa(byte[29],buff29,2) für EB3
    Zitat Zitat von Zottel Beitrag anzeigen
    Nun liest du 2 Bytes ab EB0 mit Libnodave: Aus deinen Beispielen scheint hervorzugehen, daß die Ergebnisbytes bei dir ab byte 26 gespeichert werden. In Byte 26 steht also 2 und in Byte 27 154.
    Dein LE-System würde diese Bytes als (usigned)16-Bit-Wert als 256*154 +2 interpretieren. Du mußt die Bytes tauschen.
    Ich habe eine andere _ReadBytes-Funktion geschrieben, die das DLE-Doubling so behandelt, dass ALLE nötigen Datenbytes, die eingelesen werden, ab Byte 26 bis Byte 29 stehen!
    Mehr als ein Doppelwort will ich sowieso nicht auf einmal auslesen!
    Richtig ist, dass ich dort die Bytes tauschen muss, wenn ich einen dezimalen Zahlenwert haben möchte.

    Zitat Zitat von Zottel Beitrag anzeigen
    Nun liest du 2 Bytes ab DB11.DBB2 mit Libnodave. Wieder stehn die Ergebnisbytes ab byte 26. In Byte 26 steht also 2 und in Byte 27 149.
    Dein LE-System würde diese Bytes als (usigned)16-Bit-Wert als 256*149 +2 interpretieren. Du mußt die Bytes tauschen.
    Okay...
    [byte26] = 2 = 0x02
    [byte27] = 149 = 0x95
    0x9502 = 38146 dezimal = falsch?!
    Nach dem Tausch: 0x0295 = 661 dezimal = richtig?!

    Zitat Zitat von Zottel Beitrag anzeigen
    Aus diesen Beispielen sollst Du erkennen, daß man wissen muß, welche Datentypen an welcher Stelle im Speicher der S7 stehen, um zu entscheiden, welche Bytes zu tauschen sind.
    Also kommt es nur darauf an, wie man die Daten interpretiert bzw. man wissen muss, welchen Wert man zu erwarten hat...

    Zitat Zitat von Zottel Beitrag anzeigen
    Das Tauschen selbst kannst du den Funktionen daveGet<TypeName> oder daveGet<TypeName>At überlassen. Die machen das effizient. Oder hat AVRGcc damit Probleme? Spätestens bei Fließkommazahlen (S7:REAL, C:float) kommt die Fummelei mit 2^x, Schieben und AND und OR an ihre Grenzen (Ja, mir hat schon mal einer geschrieben, daß er REALs so bearbeitet...).
    Um float habe ich mich noch nicht gekümmert, kommt demnächst.
    Und ich verspreche dir, dass ich nicht mit Potenzen rechne!

    Ich hoffe, ich habe das jetzt um diese Uhrzeit noch einigermaßen verstanden und nichts verbockt...

    Vielen Dank,
    poppycock
    Mit einem Computer löst man die Probleme, die man ohne einen Computer nicht hätte.

  8. #8
    Registriert seit
    19.06.2003
    Beiträge
    2.200
    Danke
    85
    Erhielt 259 Danke für 175 Beiträge

    Frage

    Habe nicht erforscht, ob AVRgcc die Headerdatei bswap.h kennt.
    Hier mal eine Nachbildung dieser Funktionen:

    static inline int16 bswap_16(int16 ff) {

    union { // Ne union, das sind mehrere Daten verschiedenen Typs, die
    // denselben Speicherplatz belegen. Man könnte auch sagen: Verschiedene
    // Sichtweisen auf diesen Speicherplatz, verschiedene Interpretationen.
    unsigned int16 a; // eine 16-Bit-Variable
    unsigned char b[2]; // 2 Bytes, an DERSELBEN Position im Speicher
    } f;
    char xc;
    f.a=ff;
    xc=f.b[0];
    f.b[0]=f.b[1];
    f.b[1]=xc;
    return (f.a); }

    static inline int32 bswap_32(int32 ff) {

    union { // Ne union, das sind mehrere Daten verschiedenen Typs, die
    // denselben Speicherplatz belegen. Man könnte auch sagen: Verschiedene
    // Sichtweisen auf diesen Speicherplatz, verschiedene Interpretationen.
    unsigned int32 a; // eine 32-Bit-Variable
    unsigned char b[4]; // 4 Bytes, an DERSELBEN Position im Speicher
    } f;
    char xc;
    f.a=ff;
    xc=f.b[0];
    f.b[0]=f.b[3];
    f.b[3]=xc;

    xc=f.b[1];
    f.b[1]=f.b[2];
    f.b[2]=xc;

    return (f.a); }

  9. Folgender Benutzer sagt Danke zu Zottel für den nützlichen Beitrag:

    poppycock (03.06.2011)

  10. #9
    Registriert seit
    19.06.2003
    Beiträge
    2.200
    Danke
    85
    Erhielt 259 Danke für 175 Beiträge

    Standard

    Zitat Zitat von poppycock Beitrag anzeigen
    Also kommt es nur darauf an, wie man die Daten interpretiert bzw. man wissen muss, welchen Wert man zu erwarten hat...
    Es geht nicht darum, welchen Wert man erwartet. Im beispiel der Waage ist jedes Gewicht zwischen 0 und 65536 Kg verarbeitbar, zwischen 5 und 65536 Kg sinnvoll.
    Es geht darum, welchen Datentyp man an erwartet. Es ist eine Art von Vereinbarung zwischen dem S7-Programm und der Libnodave-Anwendung, daß an einer bestimmten Stelle des Speicher(abbilde)s eine Gruppe von Bytes beginnt, die eine 16-Bit, 32-Bit oder Real-Zahl darstellt.

  11. Folgender Benutzer sagt Danke zu Zottel für den nützlichen Beitrag:

    poppycock (03.06.2011)

  12. #10
    Avatar von poppycock
    poppycock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    30.08.2007
    Beiträge
    207
    Danke
    16
    Erhielt 22 Danke für 17 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hallo Zottel!

    Zitat Zitat von Zottel Beitrag anzeigen
    Es geht nicht darum, welchen Wert man erwartet. [...] Es geht darum, welchen Datentyp man an erwartet. Es ist eine Art von Vereinbarung zwischen dem S7-Programm und der Libnodave-Anwendung, daß an einer bestimmten Stelle des Speicher(abbilde)s eine Gruppe von Bytes beginnt, die eine 16-Bit, 32-Bit oder Real-Zahl darstellt.
    Ich sollte die Endianess-Sache ganz anders betrachten.
    Und ja, das stimmt, es kommt darauf an, welchen Datentyp ich erwarte!
    Jetzt habe ich (so glaube ich) die Sache besser verstanden.

    Vielen Dank für das union-Beispiel!
    So eine Funktion ist echt genial, kannte ich vorher nicht!
    Ich kann mit einer union wunderbar Datenbytes so interpretieren, wie ich diese brauche! Danke dafür!

    Und zum Schluss:
    Zitat Zitat von Zottel Beitrag anzeigen
    Ein BE-System interpretiert den 16-Bit-Wert als 256*EB0+EB1, also 384.
    Ja, das stimmt. Im Anhang ist das EW0 zu sehen, wie es hier besprochen wurde!

    Gruß und besten Dank,
    poppycock
    Angehängte Grafiken Angehängte Grafiken
    • Dateityp: png vat.PNG (21,6 KB, 15x aufgerufen)
    Mit einem Computer löst man die Probleme, die man ohne einen Computer nicht hätte.

Ähnliche Themen

  1. Fragen zu Libnodave, die immer wieder kommen
    Von Zottel im Forum Hochsprachen - OPC
    Antworten: 2
    Letzter Beitrag: 22.03.2010, 10:41
  2. Timer (SE) starten nicht immer
    Von Hello_SPS im Forum Simatic
    Antworten: 7
    Letzter Beitrag: 13.11.2009, 10:09
  3. Libnodave / HB LB / Byte drehen / DB incl. DB in PC einlesen
    Von Softi79 im Forum Hochsprachen - OPC
    Antworten: 10
    Letzter Beitrag: 15.10.2008, 07:58
  4. max bytes mit libnodave
    Von Praseodym im Forum Hochsprachen - OPC
    Antworten: 4
    Letzter Beitrag: 13.02.2008, 12:29

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •