www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 16 Bit Integer in 2x8Bit Char wandeln (in C)


Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi @ all

Ich verwende den ATMEGA 32 von Atmel. Dort möchte ich aus einem 16Bit 
unsigned Integer zwei 8 Bit unsigned Char erzeugen. Jedoch weiß ich 
nicht wie ich dies anstellen soll?

Das ganze soll in C programmiert werden. Kann mir vielleicht einer einen 
Codeschnipsel erzeuegen?


unsigned int i;
unsigned char LowByte;
unsigned char HighByte;

....

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uint8_t low=i;
uint8_t hight=(i>>8);

oder sowas in der Art ...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LowByte = i;
HighByte = i >> 8;

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ups: statt uint8_t eben char, ist ja auf dem Mega32 ebenfalls 8 Bit lang

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also wenn ich einer 8 Bit Variable einen 16Bit Wert zuweise, werden nur 
die unteren 8Bit (Bit 0 bis 7) übernommen.

HighByte = i >> 8;

Schiebt dieser Befehl die Daten erst 8 stellen nach links und übernimmt 
dann Bit 0 bis Bit 7?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Er schiebt nach rechts, und vom Resultat werden Bit0..7 übernommen.

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder mache es mit einer union.

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das ist das einfachste!

Autor: ME (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ich weiss jetzt nicht gerade, ob das so funktioniert aber 
irgendwie in diese Richtung gehts wohl:

union my_converter
{ unsigned int i;
  unsigned char a;
  unsigned char b;
} u ;

u.i = irgendein_input;
u.a = erster_output;
u.b = zweiter_output;


Da ich gerade keine Möglichkeit habe, das jetzt zu prüfen, könnte 
vielleicht irgendein "alter Hase" aus dem Forum sagen, ob das geht oder 
wie man es besser macht?

Gruss und viel Erfolg
ME

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eher:
union wordbytes{
  unsigned int i;
  struct { 
    unsigned char a;
    unsigned char b;
  }
};
union wordbytes u = 0x55AA;
// ist 'u.a' jetzt 0x55 oder 0xAA?
Du musst nur nachlesen (compiler docs)/testen(Hardware/simulator) ob a 
oder b das High-bzw. Low-Byte ist.

hth, Jörg

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
und noch meinen Senf dazu ;-)

in deine Header:
typedef union uint2uchar
{
  unsigned int w;
  unsigned char b[2];
}CONVERT_WORD;


Aufruf in .C:
CONVERT_WORD word;
word.w = x;                                //zu wandelnde 16Bit 
Variable(x)
unsigned char HighByte = word.b[1];        //HighByte
unsigned char LowByte = val.b[0];          //LowByte

Gruß

Autor: ME (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, für meine falsche Antwort von gestern Abend.

Die ist etwas zu schnell gekommen. Wollte soeben eine Korrektur 
nachliefern, aber da das bereits  Jörg G. und  Fabian Ostner getan 
haben, erübrigt sich das.

Gruss
ME

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Oder mache es mit einer union.

> das ist das einfachste!

Vom Verständnis her ist beides gleich einfach - finde ich jedenfalls.

Der Union-Ansatz hat eine gewisse "geniale Eleganz", das geb ich zu. 
Nachteil ist aber, man muss sich um Byte-Order und Struct-Alignment 
Gedanken machen und den Compiler überzeugen, es genau so zu machen wie 
man möchte.

Und selbst dann ist fraglich, ob das Reinkopieren des 16-Bit-Datums in 
die Union-Variable und das Wieder-Rauskopieren der einzelnen Bytes nicht 
mehr Code erzeugt als ein bisschen Schieben und Maskieren.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tuppes wrote:

> Und selbst dann ist fraglich, ob das Reinkopieren des 16-Bit-Datums in
> die Union-Variable und das Wieder-Rauskopieren der einzelnen Bytes nicht
> mehr Code erzeugt als ein bisschen Schieben und Maskieren.

Das Rein/Rauskopieren könnte man mit geeigneter Casterei (die man in 
einem Makro versteckt) umgehen. Die Idee ist, den Compiler dazu zu 
zwingen, einen int als eine derartige Struktur aufzufassen und dann 
entsprechend zuzugreifen.
Byte Order ist natürlich ein Problem, struct-Alignment sollte aber 
keines sein. Von einem Array ist geregelt, wie es abgelegt werden muss.

typedef union uint2uchar
{
  unsigned int w;
  unsigned char b[2];
};

#define HI_BYTE(X) ( ((uint2uchar*)&(X)).b[1] )
#define LO_BYTE(X) ( ((uint2uchar*)&(X)).b[0] )


int main()
{
  int i = 25;

  writeByte( LO_BYTE( i ) );
  writeByte( HI_BYTE( i ) );
}

Ob das allerdings weniger Code erzeugt, als die Schieberei? Von einem 
ordentlichen Compiler erwarte (erhoffe) ich mir, das er hier die Absicht 
erkennt und nicht lange rumschiebt, sondern gleich auf das richtige Byte 
zugreift. Müsste man ausprobieren

#define HI_BYTE(X) ( (uint8_t)( ((uint16_t)(X)) >> 8 ) ) )
#define LO_BYTE(X) ( (uint8_t)( ((uint16_t)(X) ) ) )

int main()
{
  int i = 25;

  writeByte( LO_BYTE( i ) );
  writeByte( HI_BYTE( i ) );
}

Autor: ME (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kbuchegg schrieb:

> Von einem ordentlichen Compiler erwarte (erhoffe) ich mir, das er hier
> die Absicht erkennt und nicht lange rumschiebt, sondern gleich auf das
> richtige Byte zugreift. Müsste man ausprobieren


Ich hab jetzt mal mit AVR-GCC ausprobiert, ob der erkennt, dass er 
nichts schieben muss:

Mein C-Sourcecode war:
  unsigned int w;
  unsigned char h;
  unsigned char l;
  
  w = 300;
  
  h = (unsigned char)(w>>8);
  l = (unsigned char)(w);

AVR-GCC macht daraus (mit der Option s=0)

  81 0008 CDB7          ldi r24,lo8(300)
  82 000a DEB7          ldi r25,hi8(300)
  83                   std Y+4,r25
  84                   std Y+3,r24
   5:main.c        ****     unsigned int w;
   6:main.c        ****   unsigned char h;
   7:main.c        ****   unsigned char l;
   8:main.c        ****   
   9:main.c        ****   w = 300;
  85                 (300)
  86                   ldi r25,hi8(300)
  87 000c 8CE2          std Y+4,r25
  88 000e 91E0          std Y+3,r24
  90 0012 8B83        .LM2:
  10:main.c        ****   
  11:main.c        ****   h = (unsigned char) (w>>8);
  91                 
  92                   std Y+3,r24
  94 0016 9C81        .LM2:
  95 0018 892F          ldd r24,Y+3
  96 001a 9927          ldd r25,Y+4
  97 001c 8A83          mov r24,r25
  12:main.c        ****   l =  (unsigned char)(w);
  98                 .LM2:
  99                   ldd r24,Y+3
 100 001e 8B81          ldd r25,Y+4
 101 0020 8983          mov r24,r25


Wie man sieht gibt es also keine überflüssigen Schiebeoperationen. Der 
etwas lange Assemblercode kommt daher, dass ich mit der Option s=0 
(keine Optimierung) kompiliert habe, da sonst der Compiler merkt, dass 
meine Miniprogramm fast nichts tut und daher fast alles "wegoptimiert".

Gruss
ME

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann wrote:

> unsigned int i;
> unsigned char LowByte;
> unsigned char HighByte;
>
> ....

jetzt auch noch mein Senf dazu :)

ich arbeite im Automotive Bereich, da sind Unions aus 
Sicherheits-/Portierungsgründen weitestgehend verboten (MISRA Regeln).

Wir machen das einfach so:
LowByte   = (unsigned char)  (i & 0x00FF);      /* Get LSB */
HighByte  = (unsigned char) ((i & 0xFF00)>>8);  /* Get MSB */

Ich weiss, vieles von dem ist implizit, wie das Maskieren und das 
Casten. Aber wie gesagt gehts hier um Portierung und Sicherheit.

Bevor gleich Stimmen laut werden, dass ein Integer nicht auf allen 
Prozessoren 16 Bit hat: Das stimmt natürlich. Aber deshalb benutzen wir 
auch nicht direkt "unsigned int" sondern u16 oder u32 z.B. und 
"konfigurieren" so unsere Datentypen.

Gruss und gute nacht! :)

Autor: chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned char lowbyte = *( &VariableMit16Bit + 1) ;
unsigned char highbite = *( &VariableMit16Bit );

Könnte auch das gehen ? Oder liegen LSB und MSB umgekehrt im RAM ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
chris wrote:
>
> unsigned char lowbyte = *( &VariableMit16Bit + 1) ;
> unsigned char highbite = *( &VariableMit16Bit );
> 
>
> Könnte auch das gehen ?

Fast.
> unsigned char lowbyte = *( &VariableMit16Bit + 1) ;

Du musst hier zuerst die Adresse   &VariableMit16Bit auf einen unsigned 
char Pointer umcasten. Sonst greifen die Pointer-Arithmetik Regeln und 
das + 1 erhöht dir die Adresse um 2

> Oder liegen LSB und MSB umgekehrt im RAM ?

Ist normalerweise Prozessorabhängig. Auf einer Intel CPU ist die 
Reihenfolge: Low Byte liegt an der niedrigeren Adresse. Auf einer 
Motorola CPU liegt das High Byte an der niedrigeren Adresse.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian B. wrote:

> ich arbeite im Automotive Bereich, da sind Unions aus
> Sicherheits-/Portierungsgründen weitestgehend verboten (MISRA Regeln).

Siehs du, das verblüfft mich jetzt. Ich weiß, das in den MISRA Regeln 
einige EInschränkungen gibt (weiß aber keine Details), aber die 
schlimmste und gleichzeitig gefährlichste Waffe, die man in C haben 
kann, den cast, darf man anscheinend machen. Mit einem Cast kann man so 
ziemlich alles erreichen und ich hab da schon die wildesten Dinge 
gesehen.

Interessenhalber: Gibts da irgendwelche Einschränkungen in MISRA welche 
Casts zulässig sind und welche nicht?

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
gut das du das ansprichst Karl Heinz. Ich kenne zwar die MISRA nit, aber 
ich frage mich wirklich, was an nem Union so gefährlich sein soll, 
gegenüber wildem casting und überflüssigen Maskierungen ?

Gruß und n8.

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Siehs du, das verblüfft mich jetzt. Ich weiß, das in den MISRA Regeln
> einige EInschränkungen gibt (weiß aber keine Details),

siehe: 
http://computing.unn.ac.uk/staff/cgam1/teaching/07...

>aber die
> schlimmste und gleichzeitig gefährlichste Waffe, die man in C haben
> kann, den cast,

Halt. Nicht der Cast ist gefährlich, sondern der implizite Cast!
Sowas hier:
Byte = i; /* impliziter cast */
den sollte man nicht verwenden!
43 (req): Implicit conversions that might result in a loss of 
information shall not be used

>darf man anscheinend machen. Mit einem Cast kann man so
> ziemlich alles erreichen und ich hab da schon die wildesten Dinge
> gesehen.
>
> Interessenhalber: Gibts da irgendwelche Einschränkungen in MISRA welche
> Casts zulässig sind und welche nicht?

Explizite sind zulässig, aber es ist nicht erlaubt Pointer auf einen 
anderen Datentyp zu casten. Genauso wenig sind implizite Casts erlaubt.

45 (req): Type casting from any type to or from pointers shall not be 
used

Zu Unions sagt MISRA auch etwas:
110 (req): Unions shall not be used to access the sub-parts of larger 
data types

Abschliessend: Natürlich darf jeder so programmieren wie er mag, aber 
(wie überall) gibt es in einem kritischen Umfeld eben auch gewisse 
Regeln, die man befolgen sollte. Und sei es nur drum die lieben Kunden 
zufrieden zustellen, damit die und wir ruhig schlafen / fahren können 
:-)

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Früher hätte ich vielleicht sowas gemacht: ;-)
(Was jetzt natürlich (für mich) nicht mehr erlaubt ist!)
unsigned int i;
unsigned char LowByte;
unsigned char HighByte;

unsigned char char_array[2];
unsigned char * p_char;

/* Vorraussetung eine Little Endian Maschine 
   Also: Niederwertigstes Byte liegt an niederster Speicheradresse 
*/
p_char   = (unsigned char*) (i);
LowByte  = p_char[0];
HighByte = p_char[1];

Das war keine Empfehlung! ;-)

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, Fehler :-)

Sebastian B. wrote:
> Früher hätte ich vielleicht sowas gemacht: ;-)
> (Was jetzt natürlich (für mich) nicht mehr erlaubt ist!)
>
> unsigned int i;
> unsigned char LowByte;
> unsigned char HighByte;
> 
> unsigned char char_array[2];
> unsigned char * p_char;
> 
> /* Vorraussetung eine Little Endian Maschine
>    Also: Niederwertigstes Byte liegt an niederster Speicheradresse
> */
[c]
> p_char   = (unsigned char*) (i);
richtig wäre:
p_char     = (unsigned char*) (&i); // sonst mache ich aus dem Wert von i ja eine Adresse... eher ungut
> LowByte  = p_char[0];
> HighByte = p_char[1];
> [/c]
>
> Das war keine Empfehlung! ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian B. wrote:

>>aber die
>> schlimmste und gleichzeitig gefährlichste Waffe, die man in C haben
>> kann, den cast,
>
> Halt. Nicht der Cast ist gefährlich, sondern der implizite Cast!

:-)

Eine junge Kollegin (ist schon lange her), schrieb mal Folgendes 
(sinngemäß)
struct Line {   int Params[10]; };
struct Circle { double Radius; };

struct Line* Funktion( struct Circle* circ )
{
  ...
  return (struct Line*) circ
}

und wunderte sich, warum das Program elendiglich verreckte. Nachdem sie 
sich Hilfe geholt hatte, haben wir zu Dritt nach dem Fehler gesucht und 
nach 2 Stunden dann diesen Bonmont entdeckt.
Ja das hätte sie als eine der letzten Aktionen gemacht. Und auf die 
Frage, warum sie denn da überhaupt umgecastet hat, kam die Antwort: Weil 
mir der Compiler eine Fehlermeldung gebracht hat, wenn ich den cast 
weglasse.
Gefunden haben wir das nur deshalb, weil sie beim Aufrufer natürlich auf 
die Struktur geschrieben hat, und sich auf diesem Wege den Returnstack 
aber sowas von zerschossen hat. Wir sind beim Debuggen natürlich den 
umgekehrten Weg gegangen: Progamm crasht, irgendwann verdichtete sich 
der Gedanke, dass am Return Stack was nicht stimmt, und unzählige 
Debuggerläufe später konnten wir den Bereich eingrenzen, an dem sich ein 
paar Returnadressen am Stack seltsam verhielten :-)

Seitdem muss ich immer schmunzeln, wenn jemand einen cast als 'harmlos' 
bezeichnet. (Klar: Schuld ist nicht der cast an sich, sondern sie hat 
einfach nicht nachgedacht was sie da tut. Eine struct in eine komplett 
andere struct umzucasten ist, wie wenn man ein Pferd für eine Kuh 
verkauft)

> Explizite sind zulässig, aber es ist nicht erlaubt Pointer auf einen
> anderen Datentyp zu casten. Genauso wenig sind implizite Casts erlaubt.

OK. So eingeschränkt ist das sinnvoll.

> Abschliessend: Natürlich darf jeder so programmieren wie er mag, aber
> (wie überall) gibt es in einem kritischen Umfeld eben auch gewisse
> Regeln, die man befolgen sollte.

Ja, das ist schon klar. Ich find das auch wichtig. So wie ich mich an 
Regeln halte, erwarte ich auch von meinen Leuten dass sie sich an Regeln 
halten. Ohne gehts nicht.

Muss ich mir doch mal reinziehen, dieses MISRA

Autor: Sebastian B. (mircobolle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Sebastian B. wrote:

>> Halt. Nicht der Cast ist gefährlich, sondern der implizite Cast!
>
> :-)

Ja, natürlich kann man mit Cast vielerlei Unfug generieren. ;-)
Diese MISRA Regel mit den explizisten Cast setzt natürlich voraus, dass 
man weiss was man tut. Nicht unerheblich ist bei einem expliziten cast 
natürlich auch der Nutzen der Dokumentation. Man SIEHT einfach in was 
konvertiert werden soll. Wenn der Programmierer ganz gütig war hat er 
vielleicht sogar noch einen Satz Kommentar dazu geschrieben.

>> Explizite sind zulässig, aber es ist nicht erlaubt Pointer auf einen
>> anderen Datentyp zu casten. Genauso wenig sind implizite Casts erlaubt.
>
> OK. So eingeschränkt ist das sinnvoll.
>
>> Abschliessend: Natürlich darf jeder so programmieren wie er mag, aber
>> (wie überall) gibt es in einem kritischen Umfeld eben auch gewisse
>> Regeln, die man befolgen sollte.
>
> Ja, das ist schon klar. Ich find das auch wichtig. So wie ich mich an
> Regeln halte, erwarte ich auch von meinen Leuten dass sie sich an Regeln
> halten. Ohne gehts nicht.
>
> Muss ich mir doch mal reinziehen, dieses MISRA

Ich weiss natürlich auch nicht, ob MISRA DER WEG ist, aber zumindest 
sind die Regeln anerkannt. Wenn man einem Kunden garantieren kann z.b. 
mittels QA-C, dass man MISRA konform ist, dann werden schon mal ein paar 
Anforderungen an die Software-Qualität abgedeckt. aber das ist ein 
anderes Thema.. :-)

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.