Forum: Mikrocontroller und Digitale Elektronik Longwert: Bits vertauschen LSB zu MSB


von Andreas Häusler (Gast)


Lesenswert?

Hallo Leute

Brauche wieder mal dringend Eure Hilfe.
Muss in einer long Variable (32Bit) alle Bits vertauschen.


      Bit31                              Bit0
Alt:    11110001 11110001 11110001 11110001
Neu:    10001111 10001111 10001111 10001111

Wer kennt die effizienteste Variante?

Danke im Voraus.

von Axel K. (axel)


Lesenswert?

eventuell mit Schiebebefehlen unter Benutzung des Carry Bit

edit:  zb r10 - 14 und hilfregister r17

clc  ;clear carry

lsr r14

rol r17

von avr (Gast)


Lesenswert?

Auf einen Rutsch wohl blöd zu machen.

In einzelnen Byte besser.

Ein Byte drehen:
1
unsigned char umkehr(unsigned char n){
2
n=((n>>1)&0x55)|((n<<1)&0xaa);
3
n=((n>>2)&0x33)|((n<<2)&0xcc);
4
return (n>>4)|(n<<4);
5
}

Byte 1 mit 4 und 2 mit 3 tauschen.

fertig

avr

von Andreas Häusler (Gast)


Lesenswert?

Hallo Leute

Danke für die Info. Hab's jetzt so gelöst:
1
unsigned char i;
2
unsigned long mask;
3
unsigned long tmp_data;
4
unsigned long reverse_data;
5
6
mask = 0x00000001;
7
reverse_data = 0;
8
9
//Longwert spiegeln
10
for (i=0;i<32;i++)
11
{
12
  if((tmp_data & 0x80000000) == 0x80000000)
13
  {
14
    reverse_data |= mask << (unsigned long)i;  
15
    tmp_data = tmp_data << 1;
16
  }
17
  else
18
  {
19
    reverse_data &= ~(mask << (unsigned long)i);  
20
    tmp_data = tmp_data << 1;
21
  }  
22
}

Ist vielleicht nicht die beste Lösung, aber es tut.

von (prx) A. K. (prx)


Lesenswert?

Andreas Häusler schrieb:

> Muss in einer long Variable (32Bit) alle Bits vertauschen.

Welcher Prozessor?

von Stephan H. (stephan-)


Lesenswert?

bei 4 Bit macht man Nibbletausch.
Warum nicht auf 8 Bit Ebene ? 0 Problem in ASM:

Sonst hilft wohl nur Ringelpietz mit Anfassen :-))
Oder ein Tauschbuffer.

von (prx) A. K. (prx)


Lesenswert?

Hintergrund meiner Frage: Es gibt Prozessoren, die für sowas nur einen 
Takt benötigen. Weil entsprechender Befehl vorhanden. Ausserdem wurde 
anfangs explizit nach der effizientesten Variante gesucht, nicht - wie 
später - nach irgendeiner.

von Stephan H. (stephan-)


Lesenswert?

A. K. schrieb:
> Ausserdem wurde
> anfangs explizit nach der effizientesten Variante gesucht, nicht - wie
> später - nach irgendeiner.

Leider hast Du die Plattform nicht erwähnt. Daher nur Antworten aus der 
Glaskugel. Sorry.
Oder wäre die Antwort

SWAP A

hilfreicher ?

von R. K. (uc_student)


Lesenswert?

Hallo zusammen

Ich möchte dieses Thema nochmals ein wenig aufwärmen...

Ich portiere gerade ein Programm von einem STM32 auf einen Stellaris uC. 
Dabei ist mir aufgefallen, dass ich bei der SPI-Schnittstelle die Wahl 
von LSB-First nicht mehr habe. Bei den Stellaris ist halt einfach 
MSB-First fix einprogrammiert.

@A.K. könntest du mir vielleicht den Befehl zum drehen eines 16 Bit 
Wortes nennen? Ich stehe da gerade ziemlich auf dem Schlauch.

Besten Dank im Voraus

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich würde es mal der Suche versuchen...
Und fände dann ganz leicht den 8 Jahre alten 
Beitrag "Re: Bitreihenfolge ändern"
Und den 3 Jahre alten Beitrag "Wie drehe ich eine Bitreihenfolge um??"
Und noch einige mehr...

> R. K. schrieb:
> Bei den Stellaris ist halt einfach MSB-First fix einprogrammiert.
Ja, weil das der Rest der Welt auch so macht...

von R. K. (uc_student)


Lesenswert?

>> R. K. schrieb:
>> Bei den Stellaris ist halt einfach MSB-First fix einprogrammiert.
> Ja, weil das der Rest der Welt auch so macht...


Doch genau damit habe ich ein Problem. Ich empfange einen
kontinuielichen Datenstrom. Ich clocke dabei die SPI selbst und
speichere einfach alle empfangenen Bits in einem grossen Buffer. Danach
suche ich in diesem Buffer nach meinem Sync-Wort und decodiere die
Daten.

Da ich asynchron arbeite kann ein Daten-Byte auch über mehre Bytes im
Speicher verteilt sein. Durch die LittleEndian eigenschaft des Cortex
ergeben sich dann deutliche Unschönheiten.

Der DMA füllt beispielsweise den Buffer an der stelle [1] mit dem ersten
Byte. Danach füllt er den Buffer an der stelle [2] mit dem nächsten
Byte... Wenn ich die Daten für eine effiziente Verarbeitung mit
32-Bit-Variablen verarbeiten will krieg ich ein riisen Problem wegen dem
little Endian. Könnte ich die Daten mit LSB first im Speicher ablegen,
so würde das ganze zwar vedreht, jedoch gibt es keine Fehler im
Speicher.

Vielleicht kennst du auch eine Möglickeit, damit der DMA meine 
Byte-Daten so in den Speicher schreibt, damit ich die Daten später als 
32-Bit interpretieren kann?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

R. K. schrieb:
> Ich clocke dabei die SPI selbst und speichere einfach alle empfangenen
> Bits in einem grossen Buffer. Danach suche ich in diesem Buffer nach
> meinem Sync-Wort und decodiere die Daten.
Und warum suchst du nicht während der Übertragung nach dem Sync-Wort 
und speicherst ab dann die Daten? Dann hast du nuch nicht irgendwo 
mitten drin einen Byte- bzw. Wortumbruch, und du weißt sofort wo die 
relevante Information im Speicher liegt.

von MaWin (Gast)


Lesenswert?

> Wer kennt die effizienteste Variante?

Tabellenzugriff.

Als speed/space tradeoff wohl byteweise.

union
{
    long longvalue;
    unsigned char bytevalue[3];
}
value,newvalue;

unsigned char table[256]={0x00,0x80,0x40,0xC0,...};

newvalue.bytevalue[0]=table[value.bytevalue[3]];
newvalue.bytevalue[1]=table[value.bytevalue[2]];
newvalue.bytevalue[2]=table[value.bytevalue[1]];
newvalue.bytevalue[3]=table[value.bytevalue[0]];

Zumindest auf Prozessoren ohne barrel shifter.

von Uwe Bonnes (Gast)


Lesenswert?

Cortex M3/4 kennt den RBIT Befehl:
RBIT: Reverse the bit order in a 32-bit word
Und dazu noch verschiedene REV Befehle, um Bytes zu tauschen. Ist das 
nicht was hier benoetigt wird?

von eProfi (Gast)


Lesenswert?

for (i=0;i<32;i++)
{
  if((tmp_data & 0x80000000) == 0x80000000)
  {
    reverse_data |= mask << (unsigned long)i;
    tmp_data = tmp_data << 1;
  }
  else
  {
    reverse_data &= ~(mask << (unsigned long)i);
    tmp_data = tmp_data << 1;
  }
}


Das geht aber eleganter (mask ist Maske und Zähler in einem):
data_out=0;mask=0x80000000;do{data_out<<=1;
  if((data&mask)!=0)data_out |= 1;}while((mask>>=1)!=0);

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.