Zwei Byte-Zahlen und Buchstaben

Ich experimentiere momentan mit dem MIT-App Inventor, und schicke über eine App per Bluetooth Zahlen, die größer als ein Byte sind, und einzelne Buchstaben an den Arduino. Mein Problem ist nun folgendes: bei den Zahlen bekomme ich so etwas:

0
1
149

Dies passiert, weil die Zahl größer als ein Byte ist, das ist mir klar, aber wie füge ich sie auf dem Arduino wieder korrekt zusammen?
Das zweite Problem ist das Senden einzelner Buchstaben. Wenn ich beispielsweise ein 'A' schicke, bekomme ich folgendes:

65
13
10

Wie kann ich diese Zahlenfolge nun wieder in normalen Text umwandeln?

LG Felix

Hallo,
zu den Buchstaben: 65, 13, 10
65 ist das ASCII Zeichen für “A”, 13 ist Steuerzeichen für “Wagenrücklauf ohne Zeilenvorschub”, 10 ist Steuerzeichen für Zeilenvorschub. 13,10 bewirkt eine neue Zeile.

zu der Zahl: Hier kann man nur vermuten, weil unbekannt ist was gesendet wurde. Vielleicht
1 * 256 + 149 = 405 (nur Vermutung. 1 könnte der höherwertige Teil des 2 Byte Wertes sein.
Viele Grüße Manfred

Beim ersten Beispiel solltest Du mal sagen, was Du geschickt hast.
Es werden Dir im Normalfall die beiden Bytes (LowByte und HighByte) geschickt.
In welcher Reihenfolge hängt von Deinem Sendeprogramm ab.

Beim 2. Beispiel hast Du bekommen:
65 = A, 13 = Wagenrücklauf, 10 = Zeilenvorschub
Du hast wohl die Eingabe mit der Entertaste beendet.

Es würde nicht schaden, wenn Du Dich in solche elementarsten Grundlagen einlesen würdest, wenn Du Dich erfolgreich mit dem Arduino beschäftigen willst.

Gruß Tommy

Tommy56:
Beim ersten Beispiel solltest Du mal sagen, was Du geschickt hast.
Es werden Dir im Normalfall die beiden Bytes (LowByte und HighByte) geschickt.
In welcher Reihenfolge hängt von Deinem Sendeprogramm ab.

Beim 2. Beispiel hast Du bekommen:
65 = A, 13 = Wagenrücklauf, 10 = Zeilenvorschub
Du hast wohl die Eingabe mit der Entertaste beendet.

Es würde nicht schaden, wenn Du Dich in solche elementarsten Grundlagen einlesen würdest, wenn Du Dich erfolgreich mit dem Arduino beschäftigen willst.

Gruß Tommy

Ich bekomme anscheinend von meiner App nun zuerst das Low-, dann das High-Byte geschickt.

Zu den Ziffern:
Getestet habe ich mit einer "Konsolen"-App. Mit meiner App bekomme ich dann bspw.:
71
10

Kurz zur Erklärung, was eventuell behilflich sein könnte: über die App wird eine RGB-LED gesteuert, diese wird über den PWM-Wert gedimmt, und über die gesendeten Buchstaben sollen weitere Befehle aktiviert werden.

Bezüglich "Elementarster Grundlagen": Wo soll ich so etwas wie das beispielsweise finden? Gegoogelt habe ich schon, falls das die Antwort wäre.

Bezüglich "Elementarster Grundlagen": Wo soll ich so etwas wie das beispielsweise finden? Gegoogelt habe ich schon, falls das die Antwort wäre.

Tja, da hast du Recht. Tommy weiss wahrscheinlich auch nicht mehr, wer ihm Laufen beigebracht hat und was dabei zu beachten ist.

Zu "Elementarsten Grundlagen" wie z.B. hier
"Wenn ich ein A lesen sollte, kriege ich aber eine 65? Und was bedeutet die 10 dahinter?"
findet man die Lösung erst, wenn man schon weiss, oder zumindest ahnt, was passiert.

Zum Thema "Binär-Übertragung von Zahlen" würde ich sagen dass man das der Einfachheit halber nicht macht. Serielle Übertragung hat den Vorteil, dass du anstelle Deiner Bluetooth-Verbindung per eigener App auch genausogut zum Testen den SerialMonitor nehmen kannst, wenn du alles als Text überträgst.

Also statt 1000 als 16-Bit zahl ( 0x03E8 ) in zwei Byte (0xe8 = 232 und 0x03 = 3) lieber in 5 Byte Text
( "1000" ) wandeln und diesen Text übertragen. Möglichst noch mit einer Ende-Kennzeichnung.

In umgekehrter Richtung sendet z.B.
Serial.println(1000);
6 Bytes ( '1', '0', '0', '0', '\r', '\n' )
oder in der (nur) von dir bevorzugten Dezimalschreibweise 49, 48, 48, 48, 13, 10.

Wenn es dir nicht auf kompakteste und damit schnellste Übertragung ankommt, und obwohl du auf der anderen Seite aus dem Text meist wieder eine Zahl machen musst, ist die einfache Schreib- und Lesbarkeit für Menschen ein wichtiges Argument.

Was soll das heißen, von mir bevorzugt? Das sind die Daten, die ich von der App, bekomme, und die Frage war ja eben, wie ich diese wieder in verständliche bzw. verwertbare Zahlen / Ziffern zurückwandle. Ich könnte es natürlich über den seriellen Monitor schicken, aber ich verwende ja Bluetooth, damit ich den seriellen Monitor nicht verwenden muss.

Was soll das heißen, von mir bevorzugt?

Wenn du weisst, dass es ein A sein soll, warum schreibst du dann 65 statt ‘A’ ? Das ist dasselbe, aber du magst wohl lieber die Darstellung als Dezimalzahl. ( Sonst sollte das “von dir bevorzugt” nichts heissen )

Wenn ich weiss, dass es ein Byte mit irgend einem Bitmuster ist, bevorzuge ich eher die Hex-Darzellung, das ist meiner Meinung nach ein guter Kompromiss zwischen sichtbarem Bitmuster und kompakter Darstellung.

Da wir hier deine selbstgeschriebene Android-App nicht kennen, wäre es einfacher, wenn sie sich wie eine “normale” serielle Kommunikation verhalten würde.
Wenn sie das nicht tut und auch nicht tun soll, musst du schon genau beschreiben, was eigentlich gesendet wird, und was ankommt (von mir aus auch als Dezimal-Zahl dargestellt).

Getestet habe ich mit einer “Konsolen”-App. Mit meiner App bekomme ich dann bspw.:
71
10

Wenn das eine int16_t Zahl ist, könnte es 71+10256 = 263110 gewesen sein (kleinstes Byte zuerst)
Oder auch 71
256+10 = 1818610 (größtes Byte zuerst)
Wenn es ein Text war, wäre “G\n”, also ein ‘G’ und ein NewLine -Steuerzeichen eine sinnvolle Interpretation.

Auch ist die Synchronisation mehrerer Bytes gelegentlich ein Problem bei binärer Übertragung.
Aber das kommt später.

michael_x:
Wenn du weisst, dass es ein A sein soll, warum schreibst du dann 65 statt ‘A’ ? Das ist dasselbe, aber du magst wohl lieber die Darstellung als Dezimalzahl.

Nein, anscheinend habe ich es nicht geschafft, dir mein Problem verständlich zu machen. Wenn ich in der App ein “A” (also wirklich ein A in Klartext, keine 65) an den Arduino schicke, kommt dort 65 an. Die Darstellung als Dezimalzahl mag ich nicht, Klartext wäre mir wesentlich lieber.

michael_x:
Wenn das eine int16_t Zahl ist, könnte es 71+10256 = 263110 gewesen sein (kleinstes Byte zuerst)
Oder auch 71
256+10 = 1818610 (größtes Byte zuerst)
Wenn es ein Text war, wäre “G\n”, also ein ‘G’ und ein NewLine -Steuerzeichen eine sinnvolle Interpretation.

Es ist ein Text und - wie schon richtig erkannt ein G, allerdings wird dieser Buchstabe auch (unfreiwillig) in eine Zahl umgewandelt, und wo das Steuerzeichen herkommt weiß ich nicht.

michael_x:
Da wir hier deine selbstgeschriebene Android-App nicht kennen, wäre es einfacher, wenn sie sich wie eine “normale” serielle Kommunikation verhalten würde.
Wenn sie das nicht tut und auch nicht tun soll, musst du schon genau beschreiben, was eigentlich gesendet wird, und was ankommt (von mir aus auch als Dezimal-Zahl dargestellt).

Was ich getan habe.

Des Weiteren weiß ich gerade nicht, wie du auf irgendwelche Bitmuster kommst, kannst du das kurz erläutern?

Nein, anscheinend habe ich es nicht geschafft, dir mein Problem verständlich zu machen

Beruht wohl auf Gegenseitigkeit. :wink:

Also:
'A' und 65 ist dasselbe !

if ( 'A' == 65 )  {
     // Kommt hier hin !
     Serial.print (65); Serial.write (65); Serial.write('A'); Serial.println('A');  // 65AA65
}

Dein Problem #1 ist, dass print versucht, die Zahl so darzustellen, wie du es vermutlich möchtest.
Wenn du nichts anderes angibst, wird einintals DezimalZahl ausgegeben, eincharals Buchstabe.

Serial.write wandelt nicht und hat nur 3 Varianten: 1 Buchstabe, Text bis zum Ende, byte array fester Länge.

Dein Problem #2 ist dass Serial.read() ein int zurückliefert.
Die möglichen Werte sind -1: z.Zt. kein Zeichen vorhanden, oder 0 .. 255 : ein übertragenes Byte

Eine übliche Sequenz ist

if (Serial1.available() ) {
   char c = Serial1.read(); // falls available > 0, kann hier keine -1 kommen, Ergebnis passt in ein char.
   Serial.print(c); // Serial.write(c) ist bei Datentyp char dasselbe: das Zeichen wird nicht gewandelt 
   switch (c) {
       case 'G': // manchmal leichter lesbar als case 0x47: oder case 71: 
       do_G();
       break;

   } 
}

Des Weiteren weiß ich gerade nicht, wie du auf irgendwelche Bitmuster kommst, kannst du das kurz erläutern?

Wenn du dir eine Tabelle der Buschstabencodes ansiehst (google ASCII) wirst du merken, dass die Erfinder in Bitmustern gedacht haben.

'A' + 0x20 == 'a' :wink:

DezimalZahlen sind einfach unpassend.

'A' == 0x41 muss man bald nicht mehr nachschlagen, und dass 0x40 == 64 hat man bald auch im Kopf,

aber 'G' == 71 war dann schon schwieriger :wink:

michael_x:
Tja, da hast du Recht. Tommy weiss wahrscheinlich auch nicht mehr, wer ihm Laufen beigebracht hat und was dabei zu beachten ist.

Das kann ich Dir ganz genau sagen: Das war Tommy mit Hilfe einiger Bücher (solche Dinger aus Papier).

Da lag so ein minimaler Rechner mit Z80 Prozessor, 1 KByte RAM (den sich Programm und Daten teilen mussten), einer 6-Stelligen HEX-Anzeige und einer HEX-Tastatur. Der einzige Komfort war die Möglichkeit, das Programm auf einem Audiokassettenrecorder zu speichern und von dort wieder einzulesen.

Das Ding wollte zum Laufen gebracht werden. Beigefügte "Literatur": Eine kurze Beschreibung der Anschlüsse, eine Hex-Liste der Maschinenbefehle (für einen Assembler reichte der RAM nicht).

Dann gab es öffentliche Bibliotheken und Buchläden.
Das Internet war für mich noch nicht verfügbar. Ich konnte also nicht mal eben fragen.

Nach 3 Wochen lief auf dem Teil ein (einfacher) Taschenrechner.

Wenn man will, findet man auch die notwendigen Grundlagen.

Gruß Tommy

michael_x:
Beruht wohl auf Gegenseitigkeit. :wink:

Also:
'A' und 65 ist dasselbe !

if ( 'A' == 65 )  {

// Kommt hier hin !
    Serial.print (65); Serial.write (65); Serial.write('A'); Serial.println('A');  // 65AA65
}



Dein Problem #1 ist, dass **print** versucht, die Zahl so darzustellen, wie du es vermutlich möchtest.
Wenn du nichts anderes angibst, wird ein` int `als DezimalZahl ausgegeben, ein` char `als Buchstabe.

Serial.**write** wandelt nicht und hat nur 3 Varianten: 1 Buchstabe, Text bis zum Ende, byte array fester Länge.

Dein Problem #2 ist dass Serial.**read**() ein int zurückliefert.
Die möglichen Werte sind **-1**: z.Zt. kein Zeichen vorhanden, oder **0 .. 255** : ein übertragenes Byte

Eine übliche Sequenz ist



if (Serial1.available() ) {
  char c = Serial1.read(); // falls available > 0, kann hier keine -1 kommen, Ergebnis passt in ein char.
  Serial.print(c); // Serial.write(c) ist bei Datentyp char dasselbe: das Zeichen wird nicht gewandelt
  switch (c) {
      case 'G': // manchmal leichter lesbar als case 0x47: oder case 71:
      do_G();
      break;

}
}

Das A = 65 ist habe ich ja schon verstanden :wink: mir geht es nun darum, dass ich die 65 wieder zurück in Text wandeln kann, und am Besten auch kein Steuerzeichen mitkommt :slight_smile: kann ich also die Buchstaben mit bspw.: char Buchstabe = Serial.read(); speichern? Und die Zahlen dann wie gewohnt mit int Zahl = Serial.read(); ?

verfelixt:
... mir geht es nun darum, dass ich die 65 wieder zurück in Text wandeln kann ...

Die Behandlung der 65 hängt auch vom Variablentyp ab. Als byte macht print eine Zahl daraus, als char einen Buchstaben. Dennoch kann man mit Buchstaben auch rechnen:

void setup(void) {
  Serial.begin(9600);
  Serial.println(F("Anfang"));
  byte zahl = 65;
  Serial.print(F("zahl: "));
  Serial.println(zahl);
  char zeichen = 'A';
  Serial.print(F("zeichen: "));
  Serial.println(zeichen);
  char z = char(zahl);
  Serial.print(F("z: "));
  Serial.println(z);
  z = z + 1;
  Serial.print(F("z: "));
  Serial.println(z);
}

void loop (void) {}

verfelixt:
... und am Besten auch kein Steuerzeichen mitkommt ...

Steuerzeichen haben eine ordnende Bedeutung, sind also wichtig. Mit case '\n' kannst Du den Zeilenvorschub nutzen, weil er ja das Ende einer Informationskette darstellt.

mir geht es nun darum, dass ich die 65 wieder zurück in Text wandeln kann,

Hmm…
Ist das ein Irrtum in der Sache?

Ich denke ja…
Denn:
65 ist A
Da muss nichts gewandelt werden.

Es ist eine Frage der Interpretation!
Wenn du dem Compiler klar machst, dass du das als Zeichen betrachten möchtest, dann wird er gehorchen.
Umgekehrt natürlich genau so.

Das ist dasselbe, aber du magst wohl lieber die Darstellung als Dezimalzahl.

:confused:

Die nächsten Probleme werden auf dem Fuße folgen.

Der Datenstrom muss analysiert werden.
Ein Protokoll ist Pflicht.
In der Regel verwendet/schreibt man für die Analyse einen Parser.
Einen kleinen endlichen Automaten.

Die “CMDMessager 3 LIB” kann dir davon vieles abnehmen.
Ein schlichtes Protokoll
Fertiger Parser