ich übe mich gerade im jonglieren mit Arrays und dem Seriellen Monitor. Mein Plan ist es eine Nachricht über den Seriellen Monitor einzugeben diesen in einen Array zu Speichern und ein Schlüsselwort darin zu suchen, um dann alles nach dem Schlüsselwort dann in einen Int zu konvertieren um es später im code weiter zu verwenden.
Das ist wirklich eine Herausforderung gewesen aber die letzten Tage habe ich mich intensiv damit beschäftigt und bin sogar schon ziemlich weit. Wichtig ist mit dabei dass ich eine non-blocking Operation benutze wie Serial.read() und nicht z.B. Serial.readStringUntil() weil ich von Processing Daten empfangen möchte und das nur mit Serial.read() zu funktionieren scheint.
So viel zum Hintergrund, nun zu meinem Problem: Wie ihr es dem Titel vielleicht schon entnehmen könnt bin ich schon soweit dass ich die Nachricht mit dem Kennwort = "Kevin" schon separiert habe. Ich versuche nun die Nachricht ("456") als Int zu Speichern um eine LED an meinem Breadboard anzusteuern. Das will aber nicht funktionieren... Ich lasse mir den Inhalt von goodData ausgeben und sehe ein ? vor meiner eingegeben Nachricht. Ich vermute dass es daran liegen wird, dennoch kann ich mir nicht erklären was ich da Falsch machen könnte.
Hat dazu jemand vielleicht eine Idee?
char val; // Data received from the rawDataerial port
int ledPin = 2;
char rawData[32];
char keyword[] = "kevin";
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
int availableBytes = Serial.available(); //Anzahl der Eingegebenen Zeichen
for(int i; i<availableBytes; i++){
rawData[i] = Serial.read();
rawData[i+1] = NULL;
Serial.print(rawData[i]);
}
char *keywordPointer = strstr(rawData, keyword);
if (keywordPointer != NULL) {
int dataPorawDataition = (keywordPointer - rawData) + strlen(keyword); //Position nach dem Keywort
char goodData[20];
strncpy(goodData, &rawData[dataPorawDataition], sizeof(goodData));
Serial.println(goodData); //Ausgabe von goodData mit einem ? - warum?
val = atoi(goodData);; //Vermutlich funktioniert deswegen das Convertieren nicht?
Serial.print(val);
}
if (val == 456) { // If 456 rawData received
digitalWrite(ledPin, HIGH); // turn the LED on
} else {
digitalWrite(ledPin, LOW);
}
delay(100);
}
Wenn es darum geht mit dem Text zu beschreiben was die Zahl bedeutet, kannst du auch nur einen einzelnen Buchstaben nehmen. Den kann man einfach mit switch/case abfragen
Das Einlesen ist so nicht gut. Du bedenkst nicht wie langsam die serielle Schnittstelle ist. Ein Zeichen braucht 1 / Baudrate * 10 Sekunden! Das geht also nicht in einer for-Schleife. Die bricht gleich nach dem ersten Zeichen ab. Generell nimmt man ein Endzeichen wie das Linefeed und/oder Carriage Return um das Ende der Übertragung zu markieren. So macht man es richtig: https://forum.arduino.cc/index.php?topic=659446.msg4443056#msg4443056
Und dann nur Auswerten wenn der String auch ganz da ist.
Und nicht von der while-Schleife verwirren lassen. i.d.R. wird da bei Serial nur ein Zeichen gelesen. Man muss die Funktion ständig aufrufen bis sie meldet dass sie fertig ist
in einen Array zu Speichern und ein Schlüsselwort darin zu suchen
Ich verstehe, was du erreichen möchtest.
Nennt sich in anderen Sprachen auch mal "assoziative Arrays".
Ist allerdings recht Rechen- und Speicherintensiv.
Auch C++ kann sowas.
Die, 32Bit und mehr, Arduinos haben auch die benötigten Libs dabei.
Die AVR Arduinos nicht.
dass ich die Nachricht mit dem Kennwort = "Kevin" schon separiert habe. Ich versuche nun die Nachricht ("456")
Wenn dein PC Programm das Wort "Kevin" kennt.
Und dein Arduino das Wort "Kevin" kennt.
Dann könnte man eine Vereinbarung treffen und statt "Kevin" eine 1 senden.
Oder statt "Hannelore" eine 2.
Das lässt sich schneller übertragen und einfacher auswerten.
enum Person {Kevin=1,Hannelore=2};
Diese Aufzählung benötigt kein Ram.
Für die Übertagung sollte man sich etwas Mühe mit dem Protokoll und dem Datenformat machen.
Da sehe ich noch gar keine Beschreibung von dir.
Vorschlag
Eine einfache Variante: CSV
z.B. nach dem Muster: Person,Wert;
Alle Feldelemente mit "," separieren und Kommando mit ";" abschließen.
Das Kommando
1,456;
bedeutet dann
Kevin,456;
Das lässt sich recht fix auswerten, z.B. mit strtok() und atoi()
deine Lösung ist viel Eleganter. Ich habe mir den Link angeschaut und da benutzt du readline(Serial), das habe ich so noch nie gesehen. Ist das denn auch non-blocking? soweit ich weiß ist nur .read(), available() und .peek() non-blocking. Das ist ganz wichtig damit die Serielle Kommunikation zwischen Processing und Arduino funktioniert.
Ja genau so hatte ich das vor Combie!
ich habe nur zur demonstration Kevin geschrieben, ich hatte nämlich vor eine 1 bis zwei stellige Zahl als Kennwort zu nehmen um verschiedene Befehle von Processing auswerten zu können. Ich habe kurz gesagt damit vor Informationen wie z.B. das verändern von Einstellungen in meinem Code mit Processing Graphisch darzustellen und jede Einstellung hat dann sein Eigenes Kennwort kn Form einer Zahl von 01-99 (weiß noch nicht wie viele es werden).
Ja, Ich habe mir den Code noch etwas genauer angeschaut und bemerkt dass du da ja auch Serial.read() benutzt. Und habe ich dich dabei richtig verstanden dass du sagst dass man das auf diese Weise viel schneller einliest und so eine Verzögerung minimiert?
Du hast übrigens vollkommen recht dass man am Ende der Nachricht noch ein Schluss befehl setzen muss, diesen Szenario hatte ich noch gar nicht bedacht. Ich habe mir überlegt dass man das doch mit dem selben trick wie ich das Kennwort erkannt habe auch ein Endwort suchen kann und dann an dieser stelle einen Terminator setze um nur meine gewünschte Nachricht zu übertragen und falls Mist am Anfang und Ende der Nachricht steht zu Filtern.
Vielen dank bis hier schon mal!!
GG
Edit:
Ich habe gerade strtok() ausprobiert und die funktion ist ja mega klasse! Damit ist das Start und Endzeichen das selbe also sieht das dann so aus:
Du kannst im Seriellen Monitor einstellen dass am Ende automatisch ein CR, ein LF oder CR + LF gesendet wird. Und wenn man in anderen Programmen println()/WriteLine() u.ä. macht wird auch entsprechend eines der Zeichen oder beide gesendet.
Dann macht man einfach das:
if (c == '\n')
Und man hat das Ende. Einfacher geht es nicht
Deshalb steht da weiter unten auch "else if (c >= 32". Dadurch wird ein eventuell vorhandenes CR ignoriert
Ich wollte mich nochmal melden da ich dies bezüglich noch was zu fragen habe, und keinen neuen Thread starten wollte.
Es geht mir nicht um das Konvertieren sondern habe ich eine Frage, da mein Code bei der Ausgabe von bestimmten Zahlen nicht richtig Funktioniert.
Ich versuche über den Seriellen Monitor mittels analogWrite() die Helligkeit einer LED zu dimmen.
Ich habe verschiedene Zahlen getestet und mir ist aufgefallen dass bei den Zahlen 10-19, 100-200 ein seltsames verhalten auftritt. Z.B werden wenn ich 10 eingebe nur Nullen ausgegeben, oder bei 15 nur die 5. Bei zahlen mit 100 z.B. 150 wird nur 50 ausgegeben und bei 115 nur die 5. Bei 200 ist das selbe selbe zu beobachten.
Sprich alle Zahlen mit einer 1 darin werden Fehlerhaft ausgegeben alle anderen Zahlen werden Problemlos Richtig dargestellt. Woran liegt das? Was könnte ich falsch gemacht haben?
Ich habe auch den Code für ein anderes Einlesen benutzt der hier im Thread steht, ich meine die Funktion readLine(). Genau die selben ausgaben. Bedeutet dass es der Fehler in meiner Array Verarbeitung liegen muss, aber dass sind doch nur 3 Zeilen?
Ich wäre sehr dankbar wenn sich jemand meinen Code mal anschauen würde!\
int val; // Data received from the rawDataerial port
int ledPin = 3;
char rawData[60];
char keyword[] = "led"; //Schlüsselwort muss am Anfang und am Ende des Befehls stehen.
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
int availableBytes = Serial.available(); //Anzahl der Eingegebenen Zeichen
for(int i; i<availableBytes; i++){
rawData[i] = Serial.read();
rawData[i+1] = NULL;
}
char *token = strtok(rawData, keyword);
int value = atoi(token);
if (value >0) {
analogWrite(ledPin, value); // turn the LED on
Serial.println(token);
} else {
digitalWrite(ledPin, LOW);
}
delay(100);
}
Es kommt ein Zeichen an. Das nächste Zeichen kommt erst eine Millisekunde später. Dann tust du aber so als ob gleich der ganze String da wäre
strtok() ist wie gesagt falsch verwendet. Das zerlegt einen String in Teil-Strings entlang eines Trennzeichens. z.B. Werte durch Komma oder Strichpunkt getrennt. Der Delimiter-String kann mehrere Trennzeichen auf einmal angeben
Das mit dem Endzeichen hast du nicht verstanden. Es ist wirklich nur ein Zeichen gemeint. Kein String. Mein Code läuft. Du musst den seriellen Monitor nur so einstellen, dass am Ende automatisch ein Linefeed gesendet wird.
Die Funktion schaut immer nach ob Daten da sind. Wenn nicht kehrt sie sofort wieder zurück. Wenn ja wird ein Zeichen ausgelesen und überprüft ob es das Endzeichen ist. Je nachdem was es ist wird es ignoriert oder abgespeichert. Oder wenn das Endzeichen da ist wird der String terminiert und die Funktion meldet dass sie fertig ist
Auch das mit deinen delimiters der strtok() Funktion, ist irgendwie seltsam.
Ist zwar zulässig, aber bei dir werden die Zeichen 'd' 'e' 'l' als Trennzeichen angesehen und das was dazwischen ist, an atoi() übergeben. Das kann leer "" oder gar nichts (nullptr) oder auch sonst ein Text sein. Nur warum bei dir die '1' anders behandelt wird als andere Ziffern, "ist irgendwie seltsam".
Ich würde einfachere Trennzeichen und ein eindeutiges Endezeichen mögen.
Und vor allem erst mit dem Auswerten anfangen, wenn eine komplette Eingabe da ist. (Da hilft das Endezeichen, am einfachsten ein Newline '\n' )
Serenifly:
Mein Code läuft. Du musst den seriellen Monitor nur so einstellen, dass am Ende automatisch ein Linefeed gesendet wird.
Serenifly, du missachtest aber dass ich versuche mit Processing ( also mit Java) eine Kommunikation zwischen meinem Computer und meinem Arduino aufzubauen. Also wenn du mir sagst dass dein Code funktioniert wenn ich im Seriellen Monitor ne Einstellung verändere ist das zum testen ok wird dann aber doch nicht für mein Processing Code funktionieren. Falls nicht bekannt sein sollte was Processing ist dann erkläre ich das, weil ich schon von Anfang an das erwähnt hatte.
Danke an alle für die Richtigstellung, dass ich strtok() falsch verwende, meint ihr dann also ich sollte mit strstr() weiter arbeiten und manuell in meiner Nachricht die ich sende ein Terminator (\n) einfügen?
Dann sende in Processing CR + LF. Ich nehme mal mit println(). Das CR wird ignoriert und das LF ausgewertet. Das ist auch nichts anderes.
Man kann auch in Strings ein LF manuell anhängen, aber meistens ist das nicht nötig.
Abgesehen davon heißt es am Anfang:
Mein Plan ist es eine Nachricht über den Seriellen Monitor einzugeben
Auch wenn es nicht das Endziel ist, ist das zum Test immer eine gute Idee bevor man noch ein anderes Programm als Fehlerquelle ins Spiel bringt
Serenifly, könntest du mir erklären wofür CR und LF steht? Du hast das schon paar mal erwähnt aber vertsnaden habe ich es noch nicht.
Danke combie, mit der Lib CmdMessenger, scheint das auslesen ziemlich einfach zu sein. müsste ich mal ausprobieren ob das so in meinem Projekt funktioniert.
Der Grund warum ich ein keyword habe ist der dass ich nicht nur zur einen Sache evtl. die Parameter verändern möchte. Ich habe nur zu demonstrations Zwecken als Keyword "led" benutzt, ich hätte gegen Ende das dann auch zur einer Zahl geändert und das alles etwas zu beschleunigen.
Ich wollte ein neues Problem melden, denn warum auch immer lässt sich mein Arduino gerade nicht Programmieren. Beim Hochladen eines neuen Sketches staht nur "Hochlade..." und wird nicht beendet. am Arduino leuchtet nur eine Rote LED und das sketch das vorher drauf war führt er auch nicht mehr aus. Ich habe am BreadBoard nur eine LED an pin 3. Den Com port habe ich schon gewechselt. Ist mein Nano jetzt schrott?
Windows PC ? medet sich das Teil noch am PC an wenn Du den USB reinsteckst. Akustischen "signal"
wiso com Port gewechselt ? wieviele sind denn da auswälbar ?
Ja Windows, Ja es gibt ein akustisches Signal - also wird er erkannt. Ich Habe es nur an einem anderen USP-Port angeschlossen, Es gibt aber nur einen zum auswählen. Bei einem anderen Nano funktioniert das hochladen normal. Es leuchtet nur Power und beim hochladen blinkt manchmal ne blaue LED ist vielleicht Rx.
Das ist ganz spontan passiert, habe überhaupt nichts verändert. PC neustart versuche ich jetzt.