Longwert: Bits vertauschen LSB zu MSB

Gast #1650975
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
Gast #1654571
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.
#2854488
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
Moderator (Firma: Titel) Persönliche Seite #2854496
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...
#2854539
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?
Moderator (Firma: Titel) Persönliche Seite #2854924
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.
Gast #2854928
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.
Gast #2899298
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);

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren