Serielle Kommandos auswerten

Hallo,

im Moment sende ich drei Werte um meine Led´s zu steuern. Also z.B. 255 255 255 ergibt weiß.

Mein Sketch dazu:

#include "FastLED.h"

#define NUM_LEDS 10
#define DATA_PIN 6
CRGB leds[NUM_LEDS];
byte val_r;
byte val_g;
byte val_b;



void setup() {
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  Serial.begin(9600);



}

void loop() {
while (Serial.available() > 0) {
  val_r = Serial.parseInt();
  val_g = Serial.parseInt();
  val_b = Serial.parseInt();
  

  if (Serial.read() == '\n') {
    for (int i = 0; i < NUM_LEDS; i++) {
      leds[i].r = val_r;
      leds[i].g = val_g;
      leds[i].b = val_b;
    }
  }
  FastLED.show();
}

}

Jetzt würde ich es aber gerne so ändern, das ich auch nur einzelne Werte ändern kann, ich schicke also z.B. ein r=100, und es ändert sich nur der wert für Rot.

Mir fehlt aber irgendwie der richtige Ansatz dazu.
Ein erster Versuch:

byte val_green;
byte val_red;
byte val_blue;
byte led_num;
int string;


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

void loop() {

 string=Serial.read(); 
 
if (string=='g=') {
  val_green=Serial.parseInt();
}

if (string=='r=') {
  val_redn=Serial.parseInt();
}

if (string=='b=') {
  val_blue=Serial.parseInt();
}

 if (string == '\n') {
    Serial.print("R=");
    Serial.println(val_red);

    Serial.print("G=");
    Serial.println(val_green);

    Serial.print("B=");
    Serial.println(val_blue);
  }

}

Vielen Dank im Vorraus.

'x' ist ein Zeichen. Kein String. Aktivtiere die Warnungen dann siehst du dass das der Compiler auch merkt

Sende dabei ein Linefeed am Ende (sonst geht es nicht!):

const int SERIAL_BUFFER_SIZE = 6;
char serialBuffer[SERIAL_BUFFER_SIZE];

byte r, g, b;

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

void loop()
{
  if (readSerial(Serial))      //liefert true wenn das LF eingelesen wurde
    parseSerial();
}

void parseSerial()
{
  switch (serialBuffer[0])
  {
  case 'r':
  case 'R':
    r = atoi(serialBuffer + 2);
    break;
  case 'g':
  case 'G':
    g = atoi(serialBuffer + 2);
    break;
  case 'b':
  case 'B':
    b = atoi(serialBuffer + 2);
    break;
  }

  Serial.print("R: "); Serial.println(r);
  Serial.print("G: "); Serial.println(g);
  Serial.print("B: "); Serial.println(b);
  Serial.println();
}


bool readSerial(Stream& stream)
{
  static byte index;

  while (stream.available())
  {
    char c = stream.read();

    if (c == '\n' && index > 0)       //wenn LF eingelesen und String länger als 0 ist
    {
      serialBuffer[index] = '\0';     //String terminieren
      index = 0;
      return true;                    //melden dass String fertig eingelesen wurde
    }
    else if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)   //solange noch Platz im Puffer ist
    {
      serialBuffer[index++] = c;    //Zeichen abspeichern und Index inkrementieren
    }
  }
  return false;        //noch nicht fertig
}

Mehr Code aber du hast so unendlich mehr Flexibilität als mit parseInt(). So kann man beliebige Strings einlesen und auswerten.
Außerdem ist es nicht-blockierend und du kannst "gleichzeitig" noch andere Dinge tun. Das ist gerade bei LED Sachen wichtig. parseInt() braucht normal eine ganze Sekunde und auch wenn man die Timeout Zeit nach unten setzt (siehe setTimeout()) ist es nicht schön

Du kannst auch das = weglassen. Ist eigentlich überflüssig. Aber dann muss das +2 bei der atoi() Konvertierung durch +1 ausgetauscht werden!

Und für RGB Werte hat FastLED übrigens ein Color struct

Hallo,

Was hälst Du davon, nur eine minimale Änderung des ersten Code:

Seriel musst Du dann: "LedNr r g b" übergeben.

#include "FastLED.h"

#define NUM_LEDS 10
#define DATA_PIN 6
CRGB leds[NUM_LEDS];
byte val_r;
byte val_g;
byte val_b;
byte led_num;



void setup() {
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  Serial.begin(9600);

}

void loop() {
if (Serial.available() > 0) {
  led_num = Serial.parseInt();
  val_r = Serial.parseInt();
  val_g = Serial.parseInt();
  val_b = Serial.parseInt();

  FastLED.show();
}

}

Grüße,
Donny
edit: Hab die while Schleife rausgeschmissen.

Weitere Moeglichtkeit:

String str_read; //alternativ char chstr_read[16];
str_read = Serial.readStringUntil('\n');
switch(str_read)
{
  case "..."
...
}

reference serial

parseInt() kann gehen. Gut ist es aber nicht. Und in jedem Fall sollte man unbedingt die Timeout Zeit nach unten setzten:

z.B. auf 10ms

Sonst blockiert jeder Aufruf für 1 Sekunde! Das ist typisch für viele Standard Arduino Funktionen die zwar machen was sie sagen, aber alles andere als schnell sind

Wenn man was fertiges verwendet, dann besser readStringUntil() oder readBytesUntil()

grillgemuese:
Weitere Moeglichtkeit:

String str_read; //alternativ char chstr_read[16];

str_read = Serial.readStringUntil('\n');
switch(str_read)
{
  case "..."
...
}

Das funktioniert sicher nicht.
Switch Case und Strings gehen nicht zusammen!
Reference Switch Case

Mein Favorit, in solchen Fällen, ist der CmdMessenger.

Dieser kapselt das ganze String Gehampel und auch den Dispatcher.

Läuft auf PC und Arduino
Kann Kommandos senden und empfangen

combie:
Mein Favorit, in solchen Fällen, ist der CmdMessenger.

Gemeint ist wahrscheinlich dieser - oder?

Genau der.

Das Beispiel "ConsoleShell.ino", deckt schon fast das hier gewünschte ab.
Die nötigen Anpassungen sind trivial.
(wenn ich die Frage richtig verstanden habe)

Ok, das muss ich jetzt erstmal durcharbeiten. Sind eine Menge Infos fürs erste.
Werde mich erstmal mit dem ersten Code,von Serenifly, auseinandersetzen.
Glaube das kommt meinem Ziel schon recht nahe. Möchte es aber auch selber schreiben können, deshalb erstmal verstehen.

Danach werde ich mir mal den CmdMessenger zu gemüte führen.

Erstmal Danke an Alle.

Hi,

im Prinziep baruchst Du doch 4 Komandos

Einlesen der Eingabe bis Zeileende in Zeichenkette da gibts Beispiele zu

R100 //stellt rot ein auf 100
G125 // stellt grün ein auf 125
B50 // stelt blau ein auf 50
A100// stellt alle auf 100

dann trennst Du das erste Zeichen ab und bringst den Rest in einen Integer Wert

mittels if verzweigen

Ausgänge mit Wert schreiben,

Schau dir mal unter Hilfe das String objekt an. ( ich weiß und höre auch schon den Aufschrei 8) )

Gruß Heinz

Rentner:
Schau dir mal unter Hilfe das String objekt an. ( ich weiß und höre auch schon den Aufschrei 8) )

Wenn Du es besser weißt, warum gibst Du dann solche problematischen Ratschläge? Willst Du den TO aufs Glatteis führen?

@TO: Schau Dir besser die Arbeit mit C-Zeichenketten (Chararrays) an.

Mit der Seriellen Verbindung vom PC habe ich mal eine RGB-LED gesteuert. Das Beispiel kannst Du Dir hier anschauen.

Gruß Tommy

Rentner:
dann trennst Du das erste Zeichen ab und bringst den Rest in einen Integer Wert

Abtrennen muss man da gar nichts. Man fragt mit switch/case auf das erste Zeichen ab.
Und macht dann atoi(... + 1). Letzteres ist auch ein großer Vorteil von char Arrays. Man kann Zeigerarithmetik verwenden.

In meinem Beispiel ist es +2 weil da noch das = danach kommt. Dass man das nicht braucht habe ich schon erwähnt