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ß
der IAR C-Compiler kennt den Befehl : _SWAP_BYTES(x); Ansonsten Bitschubsen in einer Schleife oder? Gruß Marcel
http://www.mikrocontroller.net/forum/read-1-14892.html http://www.mikrocontroller.net/forum/read-1-6535.html
@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
sorry, vorhergehender Name war noch eingetragen "TravelRec." das bin nicht ich, sondern mein Kollege. Gruß
http://www.mikrocontroller.net/forum/read-1-304028.html#304197 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
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; }
Spontan fällt mir dazu ein:
1 | unsigned char in = 0x55; |
2 | unsigned char out = 0; |
3 | |
4 | char i; |
5 | |
6 | for(i=0;i<8;i++) |
7 | out |= (in & 0x80>>i) ? 1<<i : 0 ; |
oder für CPUs ohne barrel shifter:
1 | unsigned char in = 0x55; |
2 | unsigned char out = 0; |
3 | unsigned char mask = 0x80; |
4 | |
5 | char i; |
6 | |
7 | for(i=0;i<8;i++) { |
8 | out |= (in & mask) ? 1 : 0; |
9 | out<<=1; |
10 | mask>>=1; |
11 | }
|
Hallo Mark, hab´s ähnlich realisiert uchar c=0; for(h=1; h ; h<<1){ y |= (x & h) << (7 - c++); } Grüße
>>>Aber wie mache ich das schnell und einfach in C?
Dein Code ist weder das eine noch das andere, seufz.
Cheers
Detlef
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.
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:
1 | char i,out; |
2 | |
3 | for(i=0;i<8;i++) { |
4 | out >>= 1; |
5 | out |= (byte & 0x80); |
6 | byte <<= 1; |
7 | }
|
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
@Marko B.
Dein Code ist für meinen Zweck ausreichend schnell und klein.
Danke.
@Detlef_A
>Wer lesen kann ist klar im Vorteil!
??
Gruß
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:
1 | unsigned char mirror(unsigned char byte) |
2 | {
|
3 | char out = 0, i; |
4 | |
5 | for(i=0;i<8;i++) { |
6 | out >>= 1; |
7 | out |= (byte & 0x80); |
8 | byte <<= 1; |
9 | }
|
10 | return out; |
11 | }
|
und Deine Version:
1 | unsigned char mirror(unsigned char byte) |
2 | {
|
3 | byte=((byte&0xaa)>>1)|((byte&0x55)<<1); |
4 | byte=((byte&0xcc)>>2)|((byte&0x33)<<2); |
5 | byte=((byte&0xf0)>>4)|((byte&0x0f)<<4); |
6 | |
7 | return byte; |
8 | }
|
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.
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
@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){
Profi: alles etwas umständlich, aber es hat mich auf eine Idee gebracht, man braucht die Zählvariable ja gar nicht:
1 | unsigned char mirror(unsigned char byte) |
2 | {
|
3 | char out = 0; |
4 | |
5 | for(;byte;byte<<=1) { |
6 | out >>= 1; |
7 | out |= (byte & 0x80); |
8 | }
|
9 | |
10 | return out; |
11 | }
|
Nur noch 21 Bytes. =)
Halt, stopp, Kommando zurück, das funktioniert ja gar nicht. Die Schleife kann dann ja weniger als 8 mal durchlaufen.
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 ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.