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


von Peter Maier (Gast)


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

von Karl H. (kbuchegg)


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];

von ARM-Fan (Gast)


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:
1
unsigned long length;
2
3
// dein code...
4
5
length = ((unsigned long)size[0] << 16) + ((unsigned long)size[1] << 8) + size[2];
6
7
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



von Mark .. (mork)


Lesenswert?

so zum Beispiel:
1
long l;
2
((char*)(&l))[0]=size[0];
3
((char*)(&l))[1]=size[1];
4
((char*)(&l))[2]=size[2];
5
return l;

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

MfG Mark

von ARM-Fan (Gast)


Lesenswert?

Mist schon wieder zu langsam, Karl-Heinz...

von Karl H. (kbuchegg)


Lesenswert?

Mark Prediger wrote:
> so zum Beispiel:
>
1
> long l;
2
> ((char*)(&l))[0]=size[0];
3
> ((char*)(&l))[1]=size[1];
4
> ((char*)(&l))[2]=size[2];
5
> return l;
6
>
>

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

  

von Peter Maier (Gast)


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

von Karl H. (kbuchegg)


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).



von Peter Maier (Gast)


Lesenswert?

Vielen Dank für die Erklärungen.

Peter

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.