ich bin Anfänger in Sachen Arduino und konnte mir dank den vielen Websites schon sehr gut selbst helfen. Bei einem Problem hänge ich jetzt aber deutlich, und irgendwie kapier in in dieser Hinsicht die ganzen Anleitungen nicht.
Ich möchte meinem Arduion beibringen, auf Befehle an der seriellen Schnittstelle zu reagieren (z.B. set LED rot = 128). Folgende Vorgehensweise habe ich mir dazu überlegt:
Solange an der seriellen Schnittstelle Daten anliegen, soll der µC diese Char für Char auslesen und nach Sonderzeichen wie Leerzeichen, Doppelpunkt, Komma und 'ist-gleich' absuchen. Normale Zeichen soll er in ein Stringarray ablegen. Bei jedem dieser Sonderzeichen wird ein neues Element in diesem Array begonnen. Kommt ein '/n' werden die Strings ausgewertet und verarbeitet.
Das ganze ist im Moment sehr experimentell implementiert. Hier die relevanten Codeausschnitte:
CPCH.cpp: In function 'void loop()':
CPCH:92: error: invalid conversion from 'int' to 'const char*'
CPCH:92: error: initializing argument 1 of 'String& String::operator=(const char*)'
Die hierbei bemängelte Zeile ist:
inputString[inputStringIndex] =+ inputChar;
Wie gesagt: ich habe hierzu schon einige Texte gelesen und meine kapiert zu haben, dass sich ein String nicht so einfach als Array ansprechen lässt. Aber irgendwie hats bei weitem noch nicht "klick" gemacht. Kann mir wer unter die Arme greifen?
Dann würde ich ja für jeden einzelnen Buchstaben einen neuen String anlegen, es soll aber für jedes Wort (also wenn ein Leerzeichen da ist) ein neuer String angelegt werden.
Denn damit hast Du noch kein Array (wie das z.B. in PHP der Fall wäre). In C musst Du bei solchen Konstruktionen immer Speicher reservieren oder bei Klassen ein Objekt instantiieren.
Probier mal folgendes:
Die Stringklasse selbst sorgt dann bei den einzelnen Strings für die Speicherverwaltung. Testen kann ich das zur Zeit leider nicht, daher ist der code ohne Gewähr
Genau das ist der Grund, daß der Code Variablen im Speicher überschreibt und Du nicht weißt wieso das Programm nicht funktioniert.
In C gibt es keine Strings, das sind Arrays von char. Wie bereits geschrieben muß für die Umwandlung der string mit null abgeschlossen sein.
Grüße Uwe
Strings gibt es schon, dafür ist ja die Stringklasse da, aber ein wenig Initialisierung muss schon sein. Folgender Code ist getestet und funktioniert
char inputChar = 0;
int inputStringIndex = 0;
//array für 10 Strings reservieren
String inputString[10];
void setup() {
Serial.begin(9600);
//Array Initialisieren
for(int i=0;i<10;i++) {
inputString[i] = String("");
}
Serial.println("starting");
}
void loop() {
while (Serial.available()) //solange serielle Daten vorhanden sind
{
//wenn maximaler index erreicht, dann alles löschen und von 0 anfangen
if(inputStringIndex == 10) {
inputStringIndex =0;
for(int i=0;i<10;i++) {
inputString[i] = String("");
}
}
inputChar = (char)Serial.read(); //nächstes Byte einlesen
switch (inputChar) //und auf Sonderzeichen prüfen
{
//leerzeichen als trenner
case ' ': {inputStringIndex++;} break;
//eine ";" als zeilenende erkennen.
case ';': {inputStringIndex++;showStrings();} break;
default: //wenn kein Sonderzeichen
{
inputString[inputStringIndex].concat(inputChar);
} break;
}
}
}
//Strings ausgeben
void showStrings() {
for(int i=0;i<10;i++) {
Serial.print(i);
Serial.print(": ");
Serial.println(inputString[i]);
}
}
Was nicht funktioniert ist "inputString[inputStringIndex] +=inputChar;". Hier addiert der Compiler wohl den char zum Zeiger auf den String dazu.
Daher der "sicherere" Methodenaufruf: "inputString[inputStringIndex].concat(inputChar);"
Eine Eingabe von "set led1 255" wird nun wie gewünscht in eine "Liste" von String gewandelt.
Die Stringklasse kümmert sich bereits um die Null-Terminierung des Strings und abstrahiert recht gut das Rechnen mit den char* Zeigern und der ganze Speicherverwaltung.
Trotzdem ist es nie verkehrt zu schauen wo der Speicher für irgendwelche Daten her kommt. Gerade wenn Daten mit variabler Länge eingelesen werden, kann der Compiler nicht vorher sehen wieviele Daten kommen.
Grüße,
Mario.
danke, durch den sicheren Methodenaufruf funktioniert das ganze nun.
Zwei kleinere Rückfragen noch:
1.) kann es sein, dass über das Terminal kein '/n' als Zeilenabschluss geschickt wird?
2.) Betreffs:
Trotzdem ist es nie verkehrt zu schauen wo der Speicher für irgendwelche Daten her kommt. Gerade wenn Daten mit variabler Länge eingelesen werden, kann der Compiler nicht vorher sehen wieviele Daten kommen.
Kann ich nicht nur einfach den Speicher für 10 Strings resiervieren, sondern auch für 10 Strings á 11 Zeichen?
Kann ich nicht nur einfach den Speicher für 10 Strings reservieren, sondern auch für 10 Strings á 11 Zeichen?
Ja kannst Du, ist aber Speicherverschwendung und davon hat der Arduino nicht so üppig.. Abgesehen davon ist es wurscht, was Du bei der Stringklasse am Anfang "reservierst", der Speicher für den Stringpuffer wird ja trotzdem dynamisch verwaltet. Spätestens beim Zuweisen eines kleineren Strings ist der Speicher wieder weg. Negativ könnte sich dann aber eine "Fragmentierung" des Speichers auswirken.
Beispiel:
10x11 Zeichen werden reserviert. Da das auf einen Schlag passiert, ist es sehr wahrscheinlich, das die 110 Bytes direkt hintereinander im Speicher liegen.
Nun wird dem ersten String ein neuer Wert mit 5 Zeichen zugewiesen (+\0 am Ende) werden 5 Bytes freigegeben. Die liegen nun aber als 5 Bytes freier Speicher zwischen dem 1. und dem 2. String. Kommt nun ein malloc(x) mit x>5, können die 5 Bytes nicht genutzt werden und der Speicher ist zwar nicht belegt, kann aber trotzdem nicht gut genutzt werden.
Keine Ahnung wie gut die Speicherverwaltung der eingesetzten Lib ist, aber Zaubern kann die sicher auch nicht.
Vielen Dank Joghurt
Genau, möge der Saft mit Dir sein, Lonestar
(sorry da konnte ich nicht wiederstehen)
Ist ja auch wieder vorreservieren von Speicher. Als Puffer zum ständigen Lesen und dann per strcpy() einen neuen String speichern, OK
Dann aber lieber als deutlich erkennbaren Puffer:
#define BUFFERSIZE 17
char puffer[BUFFERSIZE];
Der Code ist, bis auf die Fehlende Belegung des Puffers, identisch, man sieht aber gleich, wieviele Zeichen man zur Verfügung hat.
Wer sicher sein will, kann vorher den Puffer noch "nullen"
for(int i=0;i<BUFFERSIZE;i++) puffer[i]=0;
Durch verwenden der Konstanten "BUFFERSIZE" die man überall im Code verwenden kann, kann man sehr einfach die Größe des Puffers durch Ändern eines einzigen Wertes anpassen.
Es sollen aber mehrere Strings gelesen werden, von denen erst zur Laufzeit beim Lesen bekannt ist, wie lang die sind. Daher müssen dann sowieso von den seriell gelesenen Strings Kopien erzeugt werden, damit der Puffer wieder frei wird für den nächsten zu lesenden String.
Wie gesagt, die Stringklasse behandelt das schon sehr effizient und man muss sich um die Rechnerrei mit dem Speicher keinen Kopf machen.