Forum: Mikrocontroller und Digitale Elektronik Serial.print() eines uint8_t gibt 4 Bytes aus?!


von L. N. (derneumann)


Lesenswert?

Hallo,

ich habe folgende Structs:
1
#define RF69_MAX_DATA_LEN 61
2
3
struct nodePacketTH {
4
  uint8_t command;
5
  uint8_t serialNumber[6];
6
  float temperature;
7
  float humidity;
8
};
9
10
struct RF69dataPacket {
11
  uint8_t len;
12
  uint8_t senderID;
13
  uint8_t targetID;
14
  uint8_t rssi;
15
  char buffer[RF69_MAX_DATA_LEN];
16
  bool ackRequested;
17
};
18
19
RF69dataPacket packet;
20
nodePacketTH nodePacket;

und folgenden Code:
1
for (uint8_t n = 0; n < 15; n++)
2
{
3
  Serial.print(n);
4
  Serial.print(": ");
5
  Serial.println(packet.buffer[n], HEX);
6
}

Die Ausgabe sieht so aus:
0: 54
1: 30
2: FFFFFFBC
3: 77
4: 14
5: 73
6: FFFFFF90
7: FFFFFFB0
8: FFFFFFB6
9: FFFFFFDB
10: 41
11: 10
12: FFFFFFF9
13: FFFFFFA7
14: 41


µC ist ein Atmega328p, Arduino Framework wird genutzt.
Wie ist denn das möglich, dass bei der Ausgabe eines Bytes plötzlich 4 
Bytes ausgegeben werden? Der Inhalt des Buffers passt, ich übertrage 
genau 15 Byte dieses Buffers auf eine andere Node (per Funk) und dort 
kommen die Daten ohne den führenden drei FF Bytes an.

Bug in der Serial.print? Hat das möglicherweise etwas mit dem Alignment 
der Struct aufgrund der floats darin zu tun?

Braucht ihr mehr Infos, oder ist der Fehler schon offensichtlich?

Danke!


edit:
1
for (uint8_t n = 0; n < 15; n++)
2
{
3
  snprintf(printbuf, sizeof(printbuf), "%u: %x", n, packet.buffer[n]);
4
  Serial.println(printbuf);
5
}

Gibt übrigens folgendes aus:
0: 54
1: 30
2: ffbc
3: 77
4: 14
5: 73
6: ff90
7: ff84
8: 24
9: ffdc
10: 41
11: 10
12: ffff
13: ffa6
14: 41

also nur mehr ein führendes Byte. wtf?

von Walter (Gast)


Lesenswert?

wie ist packet definiert??
Hast du schon in der Doku von serial.printf nachgesehen?

von L. N. (derneumann)


Lesenswert?

Walter schrieb:
> wie ist packet definiert??

sorry, hab ich grad ergänzt, steht jetzt oben.

Walter schrieb:
> Hast du schon in der Doku von serial.printf nachgesehen?

Naja, die Arduino Doku zu Serial.print ist sehr spärlich. Arduino halt.
Wenn ich einen int16 oder int ausgeben würde, würde ich es ja verstehen, 
aber char? char ist doch 1 byte groß.

Das hier hab ich gefunden:
https://electronics.stackexchange.com/questions/49662/arduino-why-does-serial-printlnint-hex-display-4-bytes

wirft aber nur noch mehr Rätsel auf, da ich ja eben einen char 
verwende...

von A. S. (Gast)


Lesenswert?

char ist (vielleicht) signed und nicht uint8_t.

von A. S. (Gast)


Lesenswert?

A. S. schrieb:
> char ist (vielleicht) signed und nicht uint8_t.

Die "langen" Zahlen sind negative Zahlen -1..-127 als unsigned 
dargestellt.

von L. N. (derneumann)


Lesenswert?

A. S. schrieb:
> char ist (vielleicht) signed und nicht uint8_t.

hmm, wenn ich packet so definiere:
1
struct RF69dataPacket {
2
  uint8_t len;
3
  uint8_t senderID;
4
  uint8_t targetID;
5
  uint8_t rssi;
6
  uint8_t buffer[RF69_MAX_DATA_LEN];
7
  bool ackRequested;
8
};
9
10
RF69dataPacket packet;

dann bekomme ich keine führenden Bytes bei der Ausgabe (passt also), 
dafür natürlich Compilerwarnungen bei
1
snprintf(packet.buffer, 8, "P%s", settingsObj.serialNumber);

á la:
invalid conversion from 'uint8_t* {aka unsigned char*}' to 'char*' 
[-fpermissive]

von L. N. (derneumann)


Lesenswert?

Wenn ich mir die Print.cpp anschaue, dann ist das wohl nur eine 
Anzeigesache (was ja auch durch die Tatsache bestätigt wird, dass die 
Daten richtig ankommen):

https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Print.cpp

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ja, die Ausgabe negativer Zahlen (char ist beim GCC defaultmäßig 
vorzeichenbehaftet) in einer von 10 verschiedenen Basis erfolgt immer im 
32-Bit-Zweierkomplement, bei 8-Bit-Werten in hex also in der Form 
FFFFFFxx. Um das zu vermeiden, musst den Wert in ein unsigned char oder 
uint8_t casten:

1
Serial.println((uint8_t)packet.buffer[n], HEX);

von L. N. (derneumann)


Lesenswert?

Yalu X. schrieb:
> Ja, die Ausgabe negativer Zahlen (char ist beim GCC defaultmäßig
> vorzeichenbehaftet) in einer von 10 verschiedenen Basis erfolgt immer im
> 32-Bit-Zweierkomplement, bei 8-Bit-Werten in hex also in der Form
> FFFFFFxx. Um das zu vermeiden, musst den Wert in ein unsigned char oder
> uint8_t casten:
>
> Serial.println((uint8_t)packet.buffer[n], HEX);

Vielen Dank. Du hast in sinnvolle Worte gefasst, was ich mir im Groben 
schon gedacht habe, nach den letzten Posts.

Wenn hier Threads geschlossen werden können, gäbe es kaum einen 
passenderen Zeitpunkt als jetzt. Frage beantwortet :-)

von A. S. (Gast)


Lesenswert?

Wenn Du mit printf in den Buffer schreiben möchtest, dann lass ihn char.

Wenn Du einzelne Bytes anzeigen möchtest, dann caste sie auf uint_8.

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.