mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik LSB <----> MSB tauschen in c


Autor: seacrash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich muß eine vorhandene Variable x folgendermaßen umschreiben:

x = 0b  MSB    Bit6    Bit5    Bit4    Bit3    Bit2    Bit1    LSB

in

Y = 0b  LSB    Bit1    Bit2    Bit3    Bit4    Bit5    Bit6    Bit7

in asm kein Problem

lsr x
rol y

und das 8 mal -> einfache schnelle Sache.
Aber wie mache ich das schnell und einfach in C?
(mir fallen leider nur komplexe Lösungen ein)

Dank und Gruß

Autor: Marcel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der IAR C-Compiler kennt den Befehl : _SWAP_BYTES(x);
Ansonsten Bitschubsen in einer Schleife oder?

Gruß Marcel

Autor: Profi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: TravelRec. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Marcel
IAR nutze ich leider nicht :(

@Profi
Danke für die Links, aber auch die bieten keinen nutzbaren
Lösungsansatz in C, es sei denn man hat Flashspeicher übrig wie Sand am
Meer.

Der Profi == Profi?

Grüße

Autor: seacrash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, vorhergehender Name war noch eingetragen "TravelRec." das bin
nicht ich, sondern mein Kollege.

 Gruß

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://www.mikrocontroller.net/forum/read-1-304028...

Elegant und schnell wenn man gut schieben kann:

byte=((byte&0xaa)>>1)|((byte&0x55)<<1);
byte=((byte&0xcc)>>2)|((byte&0x33)<<2);
// Das folgende ist der AVR Befehl 'swap'
byte=((byte&0xf0)>>4)|((byte&0x0f)<<4);

Der AVR schiebt ja so schlecht. Da ist es vermutlich optimal, die
beiden Nibbles des Byte über ne 16ner Tabelle zu spiegeln und dann die
Hälften mit 'swap' zu tauschen.

Cheers
Detlef

Autor: Mark (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab hier mal ein Beispielprogramm.
Wenn du eine Schleife daraus machst, wird's kürzer.

int main(void)
{
  unsigned char byte_1,byte_2,temp;

  byte_1 = 0x0f;
  byte_2 = 0;


  {
    temp   |= (byte_1 & 0x80);
    byte_2 |= (temp >> 7);

    temp   |= (byte_1 & 0x40);
    byte_2 |= (temp >> 5);

    temp   |= (byte_1 & 0x20);
    byte_2 |= (temp >> 3);

    temp   |= (byte_1 & 0x10);
    byte_2 |= (temp >> 1);

    temp   |= (byte_1 & 0x08);
    byte_2 |= (temp << 1);

    temp   |= (byte_1 & 0x04);
    byte_2 |= (temp << 3);

    temp   |= (byte_1 & 0x02);
    byte_2 |= (temp << 5);

    temp   |= (byte_1 & 0x01);
    byte_2 |= (temp << 7);

  }

    return 0;
}

Autor: Marko B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spontan fällt mir dazu ein:
unsigned char in = 0x55;
unsigned char out = 0;

char i;

for(i=0;i<8;i++)
    out |= (in & 0x80>>i) ? 1<<i : 0 ;

oder für CPUs ohne barrel shifter:
unsigned char in = 0x55;
unsigned char out = 0;
unsigned char mask = 0x80;

char i;

for(i=0;i<8;i++) {
    out |= (in & mask) ? 1 : 0;
    out<<=1;
    mask>>=1;
}

Autor: seacrash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Mark,

hab´s ähnlich realisiert

uchar c=0;
for(h=1; h ; h<<1){
      y |= (x & h) << (7 - c++);
}


Grüße

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>>Aber wie mache ich das schnell und einfach in C?

Dein Code ist weder das eine noch das andere, seufz.

Cheers
Detlef

Autor: seacrash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Detlef _A

so ist´s,
bessere Idee? Nur her damit!! :)

Gruß

Autor: Marko B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also meine zweite Version ist doch gar nicht schlecht, mein Compiler
macht da 45 Bytes draus. Wer bietet weniger? =)

Detlef: Deine Version benötigt kompiliert 76 Bytes.

Autor: Marko B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, jetzt habe ich die Optimierung (auf Größe wohlgemerkt) im Compiler
aktiviert, und plötzlich braucht mein Code 50 Bytes und Detlefs 42.

Aber ich habe festgestellt, daß mein Code unnötig umständlich war,
diese Version benötigt nur 29 Bytes bei aktivierter Optimierung:
char i,out;

for(i=0;i<8;i++) {
    out >>= 1;
    out |= (byte & 0x80);
    byte <<= 1;
}

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Marko,

Du hast die Initialisierung von 'out' nicht drin. Der Code sollte
schnell sein, hatte ich verstanden. Hast Du mal die benötigten
Prozessorcycles für die beiden Versionen ausgezählt, das wäre
interessant!?

@seacrash: Wer lesen kann ist klar im Vorteil!

Cheers
Detlef

Autor: Läubi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Inline Assembler? wäre jezt nur sone Idee :)

Autor: seacrash (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Marko B.
Dein Code ist für meinen Zweck ausreichend schnell und klein.
Danke.


@Detlef_A
>Wer lesen kann ist klar im Vorteil!
??

Gruß

Autor: Marko B. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Detlef,

hast Recht. Das kam daher, daß ich den Code in GCC teste, aber in NC30
kompiliere um den Platzbedarf auf dem Controller zu bestimmen.
Witzigerweise braucht meine Funktion mit der Initialisierung nur 25
Byte.

Hier der genaue Code, den ich verglichen habe:
unsigned char mirror(unsigned char byte)
{
    char out = 0, i;

    for(i=0;i<8;i++) {
        out >>= 1;
        out |= (byte & 0x80);
        byte <<= 1;
    }
    return out;
}

und Deine Version:
unsigned char mirror(unsigned char byte)
{
    byte=((byte&0xaa)>>1)|((byte&0x55)<<1);
    byte=((byte&0xcc)>>2)|((byte&0x33)<<2);
    byte=((byte&0xf0)>>4)|((byte&0x0f)<<4); 

    return byte;
}

Ich habe die Taktzyklen nicht genau gezählt, schätze aber, daß deine
Version ca. um den Faktor 2-3 schneller ist (Listing ist im Anhang).
Das aber nur, weil der R8C einen Barrel Shifter hat. Auf einem AVR
dürfte meine Version gleichauf oder sogar schneller sein. Vielleicht
kann ja mal jemand den Code für AVR compilieren und vergleichen, ich
hab gerade keinen Compiler zur Hand.

Läubi: logisch, in Assembler geht das viel einfacher und schneller, da
kann man einfach durchs Carry shiften. Ist dann aber nicht portabel.

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Marko,

ja, sowas Schönes wie barrel-shifter hat der AVR nicht. Die letzte
C-Zeile von mir ist allerdings auf dem AVR ein einziger Befehl, das
erwähnte 'swap'. Für den AVR sollte das mit swap und einer Tabelle
aus 8  oder 16 chars schneller geht: Halbbyte ist zweimal die Adresse
in die Tabelle, 16 Einträge zu ja halbem Byte macht 8 Byte. Naja, ist
was für nen Novembersonntag.

Cheers
Detlef

Autor: Profi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@seacrash:
Wenn das noch nicht genug "profimassig" war, wie wärs dann mit:
bit=0x01;out=0;
for (mask=0x80;mask;mask/=2){
  if (x&mask){y|=bit;}
  bit*=2;}

Oder ohne Schleife:
  y=x&128?1:0 | x&64?2:0 | x&32?4:0 | x&16?8:0 |
    x& 8?16:0 | x&4?32:0 | x&2?64:0 | x&1?128:0;
Inwieweit der Compiler das elegant löst??

Oder brute force:
  if(x&128){y=1;}else{y=0;}
  if(x& 64){y|=  2;}
  if(x& 32){y|=  4;}
  if(x& 16){y|=  8;}
  if(x&  8){y|= 16;}
  if(x&  4){y|= 32;}
  if(x&  2){y|= 64;}
  if(x&  1){y|=128;}


Außerdem:
for(h=1; h ; h<<1){    dürfte nicht die gewünschte Wirkung haben...

for(h=1; h ; h<<=1){   oder
for(h=1; h ; h*=2){

Autor: Marko B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Profi: alles etwas umständlich, aber es hat mich auf eine Idee gebracht,
man braucht die Zählvariable ja gar nicht:
unsigned char mirror(unsigned char byte)
{
  char out = 0;

  for(;byte;byte<<=1) {
    out >>= 1;
    out |= (byte & 0x80);
  }

  return out;
}

Nur noch 21 Bytes. =)

Autor: Marko B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Halt, stopp, Kommando zurück, das funktioniert ja gar nicht. Die
Schleife kann dann ja weniger als 8 mal durchlaufen.

Autor: Profi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in meiner 3. Zeile muss es statt out=0 natürlich y=0 heißen.

oder funktioniert's doch, denn bei x=0 kann die Schleife beendet
werden, falls das Ergebnis y nicht geschoben werden muss:

  j=128;y=0;
  do{
    if(x&1){y|=j;}
    j/=2;}
  while(x/=2);    //kann eine Warnung geben, ist so beabsichtigt

oder als for-Schleife geschrieben:
  for(j=128,y=0;x;x/=2){
    if(x&1){y|=j;}
    j/=2;}

evtl. kann es günstiger sein, andersherum zu schieben (falls die
Schleife wg. der Bitmuster so schneller beendet wird):
  for(j=1,y=0;x;x*=2){
    if(x&128){y|=j;}
    j*=2;}

Naj, gut für heute mit dem Geschiebe ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.