TIA Bitfolge tauschen

vollmi

Level-3
Beiträge
5.686
Reaktionspunkte
1.615
Zuviel Werbung?
-> Hier kostenlos registrieren
ich lese hier ein Gerät ein das die Bits in den Bytes vertauscht hat. Ich hab jetzt schnell n Baustein zur Lösung geschrieben. Der funktioniert natürlich einwandfrei, aber ist halt sehr Vorschlagshammermässig programmiert.

Gibts für dieses Vorgehen auf der S7-1500 eigentlich einen Befehl oder schon einen Baustein den ich nicht gefunden habe?

Code:
FUNCTION "Bit_swap" : Byte
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      src : Byte;
   END_VAR




BEGIN
	#Bit_swap.%X0 := #src.%X7;
	#Bit_swap.%X1 := #src.%X6;
	#Bit_swap.%X2 := #src.%X5;
	#Bit_swap.%X3 := #src.%X4;
	#Bit_swap.%X4 := #src.%X3;
	#Bit_swap.%X5 := #src.%X2;
	#Bit_swap.%X6 := #src.%X1;
	#Bit_swap.%X7 := #src.%X0;
END_FUNCTION
 
ich lese hier ein Gerät ein das die Bits in den Bytes vertauscht hat.
Frag doch mal den Hersteller des besagten Gerätes! Der hat sicherlich ein GeheimRezept, sonst würde er nicht die Mühe auf sich nehmen, die Bits in die falsche Reihenfolge zu sortieren. :ROFLMAO:
Spass beiseite - Ernst auf'n Tisch! Da Dein Lösungsweg meines Wissens nicht zu überbieten ist und Du nicht darauf angewiesen bist, die Bits einzeln auszumaskieren, herumzuschieben und zusammenzuodern, sei glücklich und zufrieden mit Deinem status quo.
So einen Baustein braucht normalerweise niemand ... und vielleicht ist gerade das der Grund dafür, dass etwas entsprechendes in irgendeiner Bibliothek zu finden ist? Danach zu suchen wäre vertane Zeit. ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
... und vielleicht ist gerade das der Grund dafür, dass etwas entsprechendes in irgendeiner Bibliothek zu finden ist?
Und vermutlich macht dieser Baustein dann auch nichts Anderes, außer dass er noch etwas aufgeblähter ist, einen Knoff-Hoff-Schutz hat und dann Schwierigkeiten beim Simulieren bereitet.
:rolleyes:
 
Code:
	#Bit_swap.%X0 := #src.%X7;
	#Bit_swap.%X1 := #src.%X6;
	#Bit_swap.%X2 := #src.%X5;
	#Bit_swap.%X3 := #src.%X4;
	#Bit_swap.%X4 := #src.%X3;
	#Bit_swap.%X5 := #src.%X2;
	#Bit_swap.%X6 := #src.%X1;
	#Bit_swap.%X7 := #src.%X0;
Hinweis: besser nicht mehrmals auf Eingangs- und Ausgangs-Parameter der Function zugreifen. Das ist nicht Multitasking-sicher.

Falls es was Fertiges für das Bits spiegeln gibt, dann hat es vermutlich "...REVERSE..." o.Ä. im Name.

Der "classische" Algorithmus zum Bits spiegeln in einem Byte in C
Code:
n = (n&0xF0)>>4 | (n&0x0F)<<4;
n = (n&0xCC)>>2 | (n&0x33)<<2;
n = (n&0xAA)>>1 | (n&0x55)<<1;

und eine ähnliche OSCAT-Variante REVERSE in ST
Code:
REVERSE := SHL(in,7) OR SHR(in,7) OR (ROR(in,3) AND 2#01000100) OR (ROL(in,3) AND 2#00100010) 
        OR (SHL(in,1) AND 2#00010000) OR (SHR(in,1) AND 2#00001000);

Word oder DWord spiegeln analog dieser Lösung in S7-AWL:
Zunächst die Bit-Reihenfolge in den 4 Teil-Bytes spiegeln und bei Word/Doppelword danach
die in sich gespiegelten Bytes in die gespiegelte Reihenfolge bringen.

Multitasking-sicher: Vorsichtshalber für den Fall, daß das Word nicht als Kopie sondern per Referenz übergeben wird, bei allen Varianten darauf achten, daß zunächst das Eingangsword auf eine lokale Variable umgespeichert wird, dann die Bits der lokalen Kopie spiegeln und erst zum Schluß die lokale Spiegelung auf das Ausgangsword kopieren.

Harald
 
Was wäre das dann für ein Datenformat?
Bytes vertauscht ist ja klar Big und Little Endian, aber Bits?

Das ist ja der Witz an der Sache. Die Teile liefern Register (16 Bit) und Bool. Die 16 Bit Register kommen Little Endian daher (damit hat man ja erfahrung), aber die Bitfolge ist tatsächlich vertauscht. Es hat ein bisschen gedauert bis ich kapiert habe warum die Werte nicht korrekt sind. Ich hab dann einen freien Stromeingang mit dem Simulator beschaltet, da konnte man dann gut sehen welche Bits hochzählen. Bei Analogwertgebern ist das immer so eine Sache.
 
und eine ähnliche OSCAT-Variante REVERSE in ST
REVERSE := SHL(in,7) OR SHR(in,7) OR (ROR(in,3) AND 2#01000100) OR (ROL(in,3) AND 2#00100010) OR (SHL(in,1) AND 2#00010000) OR (SHR(in,1) AND 2#00001000);

Word oder DWord spiegeln analog dieser Lösung in S7-AWL:
Vorsicht bei der "Analogie" in S7-AWL!
Meines Wissens gibt in S7-AWL kein ROLen und RORen bezogen auf 8 Bit (Byte) und bezogen auf 16 Bit (Wort), sondern nur bezogen auf 32 Bit (DoppelWort).
In SCL aber doch. Ist zwar schwammig in der Beschreibung formuliert, aber die Beispiele belegen es anscheinend. (Seit einer Auskunft von Siemens "Ist doch nur ein Beispiel" zum Thema eines nicht funktionierenden Beispiels, formuliere ich das bewusst "vorsichtig" ;) ).

Die C-Variante finde ich schön übersichtlich und sie lässt sich auch recht überschaubar auf 16, 32, ... Bit aufbohren und bleibt dabei übersichtlich.
Pro Verdopplung der BitZahl am Anfang eine Zeile einfügen und um die nächste ZweierPotenz schieben und bei allen Zeilen die BitMasken anpassen (quasi verdoppeln) und das war's!
Da muss man gar nicht erst über tauschen von Bytes und Worten nachdenken.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die C-Variante finde ich schön übersichtlich und sie lässt sich auch recht überschaubar auf 16, 32, ... Bit aufbohren und bleibt dabei übersichtlich.
Pro Verdopplung der BitZahl am Anfang eine Zeile einfügen und um die nächste ZweierPotenz schieben und bei allen Zeilen die BitMasken anpassen (quasi verdoppeln) und das war's!
Da muss man gar nicht erst über tauschen von Bytes und Worten nachdenken.

Wie meinst Du das mit der einen Zeile?
In meiner S7-AWL-Umsetzung der C-Variante haben die Word- und DWord-Versionen überhaupt nur 1 Anweisung mehr als die Byte-Version - nämlich tauschen (spiegeln) der Ergebnis-Bytes.

Harald
 
Wie meinst Du das mit der einen Zeile?
Moin Harald,
die jeweils eine Zeile mehr bei Verdopplung der BitZahl von 8 auf 16 bzw. 16 auf 32 bezog sich auf den von Dir gezeigten C-Code - nicht auf Deinen verlinkten S7-AWL-Code:
Code:
(* für 1 Byte: *)
n = (n&0xF0)>>4 | (n&0x0F)<<4; (* [SUP]1[/SUP]) s. Edit *)
n = (n&0xCC)>>2 | (n&0x33)<<2;
n = (n&0xAA)>>1 | (n&0x55)<<1;

(* für 1 Wort: *)
n = (n&0xFF00)>>8 | (n&0x00FF)<<8; (* 1 Zeile eingefügt für Verdoppelung von 8 auf 16 Bit [SUP]1[/SUP]) s. Edit *)
n = (n&0xF0F0)>>4 | (n&0x0F0F)<<4; (* Masken "verdoppeln" durch "hintereinander hängen" *)
n = (n&0xCCCC)>>2 | (n&0x3333)<<2;
n = (n&0xAAAA)>>1 | (n&0x5555)<<1;

(* für 1 Doppelwort: *)
n = (n&0xFFFF0000)>>16 | (n&0x0000FFFF)<<16; (* 1 Zeile eingefügt für Verdoppelung von 16 auf 32 Bit [SUP]1[/SUP]) s. Edit *)
n = (n&0xFF00FF00)>>8  | (n&0x00FF00FF)<<8;  (* Masken "verdoppeln" durch "hintereinander hängen" *)
n = (n&0xF0F0F0F0)>>4  | (n&0x0F0F0F0F)<<4;
n = (n&0xCCCCCCCC)>>2  | (n&0x33333333)<<2;
n = (n&0xAAAAAAAA)>>1  | (n&0x55555555)<<1;
In Deinem S7-AWL-Code (super!!!) arbeitest Du ja von vornherein mit 32 Bits ("think big!") und "schmeisst" die nicht benötigten Bytes weg durch T #Out_Byte bzw. T #Out_Word und legst ggfs vorher die benötigten Bytes zurecht durch die "massgeschneiderten" Befehle TAD bzw. TAW.

Meine Warnung, den ROL und den ROR aus dem ST-Beispiel vorbehaltlos in AWL zu übernehmen, bezog sich natürlich auch nicht auf Deine S7-AWL-Version, die ja auf das Rotieren ganz verzichtet.

Gruss, Heinileini

Edit:
[SUP]1[/SUP]) Die Maskierung in der jeweils 1. Zeile ist eigentlich "Luxus" (= überflüssig).
 
Zuletzt bearbeitet:
[SUP]1[/SUP]) Die Maskierung in der jeweils 1. Zeile ist eigentlich "Luxus" (= überflüssig).
Da habe ich wohl vor Jahren noch nicht so genau auf mögliche Optimierungen geachtet, als ich den Algorithmus irgendwo gefunden hatte. ;)
Zumindest beim Rechtsschieben wäre es auch noch schöner, zuerst zu schieben und erst danach zu maskieren - dann funktioniert der C-Code auch mit signed Datentypen. Beim Linksschieben ist die Reihenfolge beliebig. (Stichwort: logisch oder arithmetisch verschieben)

Viele Wege führen nach Rom. Man kann die zugrunde liegende Idee/Algorithmus noch etwas besser implementieren.
Anstatt
Code:
n = (n&0xF0)>>4 | (n&0x0F)<<4;
n = (n&0xCC)>>2 | (n&0x33)<<2;
n = (n&0xAA)>>1 | (n&0x55)<<1;
besser für unsigned und signed char (8 Bit Byte):
Code:
n = ((n >> 4) & 0x0F) | ((n << 4) & 0xF0);
n = ((n >> 2) & 0x33) | ((n << 2) & 0xCC);
n = ((n >> 1) & 0x55) | ((n << 1) & 0xAA);

(* oder *)
n = ((n >> 1) & 0x55) | ((n & 0x55) << 1);
n = ((n >> 2) & 0x33) | ((n & 0x33) << 2);
n = ((n >> 4) & 0x0F) | ((n & 0x0F) << 4);

(* oder *)
n = ((n >> 1) & 0x55) | ((n & 0x55) << 1);
n = ((n >> 2) & 0x33) | ((n & 0x33) << 2);
n = ((n >> 4) & 0x0F) | ( n         << 4);

Speziell für unsigned Datentypen kann man abkürzen:
Code:
(* für unsigned char (8 Bit Byte): *)
n = ((n >> 1) & 0x55) | ((n & 0x55) << 1);
n = ((n >> 2) & 0x33) | ((n & 0x33) << 2);
n =  (n >> 4)         | ( n         << 4);

(* für unsigned short (16 Bit Word): *)
n = ((n >> 1) & 0x5555) | ((n & 0x5555) << 1);
n = ((n >> 2) & 0x3333) | ((n & 0x3333) << 2);
n = ((n >> 4) & 0x0F0F) | ((n & 0x0F0F) << 4);
n =  (n >> 8)           | ( n           << 8);

(* für unsigned int (32 Bit DWord): *)
n = ((n >> 1) & 0x55555555) | ((n & 0x55555555) << 1);
n = ((n >> 2) & 0x33333333) | ((n & 0x33333333) << 2);
n = ((n >> 4) & 0x0F0F0F0F) | ((n & 0x0F0F0F0F) << 4);
n = ((n >> 8) & 0x00FF00FF) | ((n & 0x00FF00FF) << 8);
n =  (n >> 16)              | (n << 16);
Harald
 
Zurück
Oben