Forum: Mikrocontroller und Digitale Elektronik Bitreihenfolge ändern


von Benedikt (Gast)


Lesenswert?

Es kam hier zwar bestimmt schon ein paarmal vor, aber die Suche brachte
kein Ergebnis.
Wie ändere ich am einfachsten die Bitreihenfolge in C ?

In Assembler ist es klar: Die Bits der Reihe nach nach rechts schieben,
aber mit einem Linksshift wieder auffangen.

Bei dem dummen BMP Format ist alles genau anderst rum: Es wird von
unten nach oben gespeichert.

Mikrocontroller ist ein M16C.

von Stefan Kleinwort (Gast)


Lesenswert?

Wenn es schnell gehen soll und 256 Byte Platz vorhanden sind:

konstantes byte-Array[256] anlegen mit den verdrehten Werten:

msb_to_lsb[256] = {0x00,0x80,0x40,0xc0 ...};

Im Programmablauf dann den Wert, der gedreht werden soll, als Index der
Tabelle verwenden:

my_erg = msb_to_lsb[my_byte];

Beim M16C hast Du ja genügend Flash, dass die 256 nicht weh tun, und
zur Laufzeit schneller geht es wohl kaum.

Stefan

von Stefan Kleinwort (Gast)


Lesenswert?

Habe die Tabelle, die ich mal benutzt habe, gefunden. Ist zwar in
Assembler, aber nach C müuss nur wenig geändert werden:

spiegeltab
        db        0,128, 64,192, 32,160, 96,224
        db       16,144, 80,208, 48,176,112,240
        db        8,136, 72,200, 40,168,104,232
        db       24,152, 88,216, 56,184,120,248
        db        4,132, 68,196, 36,164,100,228
        db       20,148, 84,212, 52,180,116,244
        db       12,140, 76,204, 44,172,108,236
        db       28,156, 92,220, 60,188,124,252
        db        2,130, 66,194, 34,162, 98,226
        db       18,146, 82,210, 50,178,114,242
        db       10,138, 74,202, 42,170,106,234
        db       26,154, 90,218, 58,186,122,250
        db        6,134, 70,198, 38,166,102,230
        db       22,150, 86,214, 54,182,118,246
        db       14,142, 78,206, 46,174,110,238
        db       30,158, 94,222, 62,190,126,254
        db        1,129, 65,193, 33,161, 97,225
        db       17,145, 81,209, 49,177,113,241
        db        9,137, 73,201, 41,169,105,233
        db       25,153, 89,217, 57,185,121,249
        db        5,133, 69,197, 37,165,101,229
        db       21,149, 85,213, 53,181,117,245
        db       13,141, 77,205, 45,173,109,237
        db       29,157, 93,221, 61,189,125,253
        db        3,131, 67,195, 35,163, 99,227
        db       19,147, 83,211, 51,179,115,243
        db       11,139, 75,203, 43,171,107,235
        db       27,155, 91,219, 59,187,123,251
        db        7,135, 71,199, 39,167,103,231
        db       23,151, 87,215, 55,183,119,247
        db       15,143, 79,207, 47,175,111,239
        db       31,159, 95,223, 63,191,127,255

Stefan

von Benedikt (Gast)


Lesenswert?

Danke, die Idee ist gut.
Ich hatte bisher die Idee das ganze Harwaremäßig über den Datenbus zu
machen:
Daten an eine bestimmte Adresse senden, dort befindet sich ein Latch,
dessen Ausgang in umgedrehter Folge mit den den Eingängen verbunden
ist. Liest man den Wert, hat er eine umgedrehte Bitfolge.

von AxelR (Gast)


Lesenswert?

Mir ist das auch son passiert:
PortB mit Eagle an 8 Solidstate-Relias, von da auf den Steckverbinder
geroutet und nun war der PortB0 der 8te ausgang.
Das Workaround sah dann ( in FastAVR ) so aus:

Die Variablen sind vorab Global definiert.

Function bitswap(b_in As Byte) As Byte
wrong_in = b_in
For xx= 8 To 1 Step -1
   Shift(Left,1,wrong_in)
   Shift(Right,1,ok_out)
   k = wrong_in And &h0100
    If k = &h0100 Then
      ok_out =ok_out + 128
    End If
   k = 0
   Next xx
Return ok_out
End Function

Gruß
Axel

von Markus_8051 (Gast)


Lesenswert?

Hatte mit ähnlichem Problem auch schon durch einen Layoutfehler zu
kämpfen. Da war aber nur der halbe Datenbus verdreht. Das Workaround
sah bei mir etwa so aus:

neu =
((alt&&128)>>7)||((alt&&64)>>5)||((alt&&32)>>3)||((alt&&16)>>1)||((alt&& 
8)<<1)||((alt&&4)<<3)||((alt&&2)<<5)||((alt&&1)<<7)

Codesparend, aber natürlich langsamer.

Gruß,
Markus_8051

von nobody0 (Gast)


Lesenswert?

Es gibt dafür ein bekanntes Makro (u. a. beim Programm fortune dabei)
mit logarithmischer Zeitkomplexität:

// reverse (mirror) u32 number n
#define mc_REVERSE(n) \
{\
n = ((n >> 1) & 0x55555555)  | ((n << 1) & 0xaaaaaaaa);  \
n = ((n >> 2) & 0x33333333)  | ((n << 2) & 0xcccccccc);  \
n = ((n >> 4) & 0x0f0f0f0f)  | ((n << 4) & 0xf0f0f0f0);  \
n = ((n >> 8) & 0x00ff00ff)  | ((n << 8) & 0xff00ff00);  \
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000); \
}

Wie man das auf 8 Bit reduziert oder 128 Bit Zahlen ausbaut, ist
offnsichtlich.

von Jörg Wunsch (Gast)


Lesenswert?

Allerdings bringt das Makro (so genial wie's auch ist) bei 8 Bit
praktisch keinen Vorteil mehr gegenüber der expliziten Schleife.
(Been there, done that.  Das Thema kommt regelmäßig hoch.)

von nobody0 (Gast)


Lesenswert?

Dafür belegt das Makro weniger Speicher.

von Profi (Gast)


Lesenswert?

Markus_8051:
sollte es nicht besser statt

neu =
((alt&&128)>>7)||((alt&&64)>>5)||((alt&&32)>>3)||((alt&&16)>>1)||((alt&& 
8)<<1)||((alt&&4)<<3)||((alt&&2)<<5)||((alt&&1)<<7)

neu =
((alt&128)>>7)|((alt&64)>>5)|((alt&32)>>3)|((alt&16)>>1)|((alt&8)<<1)|(( 
alt&4)<<3)|((alt&2)<<5)|((alt&1)<<7)

heißen?

Hoch lebe der M16C und der M32C!

von AxelR (Gast)


Lesenswert?

sieht hier einer durch?...
muss bei dem ganze hin und hergeschiebe nicht die augangsvariable
"alt" irgentwo gesichert werden? wenn die sagen ((alt&128>>7) dann
schiebt er, so habe ich das jetzt nach langem mangala lesen erkannt,
das höchste bit 7 mal nach rechts. was aber, wenn da schon ein bit
steht? ganz hinten steht in der zeile: alt&1<<7rüber. da steht doch
jeztzt das bit drinne, was eben noch gaanz links stand. Ich mein, wenn
ich zwei sachen über Cut and Paste tauschen will, muss ich das
"linke" Teil erstmal wo ablegen, dann das "rechte" Teil dahin
packen, wo das "linke" stand, und erst jetzt kann ich das "linke"
teil aus der Ablage nehmen und zum "rechten" packen. Das machte ihr
hier alles so in einer Zeile auf einen Rutsch?
Kein Wunder, wenn mein Windows sich ständig weghängt.hihi ;-)))

Schönen Feierabend, bis morgen
Axel

von Profi (Gast)


Lesenswert?

alt bleibt immer gleich, weil ihm ja nichts zugewiesen wird.
neu wird über die 8 ORs bitweise zusammengebaut:
(&128)>>7  alt-Bit 7 nach neu-Bit 0
(& 64)>>5  alt-Bit 6 nach neu-Bit 1
(& 32)>>3  alt-Bit 5 nach neu-Bit 2
(& 16)>>1  alt-Bit 4 nach neu-Bit 3
(&  8)<<1  alt-Bit 3 nach neu-Bit 4
(&  4)<<3  alt-Bit 2 nach neu-Bit 5
(&  2)<<5  alt-Bit 1 nach neu-Bit 6
(&  1)<<7  alt-Bit 0 nach neu-Bit 7

wenn ich zwei sachen über Cut and Paste tauschen will
Hier wird ja nichts in-place getauscht.

was aber, wenn da schon ein bit steht?
Da steht nichts, weil nicht neu (und erst recht nicht alt) modifiziert
wird (z.B. alt&=), sondern es wird ein neuer Wert zugewiesen, so wie
bei neu=12+34.
Ist es jetzt klarer?

von Markus_8051 (Gast)


Lesenswert?

@Profi:

Gute Frage, das eine war das bitweise, das andere das logische UND.
Hier muß natürlich das bitweise hin. Frag mich aber nicht, ob das jetzt
& oder && war. Gleiches gilt natürlich auch für das ODER.

von AxelR (Gast)


Lesenswert?

jetzt hab' ichs verstanden, vielen Dank.

ich werde bei meinem "Compiler" auch mal probieren...

Viele Grüße
Axel

von Profi (Gast)


Lesenswert?

Noch eine Variante:
Es empfiehlt sich, für alt und neu register-Variablen zu verwenden.

register int alt,neu;
neu = (alt&128) >>1 ;  //alt-Bit 7 nach neu-Bit 6
neu |= (alt=<1) &128;  //alt-Bit 6 nach neu-Bit 7
neu =>1;               //neu-Bit 6&7 nach neu-Bit 5&6
neu |= (alt=<1) &128;  //alt-Bit 5 nach neu-Bit 7
neu =>1;               //neu-Bit 5-7 nach neu-Bit 4-6
neu |= (alt=<1) &128;  //alt-Bit 4 nach neu-Bit 7
neu =>1;               //neu-Bit 4-7 nach neu-Bit 3-6
neu |= (alt=<1) &128;  //alt-Bit 3 nach neu-Bit 7
neu =>1;               //neu-Bit 3-7 nach neu-Bit 2-6
neu |= (alt=<1) &128;  //alt-Bit 2 nach neu-Bit 7
neu =>1;               //neu-Bit 2-7 nach neu-Bit 1-6
neu |= (alt=<1) &128;  //alt-Bit 1 nach neu-Bit 7
neu =>1;               //neu-Bit 1-7 nach neu-Bit 0-6
neu |= (alt=<1) &128;  //alt-Bit 0 nach neu-Bit 7

Vorteil ist hier, dass immer nur um EIN Bit geschoben wird, und das bei
den meisten uC (außer sie haben einen Barrel-Shifter) schneller geht als
Schieben um mehrere Bits.

Da ich im Urlaub bin und hier keinen Compiler installiert hab, kann ich
es nicht ausprobieren, vor allem ob
alt=<1
nicht als kleiner gleich compiliert wird. Ich meine natürlich alt um
eins nach links schieben.

Hier wird eine Besonderheit von C ausgenutzt, nämlich dass eine
Zuordung selbst als Wert verwendet werden kann.
neu |= (alt=<1) &128; ist eine Kurzschreibweise für
alt=<1;
neu |= alt &128;

Das ist auch der Grund, warum z.B.
if (i=8) {....}
syntaktisch richtig ist. Der Variablen i wird 8 zugewiesen und dann ist
die if-Abfrage
if (8) {....}
natürlich immer true. In diese gemeine Falle ist wohl jeder schonmal
getappt.
Gute Compiler fragen natürlich, ob es nicht besser
if (i==8) {....}
heißen soll.

von Hagen (Gast)


Lesenswert?

In Assembler wäre das simples "Loop-Unrolling", statt schleife also

LSR  Input
ROL  Output
LSR  Input
ROL  Output
LSR  Input
ROL  Output
LSR  Input
ROL  Output
LSR  Input
ROL  Output
LSR  Input
ROL  Output
LSR  Input
ROL  Output
LSR  Input
ROL  Output

oder eben einfach

LDI  Counter, 8
Loop:
  LSR  Input
  ROL  Output
DEC Counter
BRNE Loop

Gruß hagen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.