www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR: long/eine Zahl aus 3 einzelnen Bytes/Chars erzeugen


Autor: Peter Maier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

von einem Gerät (Analyser) das per serieller Schnittstelle angesprochen 
wird, möchte ich die Datenpaketgröße abfragen. Problem ist: die ist bis 
zu 3 Bytes groß. Der Ablauf ist wie folgt: ich versende ein Kommando, 
und der Analyser liefert die Datenpaketgröße für folgende Abfragen 
zurück. Meine übergeordneten Funktionen müssen sich dann dementsprechend 
verhalten.
Nun ist miene Frage: wie erzeuge ich aus 3 einzelnen Bytes/Chars ein 
unsigned long/eine Zahl?

unsigned long receive_size(void)
{
  // "Kommando" zur Bestimmung der Paketgröße
  unsigned char size[3] = {0x0D, 0x01, 0xA2};
  // Kommando absenden
  receive_cmd (&size[0]);
  // Paketgröße zurückliefern
  return size[0] * 256 + size[1] *16 + size[2]; // <-- wie gibt man ein 
long zurück, bzw, wie setzt man das zusammen?
}

Gruß,

Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Peter Maier wrote:

>   return size[0] * 256 + size[1] *16 + size[2]; // <-- wie gibt man ein
> long zurück, bzw, wie setzt man das zusammen?

Der Ansatz ist doch nicht schlecht. Nur dass in einem Byte
bis 256 gezählt werden kann und nicht nur bis 16

Du musst nur aufpassen, dass die Zwischenergebnisse keinen
Overflow produzieren. 256 ist eine int Zahl und dementsprechend
wird die Multiplikation in int gemacht. Genau das willst
du nicht. Du willst das die Berechnung bereits in unsigned long
gemacht wird um Overflows zu vermeiden.

return size[0] * 65536UL + size[1] * 256UL + size[2];

Autor: ARM-Fan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, schon fast richtig.

Wenn man also annimmt, dass das erste zurückgelieferte Byte auch
das höchstwertige ist, dann würde das so aussehen:
unsigned long length;

// dein code...

length = ((unsigned long)size[0] << 16) + ((unsigned long)size[1] << 8) + size[2];

return length;

Dein Ansatz war also schon ganz ok.
Multiplizieren mit 256 ist das selbe wie 8x links schieben.
Die Multiplikation mit 16 war jedoch verkehrt (4bit links geschoben).

Ein long sieht je nun so aus:

xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx (32bit)

Jetzt kommst du mit deinen Einzelbytes:

                           xxxxxxxx
                           yyyyyyyy
                           zzzzzzzz

Nun mußt du nur noch schieben und verodern oder addieren und fertig:

         xxxxxxxx                    << 16
                  yyyyyyyy           << 8
                           zzzzzzzz  bleibt so



Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so zum Beispiel:
long l;
((char*)(&l))[0]=size[0];
((char*)(&l))[1]=size[1];
((char*)(&l))[2]=size[2];
return l;

oder so:
return ((long)(size[0])<<16)+((long)(size[1])<<8)+((long)(size[2])<<0);

MfG Mark

Autor: ARM-Fan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mist schon wieder zu langsam, Karl-Heinz...

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

Bewertung
0 lesenswert
nicht lesenswert
Mark Prediger wrote:
> so zum Beispiel:
>
> long l;
> ((char*)(&l))[0]=size[0];
> ((char*)(&l))[1]=size[1];
> ((char*)(&l))[2]=size[2];
> return l;
> 
>

Wenn schon trickreich, dann richtig trickreich :-)
unsigned long receive_size(void)
{
  // "Kommando" zur Bestimmung der Paketgröße
  unsigned char size[4] = {0x00, 0x0D, 0x01, 0xA2};
  // Kommando absenden
  receive_cmd (&size[1]);
  // Paketgröße zurückliefern
  return *(unsigned long*)size;
}

  

Autor: Peter Maier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

erst mal vielen Dank. Das ging ja schneller als erhofft. Echt super eure 
Hilfe. Die ersten Postings verstehe ich (und wäre da evtl. auch noch 
irgendwann drauf gekommen das ein Byte bis 256 geht und ein Nibble bis 
16), die letzten drei (ok, das mittlere davon schon ;=)) jedoch nicht 
mehr :=(
Zum "ersten Missverständins": es wird ein unsigned long lokal definiert, 
und dann per Char Zeigeroperation auf die einzelnen Bytes des long 
zugegriffen. Warum fange ich mit dem Index des long nicht bei [1] an und 
gehe bis [3]. Das erste Byte (alos [0]) ist ja das MSB, das soll ja auf 
0x00 bleiben. Bekomme ja nur drei Bytes zurück.
Zum "letzten Missverständnis": ich definiere ein 4 Byte char Array (= 1 
long), übergebe der Funktion nur die letzten 3 Bytes, liefer dann aber 
ab dem ersten Byte zurück. Tricky ;=) Wäre ich nie drauf gekommen. Wobei 
ich mir da das mit den * Operatoren noch mal durch den Kopf gehen lassen 
muss.
Gibt jetzt nur ein kleines Problem: size [2] ist das LSB, size[0] das 
MSB Insofern funktionieren die Tricks nicht mehr. Trotzdem, werde ich im 
Hinterkopf behalten.

Danke,

Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Peter Maier wrote:

> ab dem ersten Byte zurück. Tricky ;=) Wäre ich nie drauf gekommen. Wobei
> ich mir da das mit den * Operatoren noch mal durch den Kopf gehen lassen

Mach dir um die Multiplikationen keine Sorgen.
Da die Konstanten 2-er Potenzen sind wir das jeder optimierende
Compiler, der etwas auf sich hält in Schiebeoperationen umwandeln.

> Gibt jetzt nur ein kleines Problem: size [2] ist das LSB, size[0] das
> MSB Insofern funktionieren die Tricks nicht mehr.

Liese sich ev. durch eine andere Beschreibereihenfolge in
der read Funktion beheben.

Allerdings: Das ist ein Trick aus der untersten Schublade
und weit davon entfernt auf jedem C System zu funktionieren
(genau aus den Gründen, die die angeführt hast).



Autor: Peter Maier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Erklärungen.

Peter

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.