Dezimalzahlen in ASCII für Printausgabe wandeln

Für ein Projekt mit einem Arduino Mega lese ich seriell Daten ein. Der Befehl lautet: Serial.read()
Die empfangenen Daten (-123,46) werden in HEX oder DEC je nach Angabe ausgegeben. Ich will jedoch den empfangenen Zeichen etwas hinzufügen (t) und diese auf eine Anzeige seriell wieder ausgeben.
(-123,46t)
Mit dem Befehl Serial.readString() würde es ohne Umwandlung funktionieren. Das Programm habe ich auch fertig und funktioniert, nur leider benötigt die Ausgabe ca.1,1 sec. nach Empfang des Eingangszeichen. Da aller 0,5 sec der Datensatz vom Sender gesendet wird, erfolgt keine Ausgabe. Wenn ich einen einzelnen Datensatz sende geht es.

Hat jemand eine Idee? Mit dem Befehl Serial.read () beträgt die Antwortzeit ca. 0,01 sec.

Gruß Don

if (Serial1.available() > 0) // wenn zeichen vorhanden sind
{
C = Serial1.read(); // wird der empfangene String gelesen und der Variable c zugewiesen
Serial1.print(C, HEX); // Ausgabe der Empfangenen Zeichen(HEX kann auch entfallen, dann
//ist es DEC

Hi

Wie werden die '-123,46' übertragen?
Wie bekommst Du den zugehörigen Wert?
Was willst Du wirklich?
Und: Was soll an Serial.read() 1,1 Sekunden dauern?
Denke, dort greift ein TimeOut, Welches nach 1000ms zuschlägt, wenn kein 'Zeilen-Ende-Zeichen' empfangen wurde.

Allgemein ist's nicht schlecht, wenn man weiß, was kommt und wie man Das interpretieren will.

MfG

Du solltest Deine seriellen Daten mit einem Abschlusszeichen z.B. NewLine/Zeilenvorschub/'\n' beenden.
Dann musst Du nicht auf den Timeout warten und kannst readBytesUntil('\n',...) verwenden.

Gruß Tommy

Mit dem Befehl: Serial.read() dauert die Ausgabe nur 0,01 sec. Bei dem Befehl: Serial.readString() dauert diese 1,1 sec.
Die -123,46 kommen von einem PC und werden seriell übertragen. Zu dem Wert -123,46 wird das Zeichen t als Maßeinheit für Gewicht hinzugefügt und für eine Anzeige weiterverarbeitet.
Die Maßeinheit t ist fest und wird jeden Wert zugeordnet. Dieser Wert wird vom PC aller 500 ms übertragen.
Die Anzeige arbeitet mit der Print Ausgabe (box.print();). Der Wert in Klammern entspricht der angezeigten Zeichen -123.46t.
Eingangsseitig (vom PC) kann ich noch STX und ETX einstellen. Der Datensatz lautet dann STX -123,46 ETX. Da könnte ich das ETX als Abschlußzeichen verwenden um nicht auf den TIMEOUT zu warten. Weis nur nicht wie ich das programmtechnisch umsetzen kann da ich derzeit nur die Befehle Serial.read oder Serial.readString verwende.
Ich kann auch den kompletten Code senden. Brauche nur eine Info wie ich den Code einfügen kann...

Vielen Dank für eure Mühe..

Gruß Camillo

Hi

Du liest ZEICHENWEISE ein, Du erwartest
-S
-T
-X
-
... Deinen Wert, Der bis zu einem zu gehen scheint.
-E
-T
-X
fertig, Dein Wert ist dazwischen gewesen.
Diesen Wert nun verarbeiten ect.pp.
Wenn ein neues Zeichen kommt, wartest Du auf das S - wenn das jeweils nächste Zeichen NICHT kommt, wartest Du wieder auf das S als Start-Zeichen.

Nennt sich State-Maschine.

mfG

STX und ETX sind keine Zeichenfolgen, sondern ASCII-Steuerzeichen ( STX='Start of Text'=0x02, ETX='End of Text'=0x03 ).
Das ETX könnte man direkt als Terminierungszeichen in 'readBytesUntil' verwenden.

Also ich kenne STX und ETX ja als ASCII-Zeichen 2 und 3
2 STX Start of Text
3 ETX End of Text
:slight_smile:
Das ist also jeweils nur EIN Zeichen und nicht 3.

Ach zu spät ... :slight_smile:

#include <SPI.h>
#include <DMD2.h>
#include <fonts/Arial14.h>

// Set Width to the number of displays wide you have
const int WIDTH = 3;

const uint8_t *FONT = Arial14;
//const uint8_t *FONT = SystemFont5x7;

const char *MESSAGE = "Display Version 1.5         9600 Baud 8 Bit no Parity              ";
String C;              // Variable C ist String
String Gewicht;        // Variable Gewicht ist String 
String Gewicht_1;
String Geschwindigkeit;// Variable Geschwindigkeit ist String
String Geschwindigkeit_1;
int x = 0;             // Variable x ist int und 0 bei Start
String Datensatz;

SoftDMD dmd(WIDTH,1);  // DMD controls the entire display
DMD_TextBox box(dmd, 0,2);  // "box" provides a text box to automatically write to/scroll the display

// the setup routine runs once when you press reset:
void setup()
{
  Serial.begin(9600);
  dmd.setBrightness(255);
  dmd.selectFont(FONT);
  dmd.begin();
  const char *next = MESSAGE;
  while(*next) {
   //Serial.print(*next);
   box.print(*next);
   delay(100);
   next++;
  }
}

// the loop routine runs over and over again forever:
void loop()
{


   if (Serial.available() > 0)                  // wenn zeichen vorhanden sind
   {                                            // Wenn mind. ein Byte empfangen wurde
   C = Serial.readString();                     // wird der empfangene String gelesen und der Variable c zugewiesen
   x = C.length();                              // Ermittlung der Stringlänge, Wert steht in x
   String Gewicht_1 = C.substring(1,7);         // Lese  2. - 8. Zeichen des String C, Zuweisung String "Gewicht"  1.Zeichen bei 0
   String Gewicht = (Gewicht_1 + "t ");         // Hinzufügen von "t " zum String Gewicht
   String Geschwindigkeit_1 =C.substring(9,12); // Lese 10. - 12. Zeichen des String C, Zuweisung String "Geschwindigkeit"
   String Geschwindigkeit = String (Geschwindigkeit_1 + "t/min"); // Hinzufügen von "t/min" zum String Geschwindigkeit
   String Datensatz = String (Gewicht + Geschwindigkeit); //Zusammenfügen von Gewicht und Geschwindigkeit zum String Datensatz

 
  DMD_TextBox box(dmd, 1, 1, 96, 16);
  box.print(Datensatz); // Display 
  Serial.print(Datensatz);
 
  }
}

Oben der komplette Code. Der Eingangsdatensatz vom PC lautet: (STX) -123,46#1,2(ETX).
Dieser wird Datensatz wird seriell eingelesen und aufgeteilt in:
Gewicht (-123,46) und Geschwindigkeit (1,2). Zu den Daten wird beim Gewicht die Maßeinheit "t" hinzugefügt und bei der Geschwindigkeit die Maßeinheit "t/min"
Anschließend wird der Datensatz zusammengesetzt in -123,46t 1,2t/min und zur Anzeige gesendet.
Der PC sendet die Daten zyklisch aller 500 ms. Bei dem jetzigen Code dauert die Verarbeitung mind. 1,1 sec sodaß im zyklischen Betrieb keine Ausgabe an die Anzeige erfolgt. Sendet der PC nur 1 Mal funktioniert es.

Gruß Camillo

Ich denke der Fehler liegt beim Timeout. Mit der Funktion Serial.read () ist die Antwortzeit sehr kurz.

Hi

Zumindest hast Du erwähnt, daß Das wohl an dem TimeOut liegen könnte ... vll. liegt's ja am TimeOut?
Wäre Mal eine Überlegung wert ... und wenn Da schon ein TimeOut kommt, WARUM???
Vll ganz knapp vorher schon merken, daß die Daten komplett sind?

Aber mach Du Mal.

MfG

DonCamillo:
Ich denke der Fehler liegt beim Timeout. Mit der Funktion Serial.read () ist die Antwortzeit sehr kurz.

Wenn Du das ETX als Abschlußzeichen erkennen willst, musst Du auch die richtige Funktion verwenden:
Serial.readStringUntil(terminator)

Vielen Dank für die Info.

Das Programm läuft. Ich habe die Funktion: Serial1.setTimeout(100); // Timeout Zeit auf 100 ms
verwendet. Jetzt kommt die Antwort nach ca. 110 ms. Ich verstehe nur nicht wieso es bei dem Befehl Serial.read funktioniert auch ohne den Zusatz...
Hat jemand noch eine Idee wie die Funktion: if (Serial1.available()) funktioniert? Habe gelesen das man dort auch die Anzahl der zu empfangenen Zeichen eintragen kann: if (Serial1.available()==13) für 13 Zeichen.. Funktioniert aber nicht.

Grüße Camillo

Funktioniert aber nicht.

Du machst es ja auch falsch. :slight_smile:

Weil ich gutmütig bin: Probier mal if (Serial.available() > 12) wenn du denkst da kämen vermutlich mindestens 13 Zeichen an. Und verlass dich weniger auf das was du irgendwo liest, sondern nimm die Referenz. Dann erübrigen sich auch viele Fragen wie "Hat jemand eine Idee wie xyz funktioniert". Wenn in der Referenz etwas unklar bleibt, und Ausprobieren unerklärliches liefert. kann man gern hier diskutieren.

Du hast doch jetzt mit ETX einen Terminator für deine Übertragung. Warum nutzt Du den nicht? Das wurde dir doch schon mehrfach geraten.

Mit dem Terminator ETX (03hex) hat es nicht funktioniert bzw. war die Antwort auch erst nach 1, 2 sec. Verfügbar. Das ist zu lange. Hat nix gebracht. Die Definition if (serial. avalible ()) habe ich in der Englisch sprachigen Referenz nachgelesen. ARDUINO. CC. Ich teste die Sache heute mit dem Display und hoffe das alles funktioniert. Mit dem PC klappte es gestern Abend.

hat es nicht funktioniert bzw. war die Antwort auch erst nach 1, 2 sec. Verfügbar. Das ist zu lange. Hat nix gebracht

Die "1, 2 sec" hast du so programmiert. Lies mal readString

Serial.readString() reads characters from the serial buffer into a String. The function terminates if it times out (see setTimeout()).

Arduino String Objekte sind nie erforderlich, helfen nur manchmal, und das in der Regel nur scheinbar.

DonCamillo:
Mit dem Terminator ETX (03hex) hat es nicht funktioniert bzw. war die Antwort auch erst nach 1, 2 sec. Verfügbar.

Dann hast Du etwas falsch gemacht - oder dein PC-Programm sendet doch kein ETX. Zeigt doch mal den zugehörigen Sketch.

Man kann das auch komplett nicht-blockierend einlesen:
https://forum.arduino.cc/index.php?topic=659446.msg4443056#msg4443056

Geht völlig unabhängig von der Länge der Nachricht oder der Baudrate. Man schaut nach ob ein Zeichen da ist wenn nein beendet man die Funktion sofort. Ansonsten schaut man nach ob das Endzeichen da ist und meldet wenn man fertig ist.
Anders als die normalen Funktionen muss man das aber immer wieder in loop() aufrufen bis das Ende da ist!

Der Code dort ist mit einem LF als Endzeichen, aber das kann man natürlich leicht ändern. Das Startzeichen wird durch das c >= 32 entfernt. Braucht man auch nicht

Mit char Arrays statt einem String Objekt wird das Parsen auch sehr simpel:

void setup()
{
  Serial.begin(9600);

  char str[] = "-123,46#1,2";
  char* first = strtok(str, "#");
  char* second = strtok(NULL, "#");
  Serial.println(first);
  Serial.println(second);
}

Also nach der Definition von Michael_x
"Die "1, 2 sec" hast du so programmiert. Lies mal readString" wird der String nur duch das Timeout terminiert.
(Serial.readString() reads characters from the serial buffer into a String. The function terminates if it times out (see setTimeout())

Ich lade nochmals später den Code mit ETX hoch. Das Programm ist auf dem Laptop. Ich habe die Terminierung im Loop geschrieben. Vielleicht muss es im Setup stehen. Ich habe auch das Zeichen zur Terminierung seriell ausgegeben um zu sehen das dieses richtig definiert ist..

Grüße CAmillo

Ich habe gerade den Sketch umgeschrieben mit Serial1.readStringUntil(b). b ist char 3.
Die Zuweisung Timeout habe ich ausgeklammert. Die Zeitbasis für die Antwort siehe Auszug Terminalprogramm:

02.03.2020 20:07:41.29 [TX] - -123,46#2,1
02.03.2020 20:07:43.44 [RX] - -123,4t 2,1t/min
02.03.2020 20:07:46.57 [TX] - -123,46#2,1
02.03.2020 20:07:48.72 [RX] - -123,4t 2,1t/min

Wenn ich jetzt noch die Ausgabe erweitere (CR+LF ist durch println) und char b mit sende sieht das wie folgt aus:

02.03.2020 20:13:47.80 [TX] - -123,46#2,1
02.03.2020 20:13:49.95 [RX] - -123,4t 2,1t/min

Also das Zeichen char b (ETX) stimmt.

Wenn ich die Terminierung in das Setup schreibe ist es die gleiche Antwortdauer..

/*
  Scrolling alphabet demo, displays characters one at a time into a scrolling box.
 */

#include <SPI.h>
#include <DMD2.h>
#include <fonts/Arial14.h>

// Set Width to the number of displays wide you have
const int WIDTH = 3;

const uint8_t *FONT = Arial14;
//const uint8_t *FONT = SystemFont5x7;

const char *MESSAGE = "Display Version 1.5         9600 Baud 8 Bit no Parity              ";
String C;              // Variable C ist String
String Gewicht;        // Variable Gewicht ist String 
String Gewicht_1;
String Geschwindigkeit;// Variable Geschwindigkeit ist String
String Geschwindigkeit_1;
int x = 0;             // Variable x ist int und 0 bei Start
int a =13;
char b = 3;
String Datensatz;
SoftDMD dmd(WIDTH,1);  // DMD controls the entire display
DMD_TextBox box(dmd, 0,2);  // "box" provides a text box to automatically write to/scroll the display

// the setup routine runs once when you press reset:
void setup()
{
  Serial1.begin(9600);
  Serial1.readStringUntil(b);
  //Serial1.setTimeout(100);                      // Timeout Zeit auf 100 ms gesetzt
  dmd.setBrightness(255);
  dmd.selectFont(FONT);
  dmd.begin();
  const char *next = MESSAGE;
  while(*next) {
   //Serial.print(*next);
   box.print(*next);
   delay(100);
   next++;
  }
}

// the loop routine runs over and over again forever:
void loop()
{

   
   if (Serial1.available())                 // wenn zeichen vorhanden sind
   {                                            // Wenn mind. ein Byte empfangen wurde
   C = Serial1.readString();                     // wird der empfangene String gelesen und der Variable c zugewiesen
   //Serial1.readStringUntil(b);                   // Terminator b (03HEX ETX)
   x = C.length();                              // Ermittlung der Stringlänge, Wert steht in x
   String Gewicht_1 = C.substring(1,7);         // Lese  2. - 8. Zeichen des String C, Zuweisung String "Gewicht"  1.Zeichen bei 0
   String Gewicht = (Gewicht_1 + "t ");         // Hinzufügen von "t " zum String Gewicht
   String Geschwindigkeit_1 =C.substring(9,12); // Lese 10. - 12. Zeichen des String C, Zuweisung String "Geschwindigkeit"
   String Geschwindigkeit = String (Geschwindigkeit_1 + "t/min"); // Hinzufügen von "t/min" zum String Geschwindigkeit
   String Datensatz = String (Gewicht + Geschwindigkeit); //Zusammenfügen von Gewicht und Geschwindigkeit zum String Datensatz

 
 // DMD_TextBox box(dmd, 1, 1, 96, 16);
  //box.print(Datensatz); // Display TEXT SFE
  Serial1.println(Datensatz);
  Serial1.print (b);
 
  }
}

Hast Du Dir überhaupt mal die Zeichen, die Du empfängst einzeln als HEX ausgeben lassen?

Gruß Tommy