Forum: Mikrocontroller und Digitale Elektronik Arduino: if(String == "ein") funktioniert nicht


von Etitie (Gast)


Lesenswert?

Hier ist mein Code, welcher leider nicht funktioniert. Wo ist aber der 
Fehler?
1
String befehl;
2
3
void setup() {
4
  Serial.begin(9600);
5
  pinMode(LED_BUILTIN, OUTPUT);
6
}
7
8
void loop() {
9
  if(Serial.available()){
10
    befehl = Serial.readString();
11
    if(befehl == "ein"){
12
      digitalWrite(LED_BUILTIN, HIGH);
13
      Serial.println("ein");
14
    }else if(befehl == "aus"){
15
      digitalWrite(LED_BUILTIN, LOW);
16
      Serial.println("aus");
17
    }
18
  }
19
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Etitie schrieb:
> Hier ist mein Code, welcher leider nicht funktioniert.
Was erwartest du und was tut sich stattdessen?

> Wo ist aber der Fehler?
Welche Fehlermeldung bekommst du denn wofür?

Beitrag #6383047 wurde vom Autor gelöscht.
von MaWin (Gast)


Lesenswert?

Etitie schrieb:
> leider nicht funktioniert. Wo ist aber der Fehler?

Grundlagen von C(++).

if(befehl == "ein" fragt, ob die Speicheradresse des ersten Zeichens in 
befehl identisch mit der Speicheradresse des ersten Zeichens des 
konstanten Strings "ein" ist. Natürlich niemals.
Du brauchst eine Funktion wie strcmp oder befehl.compare

von Ben S. (bensch123)


Lesenswert?

MaWin schrieb:
> Du brauchst eine Funktion wie strcmp oder befehl.compare

Ich vermute mal, dass das ein C++ String ist und seit wann muss ich bei 
C++-Strings strncmp verwenden?

: Bearbeitet durch User
von Drago S. (mratix)


Lesenswert?

if, else if, else

von Etitie (Gast)


Lesenswert?

Lothar M. schrieb:
> Was erwartest du und was tut sich stattdessen?

Wenn ich "ein" eingebe, passiert garnichts.

Lothar M. schrieb:
> Welche Fehlermeldung bekommst du denn wofür?

Keine.

MaWin schrieb:
> Grundlagen von C(++).
>
> if(befehl == "ein" fragt, ob die Speicheradresse des ersten Zeichens in
> befehl identisch mit der Speicheradresse des ersten Zeichens des
> konstanten Strings "ein" ist. Natürlich niemals.
> Du brauchst eine Funktion wie strcmp oder befehl.compare

Ich glaube Arduino ist einwenig anders als reines C++ und C. Das geht 
das schon.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

MaWin schrieb:
> if(befehl == "ein" fragt, ob die Speicheradresse des ersten Zeichens in
> befehl identisch mit der Speicheradresse des ersten Zeichens des
> konstanten Strings "ein" ist.
Man könnte aber den "==" Operator so überladen, dass er so einen 
Stringvergleich auch tatsächlich beherrscht. Oder wie war das mit dem ++ 
in C++? In VHDL mache ich sowas auf jeden Fall ständig...  ;-)

von Thomas R. (r3tr0)


Lesenswert?

Probier mal die strcmp funktion aus.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Etitie schrieb:
> Ich glaube Arduino ist einwenig anders als reines C++ und C.
Nicht so sehr, wie du es dir erträumst.
> Das geht das schon.
Ja, offenbar doch eher nicht. Oder wie jetzt?

Du musst also nachsehen, ob in der Stringklasse der Vergleich auf "==" 
tatsächlich so implementiert ist, wie du es willst. So wie ich das sehe 
ist das nämlich eine recht stupide Klasse:
https://www.arduino.cc/reference/de/language/variables/data-types/stringobject/
Von Vergleichsoperatoren ist da keine Rede....

: Bearbeitet durch Moderator
von Ben S. (bensch123)


Lesenswert?

Lothar M. schrieb:
> So wie ich das sehe
> ist das nämlich eine recht stupide Klasse:

So wie ich das sehe, sollte das funktionieren:
https://www.arduino.cc/reference/de/language/variables/data-types/string/operators/comparison/

Ich denke eher, dass bei diesem mystischen und geheimen Code der Fehler 
an anderer Stelle liegt.

von Εrnst B. (ernst)


Lesenswert?

Ben S. schrieb:
> Ich denke eher, dass bei diesem mystischen und geheimen Code der Fehler
> an anderer Stelle liegt.

Der Fehler liegt eher an der anderen Seite der seriellen Leitung. Er 
muss ja ein "ein" ohne "\n" o.Ä. danach senden. Das können die meisten 
Seriellen Terminalprogramme nicht, die warten auf die Enter-Taste.

Ich würde ein "befehl.trim()" nach dem readString empfehlen.

: Bearbeitet durch User
von Ulf L. (ulf_l)


Lesenswert?

Hallo

Serial.avalable() geht schon beim ersten Zeichen in die if-Schleife. 
Dann liest Du schon den ser Buffer aus. Im ungünstigsten Fall steht da 
jetzt nur ein "e" drin. Das entspricht natürlich nicht dem "ein".

Lass die doch die Variable befehl einfach mal direkt nach dem befehl = 
Serial.readString(); auf dem Monitor ausgeben.

Gruß Ulf

von Geschafft (Gast)


Lesenswert?

1
[+] if(befehl == "ein"){
2
[+] }else if(befehl == "aus"){
3
    } else {
4
      Serial.println(befehl);
5
    }

Dann erkennst du was dein System rein bekommt...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Geschafft schrieb:
> Dann erkennst du was dein System rein bekommt...
Abzüglich irgendwelcher Steuerzeichen, die nicht übertragen werden.

Ulf L. schrieb:
> Serial.avalable() geht schon beim ersten Zeichen in die if-Schleife.
> Dann liest Du schon den ser Buffer aus. Im ungünstigsten Fall steht da
> jetzt nur ein "e" drin.
Aber Serial.readString() wartet danach noch hardcoremäßig irgendein 
Timeout ab:
https://www.arduino.cc/reference/de/language/functions/communication/serial/readstring/

> Lass die doch die Variable befehl einfach mal direkt nach dem befehl =
> Serial.readString(); auf dem Monitor ausgeben.
Ja, so ein richtiger Debugger ist schon echtes Gold wert. Und dessen 
Fehlen auch der Grund, warum ich diese Andruiden so ungern benutze. Da 
artet das Debuggen immer gleich in eine Ratestunde aus und man muss mit 
dem LA parallel nachmessen, was sich auf der Schnittstelle tut usw...

Εrnst B. schrieb:
> Er muss ja ein "ein" ohne "\n" o.Ä. danach senden. Das können die
> meisten Seriellen Terminalprogramme nicht, die warten auf die
> Enter-Taste.
Mit dem "Seriellen Monitor" in der Andruiden-IDE kann man das auswählen:
https://learn.sparkfun.com/tutorials/terminal-basics/arduino-serial-monitor-windows-mac-linux

Ich nehme aber gern das alte OCConsole Terminal, das sendet einfach 
jedes Zeichen genau dann, wenn ich es tippe...  ;-)

: Bearbeitet durch Moderator
von Georg M. (g_m)


Lesenswert?

Etitie schrieb:
> leider nicht funktioniert

Bei anderen funktioniert:

https://youtu.be/MAnAc_t0OrM?t=1660

von Etitie (Gast)


Angehängte Dateien:

Lesenswert?

Ulf L. schrieb:
> Lass die doch die Variable befehl einfach mal direkt nach dem befehl =
> Serial.readString(); auf dem Monitor ausgeben.

Dann wird "ein" ausgegeben. Es wird immer das ausgegeben, was eingegeben 
wurde. Mich wunderts nur, dass eine Neue Zeile dazwischen eingefügt 
wird.

von Thomas R. (r3tr0)


Lesenswert?

wegen dem \n Terminator?

von Εrnst B. (ernst)


Lesenswert?

Etitie schrieb:
> Mich wunderts nur, dass eine Neue Zeile dazwischen eingefügt
> wird.

Eben. Mach statt dem println(befehl) ein
print("["); print(befehl); println("]");

dann siehst du, dass nicht nur "[ein]" sondern
"[ein
]"
rauskommt.

deshalb: befehl.trim().

von Etitie (Gast)


Lesenswert?

Εrnst B. schrieb:
> deshalb: befehl.trim().

Jetzt funktionierts!!!
Danke!

von Frank (Gast)


Lesenswert?

Εrnst B. schrieb:
> deshalb: befehl.trim().

Viel zu kompliziert.

Einfach das "\n" anhängen:

if(befehl == "ein\n"){

}else if(befehl == "aus\n"){

und schon läufts.

von EGS (Gast)


Lesenswert?

Sein Problem ist auch das es in der Arduino IDE einen definierten 
String-Vergleich gibt: equalsIgnoreCase()

myString.equalsIgnoreCase(myString2)

Ohne GS/KS und: equals()

myString.equals(myString2)

mit GS/KS.

Wenn er diese Funktionen verwenden würde, wäre auch ein richtiges true 
oder false für seine if/else Vergleiche vorhanden.

Vielleicht sollte der TO mal hier lesen:

https://www.arduino.cc/en/Tutorial/BuiltInExamples#strings

Mit freundlichen Grüßen EGS

von Drago S. (mratix)


Lesenswert?

Ich verstehe nicht warum Serial.readString(); die Steuerzeichen bekommt.
Das Terminal sendet die Eingabe erst nach (einem klick auf) send.
Anders wäre es, wenn jedes Zeichen einzeln live eingelesen würde.

Oder ist das ein Bug in der Arduino IDE?

von Stefan F. (Gast)


Lesenswert?

Mister A. schrieb:
> Ich verstehe nicht warum Serial.readString(); die Steuerzeichen bekommt.
> Das Terminal sendet die Eingabe erst nach (einem klick auf) send.

Das Terminal sendet den String mit Sicherheit einschließlich einem 
abschließenden Zeilenumbruch. Bei den meisten Terminalprogrammen kann 
man einstellen ob und womit die Zeilen abgeschlossen werden sollen.

von Hartmut Semken (Gast)


Lesenswert?

Schön, dass man Dir helfen konnte.

Hier die Anleitung zur Selbsthilfe, wenn sowas wieder auftritt:
Ich hätte auch geraten, die Eingabe im Sketch erstmal probehalber 
auszugeben.
Das print("["); print(befehl); println("]"); geht auch - nunja, - ich 
hätte in einer for-Schleife die Länge des Eingabestrings und die 
Ascii-Codes jedes enthaltenen Zeiches ausgegeben.
Dann sieht man gseht genau, was eigentlich passiert.

hase

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Frank schrieb:
> Viel zu kompliziert.
> Einfach das "\n" anhängen:
> if(befehl == "ein\n"){
> }else if(befehl == "aus\n"){
> und schon läufts.

Wenn Du Pech hast, kommt da aber "ein\r" oder "ein\r\n" zurück. Man 
sollte da schon so flexibel sein, dass man beliebige Whitespaces 
abschneidet. Dafür bietet sich trim() in einfachster Form an. Oder man 
schreibt etwas eigenes, denn trim() hat die Unart, auch "echte Spaces" 
(Leerzeichen) abzuschneiden, was unter Umständen auch unerwünscht sein 
kann.

: Bearbeitet durch Moderator
von Schlaumaier (Gast)


Lesenswert?

Sein Problem ist das er bisher auf Systeme programmiert hat, die 
Speicher satt haben.

"Ein" und "aus" als String in einen Arduino das ist gruselig.

Das macht man via True / False als Boolean.

Der Grund ist einfach. Du verbrauchst wertvollen Speicherplatz.

Wenn ich meine VB-Programme entwickele mache ich es manchmal genauso. 
Aber da sind mir 10 KB Programmcode/Variablenspeicher völlig egal. Da 
geht es um die Übersicht und die Möglichkeit spätere Änderungen zu 
machen ohne das Prg. neu zu schreiben.

In einen Arduino ist Speicher Mangelware. Da solltest du von Anfang an 
lernen das so was Unsinn ist.

Davon abgesehen ist, wie du gelernt hast, Stringverarbeitung im Arduino 
nicht gerade angenehm.

Außer das ich Daten erstelle muss (für eine SD-Karte) kenne ich keine 
Anwendung die Strings braucht.  Ausgaben an ein Display gehen auch ohne. 
Einfach den String als Text senden und gut ist. Deshalb kann man bei 
alles Displays die ich kenne die Position genau bestimmen. Wenn man den 
Text mit Leerzeichen auffüllt, wird auch ein möglicher alter Überhang 
gelöscht. ;)

Kleiner Tipp. Schau mal beim Compilieren / Erstellen des Codes unten 
hin. Dann siehst du was du an Speicher von wie viel Speicher 
verbrauchst. Und 2 -3 Libs dazu und schon hast du ein großes Problem und 
fragst wie man Libs "Kürzen" kann ;)

von Joachim B. (jar)


Lesenswert?

Schlaumaier schrieb:
> "Ein" und "aus" als String in einen Arduino das ist gruselig.

nö, man muss es nur richtig machen
1
void inSTR_Auswertung(void) {
2
  if(strlen(serial_in_command)) { 
3
    Serial.println(); Serial.print(serial_in_command);  Serial.println(F(" -> erkannt ")); 
4
    if( !strcmp(serial_in_command, "help") || ( !strcmp(serial_in_command, "?") && strlen(serial_in_command)==1 ) ) { // help screen
5
      Serial.println();
6
      Serial.println(F("commands:"));
7
      Serial.println(F("hell, hellp, +, hellm, -, hellxx("XSTR(MIN_BL)"-"XSTR(MAX_BL)")"));
8
      Serial.println(F("con, conp, *, conm, /, conxx("XSTR(MIN_KONTRAST)"-"XSTR(MAX_KONTRAST)")"));
9
      Serial.println(F("bias, biasp, biasm, biasx("XSTR(MIN_BIAS)"-"XSTR(MAX_BIAS)")"));
10
      Serial.println(F("date, dateJJJJ/MO/TA"));
11
      Serial.println(F("time, timeHH:MM:SS"));
12
      Serial.println(F("reset"));
13
      Serial.println();
14
    } // if( !strcmp(serial_in_command, "help") || ( !strcmp(serial_in_command, "?") && strlen(serial_in_command)==1 ) )
15
16
    else if( strstr(serial_in_command, "hell") || !strcmp(serial_in_command, "+") || !strcmp(serial_in_command, "-") ) {
17
      if( strlen(serial_in_command)==4 ) {
18
        Serial.print(F("hell=")); Serial.println(backlicht);
19
      }
20
21
//....usw. bis
22
  } // if(strlen(serial_in_command))
23
  memset((char*)&serial_in_command[0], 0, sizeof(serial_in_command));
24
  stringComplete = false;
25
} // void inSTR_Auswertung(void)

ist noch etwas gemischt klappt aber seit Jahren auch auf dem nano

: Bearbeitet durch User
von Georg M. (g_m)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Bei den meisten Terminalprogrammen kann
> man einstellen ob und womit die Zeilen abgeschlossen werden sollen.

von Joachim B. (jar)


Lesenswert?

aber das Ende sollte schon erkannt werden
if(incomingByte == 13) oder if(incomingByte == '/r')

nur kommt das i.d.R. nicht in den "String" also
manuell die 0 einsetzen zur Weiterverarbeitung
1
while (Serial.available()) {
2
    char incomingByte = (char)Serial.read();
3
    if(incomingByte == 13) { // Wenn das Enter ankommt
4
      chr_cnt++;
5
      serial_in_buff[chr_cnt] = '\0';
6
      strcpy(serial_in_command, serial_in_buff);
7
      memset(&serial_in_buff[0], 0, sizeof(serial_in_buff));
8
      chr_cnt = 0;
9
      stringComplete = true;
10
      Serial.println(serial_in_command);
11
    } //if(incomingByte == 13)
12
    else { // Falls kein Enter kommt muss der Text gespeichert werden in dem inText Array
13
      if(isprint(incomingByte)) {
14
        if(chr_cnt<(MAXBUFFER-2))
15
          serial_in_buff[chr_cnt++] = incomingByte;
16
        else {
17
          Serial.println(F("serBUF ov-> DEL"));
18
          memset(&serial_in_buff[0], 0, sizeof(serial_in_buff));
19
          memset(&serial_in_command[0], 0, sizeof(serial_in_command));
20
          chr_cnt=0;
21
        } // if !(chr_cnt<(MAXBUFFER-2))
22
      } // if(isprint(incomingByte))
23
    } // if !(incomingByte == 13)
24
  } // while (Serial.available())

Beitrag #6383637 wurde vom Autor gelöscht.
von Joachim B. (jar)


Lesenswert?

Karl K. schrieb im Beitrag #6383637:
> Und dann werden die ganzen Strings noch im RAM
> vorgehalten, statt sie aus dem Flash zu holen.

wo denn?
der der eingelesen wird muss ins RAM

der mit dem verglichen wird ist im flash

falls noch einer kommt:
OK du vermisst wohl:
else if( strstr_P(serial_in_command, PSTR("hell")) )

keine Sorge, ist drin, habe nur ein altes Beispiel gezeigt, der TO darf 
auch noch lernen

: Bearbeitet durch User
von Frank (Gast)


Lesenswert?

Schlaumaier schrieb:
> In einen Arduino ist Speicher Mangelware.

Noch nie einen Arduino in der Hand gehabt?
Die gibts mittlerweile mit richtig viel Speicher; da kommts auf einige 
100kB nicht mehr an...

von Joachim B. (jar)


Lesenswert?

Frank schrieb:
> Noch nie einen Arduino in der Hand gehabt?
> Die gibts mittlerweile mit richtig viel Speicher; da kommts auf einige
> 100kB nicht mehr an...

zu dem bemängeltem Code war vom ESP der 512k SRAM hat
deswegen fehlte auch strcmp_P und PSTR()

von mh (Gast)


Lesenswert?

Joachim B. schrieb:
>         } // if !(chr_cnt<(MAXBUFFER-2))
>       } // if(isprint(incomingByte))
>     } // if !(incomingByte == 13)
>   } // while (Serial.available())

Wenn man Kommentare dieser Art braucht, um nicht den Überblick zu 
verlieren, sollte man die Verschachtelung verringern.

Joachim B. schrieb:
> if(incomingByte == 13) { // Wenn das Enter ankommt

Warum die 13 und nicht '\r'? Du ja auch '\0' statt 0. Bei der 
Gelegenheit kannst du dann auch den fehlerhaften Kommentar in der Zeile 
löschen.

von Stefan F. (Gast)


Lesenswert?

Joachim B. schrieb:
> else if( strstr_P(serial_in_command, PSTR("hell")) )
>
> keine Sorge, ist drin, habe nur ein altes Beispiel gezeigt, der TO darf
> auch noch lernen

Bei so kurzen Strings spart man womöglich nicht einmal was, weil der 
Zugriff auf den Flash aufwändiger ist, als RAM.

von Joachim B. (jar)


Lesenswert?

mh schrieb:
> Warum die 13 und nicht '\r'?

nicht gelesen?
ist alter Code im Schnellzugriff, ich lerne auch immer dazu

Joachim B. schrieb:
> aber das Ende sollte schon erkannt werden
> if(incomingByte == 13) oder if(incomingByte == '/r')

Stefan ⛄ F. schrieb:
> Bei so kurzen Strings spart man womöglich nicht einmal was, weil der
> Zugriff auf den Flash aufwändiger ist, als RAM.

auch das ist mir schon aufgefallen, aber trotzdem gab es ja einen 
Kommentar und der wurde gelöscht!

Joachim B. schrieb:
> Karl K. schrieb im Beitrag #6383637:
>> Und dann werden die ganzen Strings noch im RAM
>> vorgehalten, statt sie aus dem Flash zu holen.

aber ich prüfe ja wieviel Byte frei sind und kann entscheiden ob ich aus 
dem flash lese mit strxxx_P PSTR() oder nicht!

von Gerald K. (geku)


Lesenswert?

Etitie schrieb:
> if(befehl == "ein")

Ich würde es mit
1
if (strcmp(befehl,"ein") == 0)
versuchen.

https://www.c-howto.de/tutorial/strings-zeichenketten/string-funktionen/strings-vergleichn/

von Stefan F. (Gast)


Lesenswert?

Etitie schrieb:
> if(befehl == "ein")

Gerald K. schrieb:
> Ich würde es mitif (strcmp(befehl,"ein") == 0)

Möchte noch jemand diesen falschen Hinweis geben?

strcmp() ist für C Zeichenketten vorgesehen, nicht für Arduino Strings, 
das sind C++ Objekte. Die String Klasse hat den Operator == 
überscheieben, so dass Etite sie bereits korrekt angewendet hat.

Der Knackpunkt mit dem Zeilenumbruch wurde bereits geklärt.

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Möchte noch jemand diesen falschen Hinweis geben?

Ach, So ganz falsch ist das ja nicht, denn die Klasse verwendet 
schließlich intern strcmp(), genau für diesen Zweck.
Also Thema korrekt erkannt, aber Kontext nicht verstanden.

> if (strcmp(befehl.c_str(),"ein") == 0)
würde sogar funktionieren.
(wenn nicht das EndlineChar Drama bestehen würde)

von Joachim B. (jar)


Lesenswert?

Stefan ⛄ F. schrieb:
> Möchte noch jemand diesen falschen Hinweis geben?
>
> strcmp() ist für C Zeichenketten vorgesehen,

jaaa
1
      if ((inChar == '\n') || (inChar == '\r')) {
2
        stringComplete = true;
3
        strcpy(serial_in_command, serial_in_buff.c_str());
4
        Serial.print(F("serial_in_command 1. ")); Serial.print(F("Event: ")); Serial.println(serial_in_command);
5
        serial_in_buff="";
6
      } // if ((inChar == '\n') || (inChar == '\r')) {

.c_str()
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/c_str/
https://www.arduino.cc/en/Tutorial/BuiltInExamples#strings

von Stefan F. (Gast)


Lesenswert?

Ich benutze an solchen Stellen das Stream Interface, das auch die Serial 
Klasse unterstützt:
1
#include "Stream.h"
2
3
/**
4
 * Append characters from a stream to the buffer until the terminator has been found.
5
 * In case of buffer overflow, read until the terminator but skip all characters that 
6
 * do not fit into the buffer.
7
 * @param source The source stream.
8
 * @param buffer The target buffer, must be terminated with '\0'.
9
 * @param bufSize Size of the buffer.
10
 * @param terminator The last character that shall be read from the stream, e.g. '\n'.
11
 * @return True if the terminator has been reached, false if the stream did not contain the terminator.
12
 */
13
bool appendUntil(Stream& source, char* buffer, int bufSize, char terminator)
14
{
15
    int data=source.read();
16
    if (data>=0)
17
    {
18
        int len=strlen(buffer);
19
        do
20
        {
21
            if (len<bufSize-1)
22
            {
23
                buffer[len++]=data;
24
            }
25
            if (data==terminator)
26
            {
27
                buffer[len]=0;
28
                return true;
29
            }
30
            data=source.read();
31
        }
32
        while (data>=0);
33
        buffer[len]=0;  
34
    }
35
    return false;
36
}

Innerhalb der Hauptschleife rufe ich wiederholt die Funktion 
appendUntil() mit dem selben Puffer auf. Wenn der erwartete Terminator 
(z.B. '\n') empfangen wurde, liefert die Funktion true zurück. Dann kann 
ich die bis dahin empfangene Zeichenkette verarbeiten.

Der Terminator wird weg geschnitten.

Achtung: Der Puffer muss vor Aufruf der Funktion als Leerstring 
initialisiert werden, als mit \0 beginnen.
1
char buffer[41];
2
3
void loop()
4
{
5
    if (appendUntil(Serial, buffer, sizeof(buffer), '\n'))
6
    {
7
        ... process content of the buffer
8
    }
9
}

von Joachim B. (jar)


Lesenswert?

Stefan ⛄ F. schrieb:
> Achtung: Der Puffer

sollte optimal auch min 2 Byte größer sein um evtl. '/r' & '/n' 
aufzunehmen
und gleichzeitig der Pufferüberlauf verhindert werden, wer weiss was so 
alles kommen könnte!
Manchmal kommt auch Müll bei "Empfangsstörungen"

Die meiste Arbeit ist immer Fehler abzufangen.

dazu gehört auch das Zeichen auf isprint() zu prüfen

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Achtung: Der Puffer muss vor Aufruf der Funktion als Leerstring
> initialisiert werden, also mit \0 beginnen.

Wobei das im obigen Fall automatisch passiert, weil buffer eine globale 
Variable ist. Nach der Verarbeitung leert man ihn dann mit buffer[0]=0 
so dass er für die nächste Eingabe bereit ist.

Mit der String Klasse habe ich mir zu oft den Heap fragmentiert, darum 
verwende ich lieber eine offensichtlichere Speicherverwaltung, wo ich 
sehe, was passiert.

von Stefan F. (Gast)


Lesenswert?

Lothar M. schrieb:
> Du musst also nachsehen, ob in der Stringklasse der Vergleich auf "=="
> tatsächlich so implementiert ist, wie du es willst.

> Von Vergleichsoperatoren ist da keine Rede....

Weil die Doku von Arduino unvollständig ist. Wenn man da wenigstens eine 
ordentliche IDE hätte, die einen das hin und her Springen im 
dokumentierten Quelltext ermöglichen würde, wäre das nur halb so wild. 
Aber das fehlt da ja auch.

Ich benutze die IDE Qt Creator als "Externen Editor".

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Mit der String Klasse habe ich mir zu oft den Heap fragmentiert, darum
> verwende ich lieber eine offensichtlichere Speicherverwaltung, wo ich
> sehe, was passiert.

Der geschickte Einsatz von String::reserve() mildert das Problem.


------------

Lothar M. schrieb:
> Von Vergleichsoperatoren ist da keine Rede....
Hier findet sich das Interface der Klasse:
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/WString.h

Beitrag #6383919 wurde von einem Moderator gelöscht.
von Karl K. (karl2go)


Lesenswert?

Arduino Fanboy D. schrieb:
> Der geschickte Einsatz von String::reserve() mildert das Problem.

Der geschickte Einsatz einer Programmsprache, die Strings in der Länge 
begrenzt, mindert das Problem enorm.

Beim Arduino gibts offenbar nichtmal eine Möglichkeit, die Buffergröße 
für Serial einzustellen.

von S. R. (svenska)


Lesenswert?

Stefan ⛄ F. schrieb:
>> Ich würde es mitif (strcmp(befehl,"ein") == 0)
> Möchte noch jemand diesen falschen Hinweis geben?

Ich werfe folgendes in den Raum:

if (strncmp(befehl.c_str(), "ein", 3) == 0) {...}

Das löst auch das Problem mit nachfolgenden Zeichen (und ja, als 
Schönheitsfehler erkennt es "einander" auch als "ein").

von Stefan F. (Gast)


Lesenswert?

S. R. schrieb:
> Ich werfe folgendes in den Raum:
> if (strncmp(befehl.c_str(), "ein", 3) == 0) {...}

Auch damit wechselst du zwischen C und C++., was unnötige Konvertierung 
erfordert und den eigenen Quelltext schlechter lesbar macht.

Besser wäre in diesem Fall:

if (befehl.indexOf("ein")==0) {...}

Beitrag #6384102 wurde vom Autor gelöscht.
von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Auch damit wechselst du zwischen C und C++.,
Das passiert nur in deinem Kopf.

Stefan ⛄ F. schrieb:
> was unnötige Konvertierung erfordert
Das passiert nur in deinem Kopf.

Stefan ⛄ F. schrieb:
> und den eigenen Quelltext schlechter lesbar macht.
Naja, dem kann ich zustimmen.

Karl K. schrieb:
> Der geschickte Einsatz einer Programmsprache, die Strings in der Länge
> begrenzt, mindert das Problem enorm.
Wenn einem die originale String Klasse nicht passt, baut man sich eine 
eigene, oder verwendet eine, welcher das gewünschte Feature auf dem 
Schirm hat.
z.B. https://www.arduino.cc/reference/en/libraries/safestring/
Schwer vorstellbar, dass du damit überfordert bist.
Auch wird so ganz schnell klar, dass es kein Problem der 
Programmiersprache ist....

Karl K. schrieb:
> Beim Arduino gibts offenbar nichtmal eine Möglichkeit, die Buffergröße
> für Serial einzustellen.
Eine Nebelkerze?
Denn mit dem Eingangsproblem hat das herzlich wenig zu tun.

Vielleicht ist die Einstellung nicht einfach erreichbar...
Aber dass es keine Möglichkeit gibt, ist schlicht falsch!
Schwer vorstellbar, dass du damit überfordert bist, den richtigen Ort zu 
finden, und die Buffergröße nach Wunsch einzustellen.
Aber wenn dem wirklich so sein sollte, kann ich dir den Punkt gerne 
zeigen.

von Joachim B. (jar)


Lesenswert?

Karl K. schrieb:
> Beim Arduino gibts offenbar nichtmal eine Möglichkeit, die Buffergröße
> für Serial einzustellen.

das ist falsch, es ist möglich aber nicht zielführend!

für MICH (wohlgemerkt) war es OK die Buffergröße für Serial zu 
beizubehalten, in meinen Programmen einen eigenen Eingangsbuffer zu 
definieren und etwas Platz zu lassen für CR und LF und zeichenweise 
einzulesen, maximale Größe bestimmte ich nach den erwarteten Befehlen +2 
und wenn ich 2 Byte unter der Länge war und kein CR oder LF kommt den 
Buffer zu verwerfen und auf NULL zu setzen, sonst eben, als Terminator 
wieder 0 am Ende anzuhängen.
Somit ist Weiterverarbeitung mit strxxx problemlos möglich.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Zu dem Code wäre noch anzumerken, dass auch readString() nicht ganz
unproblematisch ist, da diese Funktion – anders als istream::getline()
und std::operator>>(string) aus der Standardbibliothek – als einziges
Kriterium für das String-Ende einen Timeout (Default: 1 s) verwendet.

Sendet man den String mit einem gewöhnlichen Terminalprogramm, muss man
die Zeichen zügig eintippen, um zu vermeiden, dass der Timeout schon vor
dem Ende der Eingabe zuschlägt.

Beim Serial-Monitor der Arduino-IDE hat man dieses Problem nicht, da
dieser immer ganze Zeilen puffert. Aber auch hier muss man nach dem
Abschicken 1 s (oder was immer als Timeout eingestellt wurde) warten,
bis das Programm auf die Eingabe reagiert.

readStringUntil('\n') wäre hier evtl. die bessere Wahl, funktioniert
aber natürlich nur, wenn man im Terminal das Zeilendezeichen passend
eingestellt hat.

von leo (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
>> Von Vergleichsoperatoren ist da keine Rede....
>
> Weil die Doku von Arduino unvollständig ist.

Aber sicher ist das dokumentiert:

"The String comparison operators ==, !=,>, < ,>=, <= , and the equals() 
and equalsIgnoreCase() methods allow you to make alphabetic comparisons 
between Strings. They're useful for sorting and alphabetizing, among 
other things."

https://www.arduino.cc/en/Tutorial/StringComparisonOperators

leo

von Joachim B. (jar)


Lesenswert?

Ich experimentierte auch mit malloc und free was aber den Speicher 
fragmentiert, somit entschied ich mich für konstante kurze Buffer als 
globale Variablen.

Eine Garbage Collection wie beim CBM fand ich nicht!
https://de.wikipedia.org/wiki/Garbage_Collection

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Stefan ⛄ F. schrieb:
> Auch damit wechselst du zwischen C und C++., was unnötige Konvertierung
> erfordert und den eigenen Quelltext schlechter lesbar macht.

Da ein Arduino-String (wie auch std::string) ein ganz gewöhnlicher 
C-String mit ein paar zusätzlichen Methoden ist, findet überhaupt keine 
Konvertierung statt. Und was ich schrieb, sieht zwar wie C aus, ist aber 
C++ - weil C++ (fast) ein Superset von C ist. Ob es besser lesbar oder 
nicht, darüber lässt sich streiten.

Und ja, du hast nach weiteren C-artigen Lösungen gefragt, also habe ich 
eine gegeben (ich widerspreche dir nur, dass es ein "falscher" Hinweis 
ist). :-)

von Johannes S. (Gast)


Lesenswert?

Yalu X. schrieb:
> Sendet man den String mit einem gewöhnlichen Terminalprogramm, muss man
> die Zeichen zügig eintippen, um zu vermeiden, dass der Timeout schon vor
> dem Ende der Eingabe zuschlägt.

der gemeine Arduino User wird auch nicht unbedingt das Verlangen haben, 
andere Terminal/Monitorprogramme zu benutzen. Bei externen Programmen 
muss man nämlich immer erst den Port zumachen bevor ein neues Programm 
geladen werden kann, es wird ja üblicherweise die selbe serielle 
Schnittstelle benutzt.
Davon ab können aber viele alternative Programme auch eine Zeile am 
Stück oder per Makro Sequenzen auf Knopfdruck senden, das gute alte Br@y 
Terminal mal als Beispiel. Terminal Emulationen sind eher selten, seit 
MS kein Hyperterminal mehr mit ausliefert kenn das keiner mehr :)

von Joachim B. (jar)


Lesenswert?

Johannes S. schrieb:
> der gemeine Arduino User wird auch nicht unbedingt das Verlangen haben,
> andere Terminal/Monitorprogramme zu benutzen.

oh ich bin ein ungemeiner User?

Ich nutze meine Arduino Projekte auch auch abgesetzt von der IDE und 
mache Terminal Programme auf um das Modul zu steuern, Uhrzeit Datum der 
RTC korrigieren, automatische Rolladen Zeiten anzupassen, oder Rolladen 
manuell fernzusteuern. Die Rolläden werden per 433 MHz fernbedient, auch 
mal Funksteckdosen, oder meine wordclock12h per wUSB.

Wenn ich die umprogrammieren will nutze ich wUSB oder sharkoon 100/400 
USB Server im LAN über die Ardunio IDE, was aber sehr selten ist das die 
SW im Wesentlichen steht.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
>> Auch damit wechselst du zwischen C und C++.,
>> was unnötige Konvertierung erfordert
> Das passiert nur in deinem Kopf.

Das mag sein. Du siehst: Es macht den Quelltext für mich schwieriger 
lesbar. Deswegen ist er nicht falsch oder schlecht. ich wollte nur 
sagen, dass es nicht mein Stil ist und eine Alternative vorschlagen.

Yalu X. schrieb:
> Zu dem Code wäre noch anzumerken, dass auch readString() ...
> als einziges Kriterium für das String-Ende einen Timeout verwendet.

Wie bei den HC-06 Modulen. Wer hat sich da wohl von wem inspirieren 
lassen?

Sage mal kann es sein, dass Serial.readString() unf readStringUntil() 
beliebig viele Zeichen einliest?

Ich hatte das Problem mal mit einem ESP8266 auf einem IP Socket, da 
schmierte mir der Chip immer ab, wenn die Strings länger als 5kB wurden. 
Vermutlich wegen Stack-Überlauf.

von Stefan F. (Gast)


Lesenswert?

leo schrieb:
> Aber sicher ist das dokumentiert:
> https://www.arduino.cc/en/Tutorial/StringComparisonOperators

Ach guck mal, danke! Ich habe das direkt im Artikel der String Klasse 
erwartet.

von mh (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> leo schrieb:
>> Aber sicher ist das dokumentiert:
>> https://www.arduino.cc/en/Tutorial/StringComparisonOperators
>
> Ach guck mal, danke! Ich habe das direkt im Artikel der String Klasse
> erwartet.

Das ist jetzt schon mehrfach aufgekommen. Dabei steht das doch klar und 
deutlich in der Dokumentation unter 
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

von Stefan F. (Gast)


Lesenswert?

Da steht es aber nicht: 
https://www.arduino.cc/reference/de/language/variables/data-types/string/

Und da auch nicht:
https://www.arduino.cc/reference/en/language/variables/data-types/string/

Über wie viele Artikel haben die denn die Doku dieser einen Klasse 
verstreut? Ich werde bekloppt!

Nee, bin ich schon.

Ich habe ich daran gewöhnt, mit den Quelltexten zu arbeiten. Die sind 
überwiegend gut strukturiert und kommentiert.

von Joachim B. (jar)


Lesenswert?

Stefan ⛄ F. schrieb:
> Über wie viele Artikel haben die denn die Doku dieser einen Klasse
> verstreut?

ich hadere auch mit der Doku, aber egal es geht auch anders!

von Yalu X. (yalu) (Moderator)


Lesenswert?

Stefan ⛄ F. schrieb:
> Da steht es aber nicht:
> https://www.arduino.cc/reference/de/language/variables/data-types/string/
>
> Und da auch nicht:
> https://www.arduino.cc/reference/en/language/variables/data-types/string/

Das ist die Beschreibung der C-Strings, d.h. char-Arrays.

Die String-Klasse schreibt sich mit einem großen S und wird in einem
eigenen Kapitel beschrieben.

von leo (Gast)


Lesenswert?

Yalu X. schrieb:
> Das ist die Beschreibung der C-Strings, d.h. char-Arrays.

Nein. S. e.g. operators

von mh (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Da steht es aber nicht:
> https://www.arduino.cc/reference/de/language/variables/data-types/string/
>
> Und da auch nicht:
> https://www.arduino.cc/reference/en/language/variables/data-types/string/
>
> Über wie viele Artikel haben die denn die Doku dieser einen Klasse
> verstreut? Ich werde bekloppt!
>
> Nee, bin ich schon.
>
> Ich habe ich daran gewöhnt, mit den Quelltexten zu arbeiten. Die sind
> überwiegend gut strukturiert und kommentiert.

2ter & 3ter Satz im ersten Link:
1
Du kannst den String-Datentyp verwenden, der ab Version 0019 Teil des Kerns ist oder du kannst einen String aus einem Array des Typs char erstellen und ihn mit einem Nullterminator abschließen. Diese Seite beschreibt die letztere Methode. Für weitere Informationen zum String-Objekt, das mehr Funktionalität auf Kosten von mehr Arbeitsspeicher bietet, siehe die string object-Seite.
Inklusive Link zur Doku der String-Klasse. Was will man mehr? Im zweiten 
Link steht das gleiche auf englisch (wie zu erwarten, da es die 
englische Version der gleichen Seite ist)

von Chregu (Gast)


Lesenswert?

Ich verwende erfolgreich in der Loop folgenden Code:
(gekürzt aufs Nötigste)
1
char inputString[25];
2
int zaehler = 0;
3
4
void setup() {
5
  Serial.begin(9600);
6
}
7
 
8
void loop() {
9
  if (Serial.available()) {           // hat die TTL-Schnittstelle Zeichen?
10
    char inChar = Serial.read();      // das neue Byte einlesen
11
    inputString[zaehler] = inChar;    // und an die nächste Position im String
12
    zaehler++;                        // inc(Position)
13
    if (inChar == '\n') {             // wenn LF (chr$(10) (Enter)
14
      inputString[zaehler] = '\0';    // NULL zum Beenden des Strings
15
      String newString = inputString; // Array in String-Objekt umwandeln
16
      // Hier die Stringverarbeitung 
17
      zaehler = 0;                    // Nach(!) der Verarbeitung zurücksetzen
18
    }
19
  }
20
}

von Stefan F. (Gast)


Lesenswert?

Chregu schrieb:
> Ich verwende erfolgreich in der Loop folgenden Code:
> (gekürzt aufs Nötigste)

Offenbar zu viel gekürzt. Wenn der String länger ist, als der Puffer, 
stürzt das Ding ab.

von Karl K. (karl2go)


Lesenswert?

Arduino Fanboy D. schrieb:
> Schwer vorstellbar, dass du damit überfordert bist.

Oh bitte, ich habe mir diese Spielzeugsprache gut 2 Stunden angesehen - 
und das hat mir gereicht.

Arduino Fanboy D. schrieb:
> Schwer vorstellbar, dass du damit überfordert bist, den richtigen Ort zu
> finden, und die Buffergröße nach Wunsch einzustellen.

#IchhabBessereszutun

Jede vernünftige Seriel-Lib hat eine Möglichkeit, die Buffergröße 
einfach zu setzen, ohne im Code der Lib rumkrauchen zu müssen.

Gerade bei Arduino ist das essentiell, weil sonst einfach der Stack 
überschrieben wird.

Chregu schrieb:
> Ich verwende erfolgreich in der Loop folgenden Code:
> (gekürzt aufs Nötigste)

Oh Glückwunsch.

Ich mein, warum macht man sowas? Fehlerhafte Masseanbindung, falsche 
Baudrate, abweichender Baudratenquarz, falsch eingestelltes Terminal - 
oder eine Faxsoftware die nach einem Modem sucht... es gibt so viele 
Möglichkeiten einen RS232 mit falschen Daten zu fluten - und dabei 
jedesmal den Stack ins Nirwana zu schicken.

Nur weil man sich eine Buffer Overflow oder String Overflow Prüfung 
sparen will.

von Joachim B. (jar)


Lesenswert?

Stefan ⛄ F. schrieb:
> Offenbar zu viel gekürzt. Wenn der String länger ist, als der Puffer,
> stürzt das Ding ab.

eben

      if(isprint(incomingByte)) {
        if(chr_cnt<(MAXBUFFER-2))
          serial_in_buff[chr_cnt++] = incomingByte;
        else {
          Serial.println(F("serBUF ov-> DEL"));
          memset(&serial_in_buff[0], 0, sizeof(serial_in_buff));
          memset(&serial_in_command[0], 0, sizeof(serial_in_command));
          chr_cnt=0;
        } // if !(chr_cnt<(MAXBUFFER-2))
      } // if(isprint(incomingByte))

von Einer K. (Gast)


Lesenswert?

Karl K. schrieb:
> Oh bitte, ich habe mir diese Spielzeugsprache gut 2 Stunden angesehen -
> und das hat mir gereicht.
C++ ist also eine "Spielzeugsprache"?
Alles klar....
Keine Fragen mehr.

Karl K. schrieb:
> Jede vernünftige Seriel-Lib hat eine Möglichkeit, die Buffergröße
> einfach zu setzen, ohne im Code der Lib rumkrauchen zu müssen.
>
> Gerade bei Arduino ist das essentiell, weil sonst einfach der Stack
> überschrieben wird.
Irrational!
Wie du auf solche Ideen kommst, ist mir ein Rätsel.


Die 2 Stunden haben offensichtlich nicht gerecht, für ordentliche 
Argumente.

von Karl K. (karl2go)


Lesenswert?

Arduino Fanboy D. schrieb:
> C++ ist also eine "Spielzeugsprache"?

Ich bin mir ziemlich sicher dass du weißt, ich meine damit das was unter 
Arduino drauß gemacht wurde.

Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?

Heise bringts aktuell mal wieder gut auf den Punkt:

https://www.heise.de/hintergrund/Entwicklung-Warum-Rust-die-Antwort-auf-miese-Software-und-Programmierfehler-ist-4879795.html

von Carl D. (jcw2)


Lesenswert?

Stefan ⛄ F. schrieb:
> S. R. schrieb:
>> Ich werfe folgendes in den Raum:
>> if (strncmp(befehl.c_str(), "ein", 3) == 0) {...}
>
> Auch damit wechselst du zwischen C und C++., was unnötige Konvertierung
> erfordert und den eigenen Quelltext schlechter lesbar macht.
>
> Besser wäre in diesem Fall:
>
> if (befehl.indexOf("ein")==0) {...}

String::indexOf hat 2 Overloads. Eins für char, also Einzelzeichen und 
eins für String, aber kein Overload für "const Char *", das funktioniert 
nur, weil einen nicht-expliziten Konstructor für String gibt, der aus 
"const char *" einen String macht. Und dabei wird erst mal ein neuer 
String angelegt (auf dem Heap). "small string optimization", wie es in 
"kompletten" C++-Libs zu finden ist, gibt es nicht, also werden für 
"ein" 3 Bytes allokiert. Ist natürlich mit 64Bit Ptr/Länge/Kapazität, 
also 24Byte Verwaltungdaten einfacher da notfalls den Inhalt direkt 
reinzuschreiben, als beim AVR mit nur 6Byte.

Der String::operator==() hat ein Overload für "const char *" und kommt 
ohne temporären String aus.
Und das eigentliche Problem waren ja das/die Whitespace(s) am Ende des 
Befehls.

Allerdings kann man String leicht um fehlendes erweitern:
1
struct myString : Public String {
2
int String::indexOf(const char * cstr) const
3
{
4
  // hier darf man mit str..irgendwas() das gewünschte implementieren
5
  // also cstr in this.buffer suchen
6
}
7
};
Bei String ist das offensichtlich vorgesehen, da alle internen 
Daten/Methoden protected sind, also für Ableitungen sichtbar.

von STK500-Besitzer (Gast)


Lesenswert?

Karl K. schrieb:
> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?

Oder python? Oder C#? oder Basic?

Mich erinnert Rust an Pascal.
Meist werden neue Programmiersprachen entwickelt, weil jemand "zu doof 
oder zu faul" für die herkommlichen ist oder sie etwas "Modernes" nicht 
einfach so unterstützen (GUI-Programmierung in C auf einem 
Windows-Rechner war damals ziemlich aufwendig).
Oder sie einfach als alt und unmodern ("nicht mehr hip") angesehen 
werden.

von Stefan F. (Gast)


Lesenswert?

Karl K. schrieb:
> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?

Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Karl K. schrieb:
>> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?
>
> Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.

Der Kollege Karl hat schon lange eingesehen, dass seine Argumente an den 
Haaren herbei gelogen sind.
Anstatt sich auf einen Dialog einzulassen, greift er zum Mittel, welches 
sich auf Neudeutsch "whataboutism" nennt.
Oder einfach nur "Nebelkerzen".

Karl K. schrieb:
> Ich bin mir ziemlich sicher dass du weißt, ich meine damit das was unter
> Arduino drauß gemacht wurde.
Ja!
Ich denke schon...
C++ ist C++, und die Arduino Entwickler haben das nicht verändert.

Es ist ok, wenn du C++ nicht magst.
Es ist auch ok, wenn dir Arduino nicht schmeckt.
Aber was mir nicht schmeckt, ist dein Arduinobashing mit solchen 
Scheinargumenten/Nebelkerzen/Lügen.

Von mir aus können wir beide uns gerne sachlich über Arduino und die 
Zusammenhänge unterhalten.
Oder es auch sein lassen......

von Karl K. (karl2go)


Lesenswert?

Stefan ⛄ F. schrieb:
> Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.

Klar, wir lieben sie doch alle: Die Angriffe, weil die Länge der Url im 
Eingabefeld nicht begrenzt ist - und ausführbarer Code in den Speicher 
geschrieben wird. Oder nicht sichtbare Zeichen, die dann 
Speicherbereiche überschreiben.

Sowas gab es vor 25 Jahren - und sowas gibt es heute immer noch.

Soviel zu

STK500-Besitzer schrieb:
> Meist werden neue Programmiersprachen entwickelt, weil jemand "zu doof
> oder zu faul" für die herkommlichen ist

Ja, weil viele Programmierer sich absurd überschätzen und glauben nur 
die anderen machen Fehler.

Siehe oben: Auf Buffer Overflow prüfen brauch ich nicht, ich schick ja 
immer nur 3 Zeichen.

Und dann rumheulen, wenn man tagelang einen Fehler nicht findet, der µC 
schon immer abstürzt bevor man überhaupt zum Testen kommt - weil der 
Stack überschrieben wird. Weil man ein if sparen wollte.

von Joachim B. (jar)


Lesenswert?

Karl K. schrieb:
> Und dann rumheulen, wenn man tagelang einen Fehler nicht findet, der µC
> schon immer abstürzt bevor man überhaupt zum Testen kommt - weil der
> Stack überschrieben wird. Weil man ein if sparen wollte.

ist leider so musste ich auch erst lernen, deswegen kommt nach 
Serial.begin erst mal Mist auslesen!

  Serial.begin(19200);
//  while(Serial.available())
//    Serial.read();
  Serial.flush();

offensichtlich steht schon vorher was im Empfangsbuffer, woher? keine 
Ahnung denn ich sende vorher ja nichts, kann also Einstrahlung sein!

Das betrifft bei mir übrigens mehrere AVR, auch der NETIO von Pollin hat 
mit Arduino nichts zu tun!

Das führt am NETIO mit Radig SW regelmäßig zu einem Pufferüberlauf!
Die habe ich aber nie angepasst und dürfte auch nie den Pufferüberlauf 
prüfen oder gar auf isprint testen!

von Karl K. (karl2go)


Lesenswert?

Arduino Fanboy D. schrieb:
> Aber was mir nicht schmeckt, ist dein Arduinobashing mit solchen
> Scheinargumenten/Nebelkerzen/Lügen.

Oh bitte, lern erstmal Datentypen.

Beitrag "AVR Inline Optimierung kaputt?"

Genau diese Scheisse. Immer wieder. Seit zig Jahren. Und wird verteidigt 
bis aufs Messer.

von Karl K. (karl2go)


Lesenswert?

Joachim B. schrieb:
> offensichtlich steht schon vorher was im Empfangsbuffer, woher?

Ein AVR liefert gern erstmal ein $00 einfach durch den Pegelwechsel beim 
Einstecken, weil am Uart ein Startbit erkannt wird. Je nachdem ob die 
Uart Fehlerbits ausgewertet werden, landet das dann im Buffer.

Andere Gründe hab ich oben schon genannt, alles erlebt. Und nur deswegen 
unkritisch - weil man sich halt als Erstes Gedanken macht wie man Daten 
so behandelt, dass der Controller nicht dadurch lahmgelegt wird.

Ich mein, dass ist seit zig Jahren Praxis, aber dennoch schlagen immer 
wieder Leute auf, die meinen es besser zu wissen. Und wiederholen die 
Fehler von vor zig Jahren.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl K. schrieb:
> Beitrag "AVR Inline Optimierung kaputt?"
>
> Genau diese Scheisse. Immer wieder. Seit zig Jahren. Und wird verteidigt
> bis aufs Messer.

Naja, Thema war dort schlussendlich Undefined Behaviour (UB). Davon kann 
sich Rust auch nicht freisprechen:

https://doc.rust-lang.org/reference/behavior-considered-undefined.html

C ist darauf optimiert,

 - schnell zu sein
 - auf möglichst vielen Plattformen zu laufen

Beides kann man nur unter einen Hut bekommen, wenn man einiges 
schlichtweg als UB deklariert.

: Bearbeitet durch Moderator
von Karl K. (karl2go)


Lesenswert?

Frank M. schrieb:
> Naja, Thema war dort schlussendlich Undefined Behaviour (UB). Davon kann
> sich Rust auch nicht freisprechen:

Ja, aber wenn Du den Artikel bei Heise gelesen hättest, würdest Du 
verstehen: UB ist bei C(++) Standard, bei Rust muss man es wollen.

Du kannst mit Rust alle Fehler machen, die Du auch mit C(++) machen 
kannst. Aber eben nicht aus Versehen, sondern weil Du es willst.

Frank M. schrieb:
> C ist darauf optimiert,
>  - schnell zu sein
>  - auf möglichst vielen Plattformen zu laufen

Ich hab mal ne Weile Ada programmiert, das erzeugte asm-Listing für AVR 
war nicht viel anders als von C für gleiche Funktionen. Wie schnell ein 
Programm am Ende ist hängt nicht davon ab, wie sehr Dir der Kompiler auf 
die Finger haut.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl K. schrieb:
> Ich hab mal ne Weile Ada programmiert, das erzeugte asm-Listing für AVR
> war nicht viel anders als von C für gleiche Funktionen. Wie schnell ein
> Programm am Ende ist hängt nicht davon ab, wie sehr Dir der Kompiler auf
> die Finger haut.

Einfaches Beispiel: C/C++ reduziert den Ausdruck
1
x * 2 / 2
einfach zu x. Das kann Rust nicht so einfach machen, weil hier ein 
etwaiger Überlauf zu berücksichtigen ist.

Aber okay, der Anspruch, auf möglichst vielen Plattformen zu laufen, 
wirkt da vermutlich schwerer. Rust garantiert zum Beispiel bei 
Integer-Overflows ein Wrapping mit 2er Komplement im Release-Mode (Panic 
im Debug-Mode). Wenn das eine CPU nicht kann, muss der Rust-Compiler per 
Code nachhelfen. Dem C-Compiler ist das vollkommen egal, für ihn ist der 
Overflow von Signed Integers einfach UB, fertig.

Und so kann ich mir auch andere Beispiele vorstellen, wo die Portierung 
von Rust auf eine andere CPU durchaus mehr Arbeit machen kann als die 
Portierung eines C-Compilers.

Interessante Lektüre: 
http://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/

: Bearbeitet durch Moderator
von 🐧 DPA 🐧 (Gast)


Lesenswert?

Karl K. schrieb:
> Du kannst mit Rust alle Fehler machen, die Du auch mit C(++) machen
> kannst. Aber eben nicht aus Versehen, sondern weil Du es willst.

Die Rust Regeln können einen stark einschränken, wie man etwas lösen 
kann. Dann kann es viele einfache Lösungen geben, aber nutzt man die, 
statt das halbe Programm neu zu designen, ist es "es falsch machen 
wollen". Ich bezweifle mal stark, dass das immer zu gutem Programmdesign 
führt.

Ausserdem, werden Stack overflows in ach so safem Rust Code mittlerweile 
endlich im vornherein abgefangen? Ich sag nur Box::new([-1; 3000000]). 
So viel zum Thema Rust und Fehlersicherheit...

von Stefan F. (Gast)


Lesenswert?

Karl K. schrieb:
>> Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.
>
> Klar, wir lieben sie doch alle: Die Angriffe, weil die Länge der Url im
> Eingabefeld nicht begrenzt ist - und ausführbarer Code in den Speicher
> geschrieben wird. Oder nicht sichtbare Zeichen, die dann
> Speicherbereiche überschreiben.
>
> Sowas gab es vor 25 Jahren - und sowas gibt es heute immer noch.

Genau. Manche Projekte brauchen eher Sicherheit als Performance, und da 
macht Rust Sinn.

von S. R. (svenska)


Lesenswert?

Karl K. schrieb:
> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?

Weil "Fortschritt" erstmal einen "Schritt" braucht.

Ob der nach vorne, zur Seite oder sogar nach hinten geht, lässt sich 
vorher oft nicht vorhersehen.

Es ist heutzutage erstaunlich einfach, mal eben schnell eine 
Programmiersprache aus dem Boden zu stampfen... und es gibt viele davon.

von Stefan F. (Gast)


Lesenswert?

S. R. schrieb:
> Ob der nach vorne, zur Seite oder sogar nach hinten geht, lässt sich
> vorher oft nicht vorhersehen.

Ist auch eine Frage des Anwendungsfalls.

Die Möglichkeit, sehr dünne Scheiben herzustellen, ist zum Beispiel für 
Smartphones eine gute Sache, aber für Fensterscheiben nutzlos.

von mh (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Die Möglichkeit, sehr dünne Scheiben herzustellen, ist zum Beispiel für
> Smartphones eine gute Sache, aber für Fensterscheiben nutzlos.

Dünne Scheiben sind auch beim Smartphone eine schlechte Sache, wenn sie 
bei jeder Erschütterung einen Sprung bekommt. Bei meinen Fenstern wären 
dünnere Scheiben praktisch, da das Gewicht der Dreifachverglasung ein 
echtes Problem ist.

von Karl K. (karl2go)


Lesenswert?

Stefan ⛄ F. schrieb:
> Die Möglichkeit, sehr dünne Scheiben herzustellen, ist zum Beispiel für
> Smartphones eine gute Sache, aber für Fensterscheiben nutzlos.

Mehrscheiben-Sicherheitsglas. Bruchsicheres Vitrinenglas. Ein Bekannter 
hat jahrelang Fenster eingebaut - und wäre über dünnere und damit 
leichtere Scheiben sehr erfreut gewesen.

Man denkt ja häufig nur nicht über seinen Tellerrand hinaus...

: Bearbeitet durch User
von Karl K. (karl2go)


Lesenswert?

🐧 DPA 🐧 schrieb:
> So viel zum Thema Rust und Fehlersicherheit...

Du hast offenbar das Problem nicht verstanden:

Es wird nicht behauptet, dass Rust eine fehlerfreie Programmiersprache 
wäre.

Es geht darum, dass man bei Rust typische Fehler nur machen kann, wenn 
man die Sicherheit ABschaltet.

Während man bei C(++) um diese Fehler sicher auszuschließen die 
Sicherheit EINschalten muss.

von Roman Z. (ztec)


Lesenswert?

so gehts

String befehl;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  if(Serial.available() > 0){
    befehl = Serial.readString();
  }
  befehl.trim();
  if(befehl == "ein"){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("ein");
  }else if(befehl == "aus"){
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("aus");
  }
  befehl = "";
}

: Bearbeitet durch User
von Jochen S. (schoenf)


Lesenswert?

Vielleicht ist der gelesene String länger? Um ein CR und/oder LF 
vielleicht?

Dann funktioniert Vergleich auf Identität nicht.

LG Jochen

von Εrnst B. (ernst)


Lesenswert?

Jochen S. schrieb:
> Vielleicht ist der gelesene String länger? Um ein CR und/oder LF
> vielleicht?

Soweit waren wir schon am 25.08.2020.
befehl.trim() hat's behoben, auch wenn die Arduino-Dokumentation auf 
Deutsch behauptet, es entfernt nur Leerzeichen: es arbeitet wie in der 
Englischen Dokumentation beschrieben und entfernt "Whitespace".

: Bearbeitet durch User
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.