Forum: Mikrocontroller und Digitale Elektronik Little Endian zu Big Endian bei 8Bit MCU


von Obs (Gast)


Lesenswert?

Hi Community,

ich hab folgendes Problem: Ich habe eine 8Bit AVR MCU und wenn ich nun 
eine Variable vom Typ uint32_t habe und sowas mache:

uint32_t counter = 0x1a2b3c4d;

dann legt er es so im Speicher ab:
4d3c2b1a

Also ist das wohl Little Endian. Das Problem ist aber, dass ich ein 
Netzwerkprotokoll implementiere und da brauche ich Big Endian. Gibt es 
da jetzt einen einfachen Weg um das zu erreichen?

Ich könnte jetzt zwar statt eines uint32_t einfach ein Array mit vier 
uint8_t nehmen, aber wenn ich dann z.b. nen Counter habe und den erhöhen 
will, muss ich den Counter ja dann "manuell" implementieren, also etwa 
so:

counter[0]++;
if(counter[0] == 0)
  counter[1]++;
if(counter[1] == 0)
  counter[2]++;
if(counter[2] == 0)
  counter[3]++;

Alternativ könnte ich natürlich erst mal mit nem uint32_t arbeiten und 
ganz normal inkrementieren und damit rechnen und muss es dann umkopieren 
nach dem Motto:

counter_8[0] = (counter_32 >> 24);
counter_8[1] = (counter_32 &0xFF0000) >> 16;
counter_8[2] = (counter_32 &0xFF00) >> 8;
counter_8[3] = (counter_32 &0xFF);


aber das finde ich auch unschön. Gibt es da noch nen eleganteren Weg?

von gerhard (Gast)


Lesenswert?

typischer einsatzfall für ein union.

gruss
gerhard

von Fabian O. (xfr)


Lesenswert?

An den Code aus dem uIP-Stack angelehnt:
1
#if BYTE_ORDER == BIG_ENDIAN
2
  #define HTONS(n) (n)
3
  #define HTONL(n) (n)
4
#else
5
  #define HTONS(n) ((uint16_t)((((uint16_t) (n)) << 8) | (((uint16_t) (n)) >> 8)))
6
  #define HTONL(n) (((uint32_t)HTONS(n) << 16) | HTONS((uint32_t)(n) >> 16))
7
#endif
8
9
#define NTOHS(n) HTONS(n)
10
#define NTOHL(n) HTONL(n)

HTONS steht für Host to Network Short (16 Bit)
HTONL steht für Host to Network Long  (32 Bit)

NTOHS und NTOHL entsprechend für Network to Host, machen aber natürlich 
das gleiche. Das praktische an den Makros ist, dass man sie auch in 
Switch-Case-Statements für Konstanten benutzen kann und damit schon zur 
Compilezeit aufgelöst werden.

Zur Verwendung: Intern mit ganz normalen uint16_t und uint32_t rechnen. 
Direkt vor dem Senden bzw. Empfangen das Makro benutzen, um den Wert 
umzukopieren. In der Regel muss er ja sowieso von einer lokalen Variable 
in einen Sendepuffer oder umgekehrt kopiert werden, da kann man ihn mit 
Hilfe des Makros gleich bei umsortieren.

von Wilhelm F. (Gast)


Lesenswert?

Obs schrieb:

> Gibt es
> da jetzt einen einfachen Weg um das zu erreichen?

Entweder mit der Union, was Fabian beschrieb, oder eine kleine 
Umsortierfunktion mit unter Umständen skalierbarer Byteanzahl als 
Übergabeparameter.

Da ist die Frage, was von beiden komfortabler, platzsparender oder 
schneller ist, und was man davon idealerweise benötigt. Notfalls das 
Assemblerlisting anschauen, welchen Code eine Union erzeugt, und welchen 
eine einfache Umsortierung.

Gelegentlich bastelte ich für Assemblerprogramme mal irgendwo gefundene 
Funktionen von Little-Endian auf Big-Endian um, und umgekehrt. Oder ich 
machte eine Copy-Funktion dazwischen. Denn man findet für den selben µC 
oft fertige Routinen beider Arten, und möchte sich in seinem Programm 
auf eine Art fest legen.

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.