INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Serielle Eingabe zur Steuerung einer RGB-LED
20.07.2016, 15:33 (Dieser Beitrag wurde zuletzt bearbeitet: 20.07.2016 15:35 von Tommy56.)
Beitrag #1
Serielle Eingabe zur Steuerung einer RGB-LED
Hallo zusammen,

da immer wieder mal Diskussionen zur Dateneingabe über die serielle Schnittstelle aufkommen, habe ich mal ein Beispiel zusammen gebaut, wie man das bewerkstelligen kann. Es wird eine RGB-LED mit gemeinsamer Kathode gesteuert.

Edit: Arduino Mega 2560

Grundlage bildet eine Eingabezeile, die mit NL abgeschlossen ist und einen oder mehre Farbbefehle beinhaltet, die durch , (Komma) getrennt sind. Die Reihenfolge der Farben ist beliebig.

Die Farbbefehle können als b200, B200 oder b:200, B:200 geschrieben werden (Blau). Zusätzlich ist a bzw. A für "alles aus" vorhanden, das nur am Anfang der Zeile sinnvoll ist.

Beispiele:

b200,r30,g100 -> Blau = 200, Rot = 30, Grün = 100
a,r:200 -> alles aus und dann Rot = 200

Was könnte man noch verbessern / optimieren. Ich bin seit 2008 aus der C-Übung und muß mich erst wieder in die Feinheiten einfuchsen.

Gruß Tommy

Code:
//serial2_string
// Steuerung einer RGB-LED (gemeinsame Kathode) per Serial
// Stringaufbau: a = alles aus (hier ist die Reihenfolge wichtig)
//               b200 oder b:200 setzt blau auf 200 (anlog r = rot, g = gruen) rgb auch als RGB moeglich
// mehrere Farben mit , getrennt. Abschluss der Eingabe NL (\n)
// z.B.: b200,r:55,g127  -> Blau 200 + Rot 55 + Gruen 127
//       a,b100 -> alles aus, dann Blau 100

// Wechselweise auskommentieren mit und ohne Debugcode
#define DEBUG 1
//#undef DEBUG

const byte LEDblau = 2; // Farbe blau an Pin 2
const byte LEDgruen = 3; // Farbe gruen an Pin 3
const byte LEDrot = 4; // Farbe rot an Pin 4

const byte dunkel = 0; // Wert fuer LED dunkel (Bei gemeinsamer Anode 255)

byte hellRot = dunkel; // Helligkeit
byte hellGruen = dunkel;
byte hellBlau = dunkel;

const byte IN_LEN = 20; // Puffergroesse Eingabe

boolean status = false; // Fehlerstatus true = ok, false = Error
boolean fertig = false; // Eingabe beendet
char inputChar;  // Zeichen zum Einlesen
char inStr[IN_LEN];  // Lesepuffer

#ifdef DEBUG
const char ok[] = "OK: ";
const char err[] = "Error: ";
char inStrDebug[IN_LEN];  // Lesepuffer zum Debuggen merken wegen Stringtokenizer
#endif


void setup() {
  Serial.begin(115200);
  // Warten bis Serial bereit
  while (!Serial);
  #ifdef DEBUG
  Serial.println("Start");
  #endif
  // alle LED aus
  analogWrite(LEDblau,dunkel);
  analogWrite(LEDgruen,dunkel);
  analogWrite(LEDrot,dunkel);
  // LED-Ausgaenge setzen
  pinMode(LEDblau, OUTPUT);
  pinMode(LEDgruen, OUTPUT);
  pinMode(LEDrot, OUTPUT);
  inStr[0] = '\0';  // Puffer auf leer initialisieren
}

void loop() {
  if (Serial.available() > 0)
    if (fertig = einlesen()) {
      // ganze Zeile eingelesen
      status = auswerten();
      if (status) {
        // mindestens 1 gueltiger Wert
        analogWrite(LEDblau,hellBlau);
        analogWrite(LEDgruen,hellGruen);
        analogWrite(LEDrot,hellRot);
      }
      #ifdef DEBUG
      ausgabe(status);
      #endif
    }  
}

// true = fertig (LF oder zu lang), false = noch nicht fertig
boolean einlesen() {
static byte i = 0; // Positionsindex in inStr
  // wenn es schon eine vollstaendige Eingabe gab -> zuruecksetzen
  if (fertig) {
    fertig = false;  // neuer Anfang
    inStr[0] = '\0'; // Puffer initialisieren
    i = 0; // Positiojnsindex auf Anfang
  }
  inputChar = Serial.read();
  // Wenn nicht Zeilenende und nicht Puffer voll
  if (inputChar != '\n' && i < IN_LEN -1) {
    // Zeichen in inStr schreiben
    inStr[i] = inputChar;
    inStr[++i] = '\0'; // Abschluss dahinter schreiben, um evtl. Debugausgaben richtig anzuzeigen
    return false;
  }  
  #ifdef DEBUG
  // kopieren wegen strtok_r fuer Debuggen
  // strtok_r veraendert das Ursprungsarray
  strcpy(inStrDebug,inStr);
  Serial.println("Fertig");
  #endif
  // Wenn noch Zeichen in Serial, diese vernichten
  // z.B. Wenn Eingabe zu lang war
  while (Serial.available() > 0) {
    inputChar = Serial.read();
    #ifdef DEBUG
    Serial.print("Zeichen: ");
    Serial.println(inputChar);
    #endif
  }
  return true;
}

#ifdef DEBUG
// Ausgabe Status und Eingabezeile
void ausgabe(boolean isOk) {
  if (isOk) {
    Serial.print(ok);
  }
  else {
    Serial.print(err);
  }
  Serial.println(inStrDebug);
}
#endif

// true = es gab mindestens einen richtigen Wert, false = kein gueltiger Wert
boolean auswerten() {
char *ptr, *p, *savePtr, *saveP;
const char delim[] = ",";
char first;
boolean status = false;
int wert;
  // inStr zerlegen an ,
  // strtok ist nicht wiedereintrittsfähig,
  // deshalb strtok_r nehmen, um auch den Doppelpunkt auszuwerten zu koennen
  ptr = strtok_r(inStr,delim,&savePtr);
  while (ptr != NULL) {
    // ist ein Doppelpunkt drin?
    if (strchr(ptr,':')) {
      // mit Doppelpunkt
      // neuer Stringtokenizer
      p = strtok_r(ptr,":",&saveP);
      if (p != NULL) {
        // erster Teil Farbe
        first = p[0];
      }
      p = strtok_r(NULL,":",&saveP);
      if (p != NULL) {
        // zweiter Teil Farbwert
        wert = atoi(p);
      }
    }
    else {
      // ohne Doppelpunkt
      first = ptr[0];
      wert = atoi(ptr+1);
    }
    // begrenzen auf 255
    if (wert > 255) {
      wert = 255;
    }
    // keine negativen Werte
    if (wert < 0) {
      wert = 0;
    }
    switch (first) {
      case 'a':   // alles aus
      case 'A':    hellRot = dunkel;
                  hellGruen = dunkel;
                  hellBlau = dunkel;
                  status = true;
                  break;
      case 'r':    // rot
      case 'R':    hellRot = wert;
                  status = true;
                  break;
      case 'g':    // gruen
      case 'G':    hellGruen = wert;
                  status = true;
                  break;
      case 'b':    // blau
      case 'B':    hellBlau = wert;
                  status = true;
                  break;
    }
    #ifdef DEBUG
    Serial.print("Farbe: ");
    Serial.print(first);
    Serial.print(" Wert: ");
    Serial.println(wert);
    #endif
    // naechster Token. NULL, wenn nichts gefunden
    ptr = strtok_r(NULL,delim,&savePtr);
  }
  return status;
}
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
20.07.2016, 16:43
Beitrag #2
RE: Serielle Eingabe zur Steuerung einer RGB-LED
Hey!

Schöner Sketch mit guten Erklärungen! Smile
Hast du bewusst mit char-array's gearbeitet, weil man auch alles (vielleicht leichter?) mit string's verarbeiten könnte? Ich habe mich bis jetzt nochnicht alzu viel mit Textauswertung etc. beschäftigt um auf die Schnelle sagen zu können was einfacher ist Big Grin
Als Zusatz wäre vielleicht noch interessant Effekt einstellen zu können z.B. Fading:
r200:g50:bf -> Rot auf 200, Gelb auf 50, Blau im Fade-Modus (Helligkeit steigt und fällt in einer gewissen Zeit).
Oder: Blinken
rf:g255:bb -> Rot fading, Gelb auf HIGH, Blau blinkt.

mfg Scheams
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
20.07.2016, 17:21
Beitrag #3
RE: Serielle Eingabe zur Steuerung einer RGB-LED
(20.07.2016 16:43)Scheams schrieb:  Hast du bewusst mit char-array's gearbeitet, weil man auch alles (vielleicht leichter?) mit string's verarbeiten könnte?
Ja, das habe ich bewusst aus 2 Gründen gemacht.
  • In einigen Beiträgen wurde geschrieben, dass Strings ziemlich viel Speicherplatz brauchen
  • Ich habe bis 2008 ca. 10 Jahre ANSI-C geschrieben und da sind mir die Char-Arrays vertrauter.

(20.07.2016 16:43)Scheams schrieb:  Als Zusatz wäre vielleicht noch interessant Effekt einstellen zu können z.B. Fading:
r200:g50:bf -> Rot auf 200, Gelb auf 50, Blau im Fade-Modus (Helligkeit steigt und fällt in einer gewissen Zeit).
Oder: Blinken
rf:g255:bb -> Rot fading, Gelb auf HIGH, Blau blinkt.
Ja, da sind noch einige Erweiterungen möglich. Entweder man bleibt bei den Befehlen aus einem Buchstaben, dann muss man halt z.B. e, f, g für Fading rot blau grün aufwärts und h,i,j für abwärts nehmen oder man benutzt variabel lange Befehle, dann sollte das Trennzeichen (: Doppelpunkt) Pflicht sein.

Mal sehen, was noch so für Ideen kommen.

Gruß Tommy
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
21.07.2016, 18:06
Beitrag #4
RE: Serielle Eingabe zur Steuerung einer RGB-LED
Ich habe die Anregung mit der Fade-Steuerung aufgegriffen und in diesem Zug die Einstellwerte für jede Farbe in einem Struct zusammengefasst und die 3 Farben dann in einem Array.

Der Befehlsaufbau steht oben im Kommentar. Evtl. kann jemand mit dem Beispiel etwas anfangen.

Gruß Tommy

Code:
//serial3_string
// Steuerung einer RGB-LED (gemeinsame Kathode) per Serial
// Befehlsaufbau: Befehl:(Doppelpunkt)Wert
// Befehl: 1.Zeichen Farbe (rgb bzw. RGB), 2.Zeichen Kommando (s = set, i=fadingintervall in ms, f= fading zu Zielwert)
// Fuer den Befehl set gibt es die Abkuerzungen ohne s und ohne :(Doppelpunkt) z.B. b:200 bzw. b200
// Bytewerte werden auf 0...255 begrenzt
// ein Sonderbefehl ist a = alles aus (auf Initialwerte)

// Eine Befehlszeile beinhaltet mit , (Komma) getrennte Befehle, die mit NL (\n) abgeschlossen wird.  
// Set und Intervall setzen ein bestehendes Fading zurueck

// Wechselweise auskommentieren mit und ohne Debugcode
#define DEBUG 1
//#undef DEBUG

const byte LEDblau = 2; // Farbe blau an Pin 2
const byte LEDgruen = 3; // Farbe gruen an Pin 3
const byte LEDrot = 4; // Farbe rot an Pin 4

const byte dunkel = 0; // Wert fuer LED dunkel (Bei gemeinsamer Anode 255)
const byte ANZ = 3;
enum farbenIndex {ROT, BLAU, GRUEN};

uint32_t currentMillis;

boolean fertig = false; // Eingabe beendet
boolean status = false; // Fehlerstatus true = ok, false = Error

char inputChar;  // Zeichen zum Einlesen
const byte IN_LEN = 100; // Puffergroesse Eingabe
char inStr[IN_LEN];  // Lesepuffer

#ifdef DEBUG
const char ok[] = "OK: ";
const char err[] = "Error: ";
char inStrDebug[IN_LEN];  // Lesepuffer zum Debuggen merken wegen Stringtokenizer
#endif

// Werte zuur Steuerung einer Farbe
struct t_farbe {
  byte pin;
  byte hell;
  int8_t delta;
  byte ziel;
  uint32_t intervall;
  uint32_t prevMillis;
};

// Array über die 3 Farben
t_farbe farben[ANZ];

void setup() {
  Serial.begin(115200);
  while (!Serial);
  #ifdef DEBUG
  Serial.println("Start");
  #endif
  initFarben();
  // alle LED aus
  analogWrite(LEDblau,dunkel);
  analogWrite(LEDgruen,dunkel);
  analogWrite(LEDrot,dunkel);
  // LED-Ausgaenge setzen
  pinMode(LEDblau, OUTPUT);
  pinMode(LEDgruen, OUTPUT);
  pinMode(LEDrot, OUTPUT);
  inStr[0] = '\0';  // Puffer auf leer initialisieren
}

void loop() {
  if (Serial.available() > 0) {
    if (fertig = einlesen()) {
      // ganze Zeile eingelesen
      status = auswerten();
      #ifdef DEBUG
      ausgabe(status);
      #endif
    }  
  }
  currentMillis = millis();
  calcFading();
  ledAusgabe();
}

// Steuerung der LEDhelligkeit
void ledAusgabe() {
  for(byte i=0;i<ANZ;i++){
    analogWrite(farben[i].pin,farben[i].hell);
  }
}

// farben initialisieren
void initFarben() {
  farben[ROT].pin = LEDrot;
  farben[BLAU].pin = LEDblau;
  farben[GRUEN].pin = LEDgruen;
  for(byte i=0; i< ANZ;i++) {
    farben[i].delta = 0;
    farben[i].intervall = 50;
    farben[i].hell = 0;
    farben[i].ziel = 0;
  }
}

// bestimmt den Delta-Wert für Fading
byte calcDelta(struct t_farbe *f) {
  if (f->ziel == f->hell) return 0;
  if (f->ziel > f->hell) return 1;
  return -1;  
}

// Berechnung des Fading ueber die 3 Farben
void calcFading() {
  for(byte i=0;i<ANZ;i++) {
    calcHell(&farben[i]);
  }
}

// Bestimmung der Helligkeit durch Fading
void calcHell(struct t_farbe *f) {
  if (f->delta == 0) return; // kein delta, also kein Fading
  // Intervall der Farbe vorbei?
  if (currentMillis - f->prevMillis >= f->intervall) {
    f->hell += f->delta; // neue Helligkeit;
    // um unsinnige Eingaben abzufangen nicht mit == vergleichen
    if (f->delta > 0 && f->hell >= f->ziel) {
      f->delta = 0; // faden aufwaerts fertig
    }  
    if (f->delta < 0 && f->hell <= f->ziel) {
      f->delta = 0; // faden abwaerts fertig
    }  
    f->prevMillis = currentMillis;
  }
}

// true = fertig (LF oder zu lang), false = noch nicht fertig
boolean einlesen() {
static byte i = 0; // Positionsindex in inStr
  // wenn es schon eine vollstaendige Eingabe gab -> zuruecksetzen
  if (fertig) {
    fertig = false;  // neuer Anfang
    inStr[0] = '\0'; // Puffer initialisieren
    i = 0; // Positiojnsindex auf Anfang
  }
  inputChar = Serial.read();
  // Wenn nicht Zeilenende und nicht Puffer voll
  if (inputChar != '\n' && i < IN_LEN -1) {
    // Zeichen in inStr schreiben
    inStr[i] = inputChar;
    inStr[++i] = '\0'; // Abschluss dahinter schreiben, um evtl. Debugausgaben richtig anzuzeigen
    return false;
  }  
  #ifdef DEBUG
  // kopieren wegen strtok_r fuer Debuggen
  // strtok_r veraendert das Ursprungsarray
  strcpy(inStrDebug,inStr);
  Serial.println("Fertig");
  #endif
  // Wenn noch Zeichen in Serial, diese vernichten
  // z.B. Wenn Eingabe zu lang war
  while (Serial.available() > 0) {
    inputChar = Serial.read();
    #ifdef DEBUG
    Serial.print("Zeichen: ");
    Serial.println(inputChar);
    #endif
  }
  return true;
}

#ifdef DEBUG
// Ausgabe Status und Eingabezeile
void ausgabe(boolean isOk) {
  if (isOk) {
    Serial.print(ok);
  }
  else {
    Serial.print(err);
  }
  Serial.println(inStrDebug);
}
#endif

// true = es gab mindestens einen richtigen Wert, false = kein gueltiger Wert
boolean auswerten() {
char *ptr, *p, *savePtr, *saveP;
const char delim[] = ",";
char farbe;
char befehl;
boolean status = false;
uint32_t wert;
  // inStr zerlegen an ,
  // strtok ist nicht wiedereintrittsfähig,
  // deshalb strtok_r nehmen, um auch den Doppelpunkt auszuwerten zu koennen
  // einzelne Befehle ermitteln
  ptr = strtok_r(inStr,delim,&savePtr);
  while (ptr != NULL) {
    // ist ein Doppelpunkt drin?
    if (strchr(ptr,':')) {
      // mit Doppelpunkt
      // neuer Stringtokenizer
      p = strtok_r(ptr,":",&saveP);
      if (p != NULL) {
        // erster Teil Farbe und Befehl
        farbe = p[0];
        befehl = p[1];
        if (befehl == '\0') befehl = 's';  // verkuerzte Set-Variante
      }
      p = strtok_r(NULL,":",&saveP);
      if (p != NULL) {
        // zweiter Teil Wert
        wert = atol(p);
      }
    }
    else {
      // ohne Doppelpunkt
      farbe = ptr[0];
      if (farbe == 'a') {
        // alle aus
        status = true;
        initFarben();
      }
      else {
        if (isDigit(ptr[1])) {
          befehl = 's';
          wert = atol(ptr+1);
        }
        else {
          // fehlerhafte verkuerzte Set-Schreibweise
          farbe = 'x';
          befehl = 'x';
        }
      }
    }
    farbe = toupper(farbe);
    befehl = toupper(befehl);
    
    // ausser Intervall ist byte
    if (befehl != 'I') {
    // begrenzen auf 255
      if (wert > 255) {
        wert = 255;
      }
    }
    // keine negativen Werte
    if (wert < 0) {
      wert = 0;
    }
    #ifdef DEBUG
    Serial.print("Befehl: ");
    Serial.print(befehl);
    Serial.print(" Farbe: ");
    Serial.print(farbe);
    Serial.print(" Wert: ");
    Serial.println(wert);
    #endif
    
    switch (farbe) {
      case 'R': // Rot
                setFarbe(&farben[ROT], befehl, wert);
                status = true;
                break;
      case 'G': // Gruen
                setFarbe(&farben[GRUEN], befehl, wert);
                status = true;
                break;
      case 'B': // Blau
                setFarbe(&farben[BLAU], befehl, wert);
                status = true;
                break;
    }
    ptr = strtok_r(NULL,delim,&savePtr);
    ausgabeFarben();
  }
  return status;
}

// wendet die Befehle auf die Farbe an
void setFarbe(struct t_farbe *f, char befehl, uint32_t wert) {
  switch (befehl) {
    case 'S': // Set
              f->hell = (byte) wert;
              f->delta = 0;
              break;
    case 'I': // Intervall
              f->intervall = wert;
              f->delta = 0;
              break;
    case 'F': // Fade
              f->ziel = (byte) wert;
              f->delta = calcDelta(f);
              
  }
}

#ifdef DEBUG
void ausgabeFarbe(byte i, struct t_farbe *f) {
// ein Pointerarray auf die Strings
const char *fstr[] = {"ROT","BLAU","GRUEN"};

  Serial.print("Farbe: "); Serial.print(fstr[i]);
  Serial.print(" Pin: "); Serial.print(f->pin);
  Serial.print(" Hell: "); Serial.print(f->hell);
  Serial.print(" Delta: "); Serial.print(f->delta);
  Serial.print(" Ziel: "); Serial.print(f->ziel);
  Serial.print(" Int: "); Serial.print(f->intervall);
  Serial.print(" Prev: "); Serial.println(f->prevMillis);
}

void ausgabeFarben() {
  for(byte i=0; i< ANZ; i++) {
    ausgabeFarbe(i,&farben[i]);
  }
}
#endif
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
22.07.2016, 14:18
Beitrag #5
RE: Serielle Eingabe zur Steuerung einer RGB-LED
Hey!

Habs direkt mal ausprobiert und funktioniert auch! Smile Bin dadurch draufgekommen, dass an meiner RGB-Platine (von nem Starterkit) die Rot- und Blau-Anschlüsse vertauscht sind Dodgy Big Grin

Ein #ifdef DEBUG #endif fehlt um die Funktion ausgabeFarben() in Zeile 273 (Kompilerfehler wenn man DEBUG Mouds aus macht).

Fadingmodus geht auch - nur ich hatte mir den Fadingmodus so vorgestellt, dass er andauernt die Helligkeit rauf und runter regelt. Sieht man evtl. mehr. Fallst du es nicht machst schau ich vielleicht in nächster Zeit in den Sketch und versuchs so umzuschreiben Smile

mfg Scheams
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
22.07.2016, 18:32
Beitrag #6
RE: Serielle Eingabe zur Steuerung einer RGB-LED
(22.07.2016 14:18)Scheams schrieb:  Ein #ifdef DEBUG #endif fehlt um die Funktion ausgabeFarben() in Zeile 273 (Kompilerfehler wenn man DEBUG Mouds aus macht).
Danke für den Hinweis. Ich stelle die korrigierte Fassung rein.
Weitere Änderungen werde ich nicht mehr einbauen, der Sketch sollte das Prinzip des Parsens verdeutlichen. Sonst wird er zu komplex.

Gruß Tommy

Code:
//serial3_string
// Steuerung einer RGB-LED (gemeinsame Kathode) per Serial
// Befehlsaufbau: Befehl:(Doppelpunkt)Wert
// Befehl: 1.Zeichen Farbe (rgb bzw. RGB), 2.Zeichen Kommando (s = set, i=fadingintervall in ms, f= fading zu Zielwert)
// Fuer den Befehl set gibt es die Abkuerzungen ohne s und ohne :(Doppelpunkt) z.B. b:200 bzw. b200
// Bytewerte werden auf 0...255 begrenzt
// ein Sonderbefehl ist a = alles aus (auf Initialwerte)

// Eine Befehlszeile beinhaltet mit , (Komma) getrennte Befehle, die mit NL (\n) abgeschlossen wird.  
// Set und Intervall setzen ein bestehendes Fading zurueck

// Wechselweise auskommentieren mit und ohne Debugcode
#define DEBUG 1
//#undef DEBUG

const byte LEDblau = 2; // Farbe blau an Pin 2
const byte LEDgruen = 3; // Farbe gruen an Pin 3
const byte LEDrot = 4; // Farbe rot an Pin 4

const byte dunkel = 0; // Wert fuer LED dunkel (Bei gemeinsamer Anode 255)
const byte ANZ = 3;
enum farbenIndex {ROT, BLAU, GRUEN};

uint32_t currentMillis;

boolean fertig = false; // Eingabe beendet
boolean status = false; // Fehlerstatus true = ok, false = Error

char inputChar;  // Zeichen zum Einlesen
const byte IN_LEN = 100; // Puffergroesse Eingabe
char inStr[IN_LEN];  // Lesepuffer

#ifdef DEBUG
const char ok[] = "OK: ";
const char err[] = "Error: ";
char inStrDebug[IN_LEN];  // Lesepuffer zum Debuggen merken wegen Stringtokenizer
#endif

// Werte zuur Steuerung einer Farbe
struct t_farbe {
  byte pin;
  byte hell;
  int8_t delta;
  byte ziel;
  uint32_t intervall;
  uint32_t prevMillis;
};

// Array über die 3 Farben
t_farbe farben[ANZ];

void setup() {
  Serial.begin(115200);
  while (!Serial);
  #ifdef DEBUG
  Serial.println("Start");
  #endif
  initFarben();
  // alle LED aus
  analogWrite(LEDblau,dunkel);
  analogWrite(LEDgruen,dunkel);
  analogWrite(LEDrot,dunkel);
  // LED-Ausgaenge setzen
  pinMode(LEDblau, OUTPUT);
  pinMode(LEDgruen, OUTPUT);
  pinMode(LEDrot, OUTPUT);
  inStr[0] = '\0';  // Puffer auf leer initialisieren
}

void loop() {
  if (Serial.available() > 0) {
    if (fertig = einlesen()) {
      // ganze Zeile eingelesen
      status = auswerten();
      #ifdef DEBUG
      ausgabe(status);
      #endif
    }  
  }
  currentMillis = millis();
  calcFading();
  ledAusgabe();
}

// Steuerung der LEDhelligkeit
void ledAusgabe() {
  for(byte i=0;i<ANZ;i++){
    analogWrite(farben[i].pin,farben[i].hell);
  }
}

// farben initialisieren
void initFarben() {
  farben[ROT].pin = LEDrot;
  farben[BLAU].pin = LEDblau;
  farben[GRUEN].pin = LEDgruen;
  for(byte i=0; i< ANZ;i++) {
    farben[i].delta = 0;
    farben[i].intervall = 50;
    farben[i].hell = 0;
    farben[i].ziel = 0;
  }
}

// bestimmt den Delta-Wert für Fading
byte calcDelta(struct t_farbe *f) {
  if (f->ziel == f->hell) return 0;
  if (f->ziel > f->hell) return 1;
  return -1;  
}

// Berechnung des Fading ueber die 3 Farben
void calcFading() {
  for(byte i=0;i<ANZ;i++) {
    calcHell(&farben[i]);
  }
}

// Bestimmung der Helligkeit durch Fading
void calcHell(struct t_farbe *f) {
  if (f->delta == 0) return; // kein delta, also kein Fading
  // Intervall der Farbe vorbei?
  if (currentMillis - f->prevMillis >= f->intervall) {
    f->hell += f->delta; // neue Helligkeit;
    // um unsinnige Eingaben abzufangen nicht mit == vergleichen
    if (f->delta > 0 && f->hell >= f->ziel) {
      f->delta = 0; // faden aufwaerts fertig
    }  
    if (f->delta < 0 && f->hell <= f->ziel) {
      f->delta = 0; // faden abwaerts fertig
    }  
    f->prevMillis = currentMillis;
  }
}

// true = fertig (LF oder zu lang), false = noch nicht fertig
boolean einlesen() {
static byte i = 0; // Positionsindex in inStr
  // wenn es schon eine vollstaendige Eingabe gab -> zuruecksetzen
  if (fertig) {
    fertig = false;  // neuer Anfang
    inStr[0] = '\0'; // Puffer initialisieren
    i = 0; // Positiojnsindex auf Anfang
  }
  inputChar = Serial.read();
  // Wenn nicht Zeilenende und nicht Puffer voll
  if (inputChar != '\n' && i < IN_LEN -1) {
    // Zeichen in inStr schreiben
    inStr[i] = inputChar;
    inStr[++i] = '\0'; // Abschluss dahinter schreiben, um evtl. Debugausgaben richtig anzuzeigen
    return false;
  }  
  #ifdef DEBUG
  // kopieren wegen strtok_r fuer Debuggen
  // strtok_r veraendert das Ursprungsarray
  strcpy(inStrDebug,inStr);
  Serial.println("Fertig");
  #endif
  // Wenn noch Zeichen in Serial, diese vernichten
  // z.B. Wenn Eingabe zu lang war
  while (Serial.available() > 0) {
    inputChar = Serial.read();
    #ifdef DEBUG
    Serial.print("Zeichen: ");
    Serial.println(inputChar);
    #endif
  }
  return true;
}

#ifdef DEBUG
// Ausgabe Status und Eingabezeile
void ausgabe(boolean isOk) {
  if (isOk) {
    Serial.print(ok);
  }
  else {
    Serial.print(err);
  }
  Serial.println(inStrDebug);
}
#endif

// true = es gab mindestens einen richtigen Wert, false = kein gueltiger Wert
boolean auswerten() {
char *ptr, *p, *savePtr, *saveP;
const char delim[] = ",";
char farbe;
char befehl;
boolean status = false;
uint32_t wert;
  // inStr zerlegen an ,
  // strtok ist nicht wiedereintrittsfähig,
  // deshalb strtok_r nehmen, um auch den Doppelpunkt auszuwerten zu koennen
  // einzelne Befehle ermitteln
  ptr = strtok_r(inStr,delim,&savePtr);
  while (ptr != NULL) {
    // ist ein Doppelpunkt drin?
    if (strchr(ptr,':')) {
      // mit Doppelpunkt
      // neuer Stringtokenizer
      p = strtok_r(ptr,":",&saveP);
      if (p != NULL) {
        // erster Teil Farbe und Befehl
        farbe = p[0];
        befehl = p[1];
        if (befehl == '\0') befehl = 's';  // verkuerzte Set-Variante
      }
      p = strtok_r(NULL,":",&saveP);
      if (p != NULL) {
        // zweiter Teil Wert
        wert = atol(p);
      }
    }
    else {
      // ohne Doppelpunkt
      farbe = ptr[0];
      if (farbe == 'a') {
        // alle aus
        status = true;
        initFarben();
      }
      else {
        if (isDigit(ptr[1])) {
          befehl = 's';
          wert = atol(ptr+1);
        }
        else {
          // fehlerhafte verkuerzte Set-Schreibweise
          farbe = 'x';
          befehl = 'x';
        }
      }
    }
    farbe = toupper(farbe);
    befehl = toupper(befehl);
    
    // ausser Intervall ist byte
    if (befehl != 'I') {
    // begrenzen auf 255
      if (wert > 255) {
        wert = 255;
      }
    }
    // keine negativen Werte
    if (wert < 0) {
      wert = 0;
    }
    #ifdef DEBUG
    Serial.print("Befehl: ");
    Serial.print(befehl);
    Serial.print(" Farbe: ");
    Serial.print(farbe);
    Serial.print(" Wert: ");
    Serial.println(wert);
    #endif
    
    switch (farbe) {
      case 'R': // Rot
                setFarbe(&farben[ROT], befehl, wert);
                status = true;
                break;
      case 'G': // Gruen
                setFarbe(&farben[GRUEN], befehl, wert);
                status = true;
                break;
      case 'B': // Blau
                setFarbe(&farben[BLAU], befehl, wert);
                status = true;
                break;
    }
    ptr = strtok_r(NULL,delim,&savePtr);
    #ifdef DEBUG
    ausgabeFarben();
    #endif
  }
  return status;
}

// wendet die Befehle auf die Farbe an
void setFarbe(struct t_farbe *f, char befehl, uint32_t wert) {
  switch (befehl) {
    case 'S': // Set
              f->hell = (byte) wert;
              f->delta = 0;
              break;
    case 'I': // Intervall
              f->intervall = wert;
              f->delta = 0;
              break;
    case 'F': // Fade
              f->ziel = (byte) wert;
              f->delta = calcDelta(f);
              
  }
}

#ifdef DEBUG
void ausgabeFarbe(byte i, struct t_farbe *f) {
// ein Pointerarray auf die Strings
const char *fstr[] = {"ROT","BLAU","GRUEN"};

  Serial.print("Farbe: "); Serial.print(fstr[i]);
  Serial.print(" Pin: "); Serial.print(f->pin);
  Serial.print(" Hell: "); Serial.print(f->hell);
  Serial.print(" Delta: "); Serial.print(f->delta);
  Serial.print(" Ziel: "); Serial.print(f->ziel);
  Serial.print(" Int: "); Serial.print(f->intervall);
  Serial.print(" Prev: "); Serial.println(f->prevMillis);
}

void ausgabeFarben() {
  for(byte i=0; i< ANZ; i++) {
    ausgabeFarbe(i,&farben[i]);
  }
}
#endif
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  360° Kamera Steuerung mit Gopro ardu1n1x 7 967 16.11.2016 10:11
Letzter Beitrag: Wolfgang50
  DIY Arduino Timelapse Slider Steuerung Uwe1475 6 639 12.11.2016 10:41
Letzter Beitrag: Uwe1475
  Sensorpositionierung mit einer Spindel Badger1875 5 208 05.11.2016 20:11
Letzter Beitrag: hotsystems
  Winkel einer Elipsenbahn messen und auswerten Nimes 2 304 09.09.2016 13:36
Letzter Beitrag: Nimes
  Modellzeit / Tag-Nacht Simulation auf einer Modellbahn MK.Matthias 14 3.652 23.05.2016 23:15
Letzter Beitrag: SkobyMobil
  Kettenoeler = EEPROM, serielle Kommunikation, externer Interrupt anwo 0 713 19.01.2016 12:21
Letzter Beitrag: anwo
  Terrarien Steuerung Lais1970 1 1.580 21.09.2015 16:04
Letzter Beitrag: hotsystems
  2 LEDs über serielle Schnittstelle steuern Bill 0 1.011 13.08.2015 16:04
Letzter Beitrag: Bill
  KFZ Steuerung mit Nfc nice123 7 2.386 07.08.2015 10:26
Letzter Beitrag: hotsystems
  Anfänger: Garten Beleuchtung + Steuerung CoreXY 13 4.490 14.07.2015 13:34
Letzter Beitrag: Hilgi

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste