Blinkende LED und Farbwechsel in einem Sketch

Hallo,
auf die Gefahr hin, dass jemand mit Standardantworten kommt wie "lies mal hier, lies mal da", habe ich eine gewisse Verständnisblockade bezüglich der Zusammenfassung von Sketchen. Aufgabenstellung ist bei einem Nano folgende: an den Ausgängen 5,6 und 9 ist eine RGB-LED angeschlossen, die über einen Farbwechselsketch zwischen verschiedenen Farben sanft wechselt. Einen solchen Sketch habe ich auch gefunden und delay() gegen millis () getauscht. Funktioniert. Jetzt soll die interne LED einen Herzschlag simulieren. Auch dafür habe ich einen passenden Sketch gefunden. Auch da habe ich ein delay gegen millis getauscht. Funktioniert. Dann habe ich beide Sketche kombiniert und kompiliert, so wie es in der einen oder anderen "Anleitung" steht. Jetzt funktioniert nur der Farbwechsel, aber nicht der Herzschlag. Setzte ich // vor den Farbwechsel, funktioniert der Herzschlag (logisch, weil Farbwechsel ist ja deaktiviert). Die Beispiele für zwei "parallele" Abläufe beziehen sich immer nur auf zwei LED und nicht auf Ansteuerungen allgemein. Zum allgemeinen Verständnis: es handelt sich um eine Halloween-Deko; ein Skelett hat RGB-LED als Augen und der Nano sitz in der Brust und leuchtet in einem freundlichem Rot (Betriebs-LED). Jetzt soll die interne LED den Effekt eines schlagenden Herzens simulieren. Anbei der Code, vielleicht kann mir da jemand auf die Sprünge helfen.....

const int rotPin = 5;
const int gruenPin = 6;
const int blauPin = 9;
const int herz = LED_BUILTIN;
unsigned long lmillis;
const long interval = 1000;

byte i = 0;
boolean up = true;
byte Fadearray[] = {
  0, 2, 4, 8, 12, 20, 32, 44, 56, 68, 80, 92, 104, 116, 128, 140,
  152, 164, 176, 188, 200, 212, 224, 236, 255, 240, 210, 180, 150,
  120, 90, 60, 40, 25, 25, 40, 60, 90, 120, 150, 180, 210, 240, 255,
  230, 205, 180, 155, 130, 105, 80, 55, 30, 20, 16, 8, 4, 2, 0,
};

int r = 0;
int g = 0;
int b = 0;

void setup() {
  pinMode(rotPin, OUTPUT);
  pinMode(gruenPin, OUTPUT);
  pinMode(blauPin, OUTPUT);
  pinMode(herz, OUTPUT);
}


void loop() {
  herzschlag();
  farbwechsel();
}

void herzschlag() {
  if (millis() - lmillis >= 11) {
    if (i == 58) {
      up = false;
      unsigned long lMillis = millis();
      while (millis() - lMillis < 650)
        //delay(600);
        i = 0;
    }
    i++;
    analogWrite(13, Fadearray[i]);
    lmillis = millis();
  }
}

void farbwechsel() {
  for (b = 0; b < 100; b++) {
    analogWrite(blauPin, b);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }

  for (r = 0; r < 100; r++) {
    analogWrite(rotPin, r);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }

  for (b = 100; b > 0; b--) {
    analogWrite(blauPin, b);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }

  for (g = 0; g < 100; g++) {
    analogWrite(gruenPin, g);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }

  for (r = 100; r > 0; r--) {
    analogWrite(rotPin, r);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }

  for (b = 0; b < 100; b++) {
    analogWrite(blauPin, b);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }

  for (g = 100; g > 0; g--) {
    analogWrite(gruenPin, g);
    unsigned long lMillis = millis();
    while (millis() - lMillis < 50)
      ;
  }
}

Du hast delay() nachgebaut... Damit du 2 Dinge "gleichzeitig" machen kannst, muss dein Code non-blocking sein.

Hier mal ein Beispiel wie man 2 LEDs unterschiedlich blinken lassen könnte:

auto start1 = millis();
auto start2 = millis();

void loop(){
  now = millis();
  
  dx = now - start1;
  on = dx < 500;
  digitalWrite(LED1, on)
  if(dx > 1000) {
    start1 = now;
  }

  dx = now - start2;
  dx = dx / 100;
  analogWrite(LED2, dx);
  if (dx >= 255){
    start2 = now;
  }
}

Auch die for-Schleifen sind blockierend.

Vielleicht hilft dies deinem Verständnis. Dein Code wird Zeile für Zeile ausgeführt. Geh mal deinen Code durch, und schau mal, wann du Herzschlag ausführst. Du wirst feststellen, das Herzschlag erst zum zweiten mal ausgeführt wird, wenn Farbwechsel einmal komplett durchlaufen ist. Farbwechsel blockiert sozusagen den Programmfluss. Dieses blockieren musst du also aufheben. (Herzschlag blockiert auch)

void heartBeat(const uint8_t LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (setUp == false) pinMode (LedPin, OUTPUT), setUp = true;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
void setup()
{

}
void loop()
{
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
}

Das tut man nicht.
Macht derbe Jitter im Überlaufbereich.
Siehe: [Bericht] Der (Millis) Ueberlauf im Test

Wurde schon kritisiert.

Das kann man ändern.
z.B. [Projekt] Multitasking

Muss man nach 49,x Tagen höllisch aufpassen, dass man die einmalige Herzrhythmusstörung auch mitkriegt.

Mich stört eher, dass man der Funktion die aktuellen millis als Parameter mitgeben muss.
Da die Funktion "heartbeat" heißt und die Frequenz nicht veränderbar ist, hätte ich wegen "small is beautiful"
digitalWrite (ledPin, (bool) (millis() & 0x400));
geschrieben. Oder das an/aus-Verhältnis hübscher als die langweiligen 1:1 gestaltet.

digitalWrite (ledPin, !(millis() & 0x700));
Ob man das nichtblockierende Programmieren einfach von Hand oder durch Verwendung entsprechender Bibliotheken macht, ist mMn Geschmackssache.

1 Like

Schreiner Spruch:
Wenn du irgendwann mal irgendwas drei mal machst, dann bau eine Schablone.

In unserem Fall: Eine Bibliothek!

Soweit zum Allgemeinen, jetzt zum Persönlichen!

Hält man sich an das BlinkWithoutDelay Beispiel, was (eigentlich) auch gut und richtig ist, dann wird der Quellcode mit solchen Statements geflutet:

if(millis() - gemerkteZeit >= wunschLaufzeit)
{
  // tuwas
  gemerkteZeit = millis();
}

Die Wurst ist total korrekt.
Aber dennoch unangenehm, da mit viel Schreibarbeit verbunden.
Es schleichen sich schnell Copy+Paste Fehler ein.
Der Quellcode des Projektes wird recht unübersichtlich. Um so schlimmer, je öfter das Konstrukt darin vorkommt.

Natürlich hat jeder seine eigenen Vorstellungen...
Ich selber habe keinen Bock mehr die Wurst zu schreiben/warten.
Null, Komma gar nicht.

Wann man das jedes mal händisch macht, wird es unübersichtlich, fehlerträchtig, und was weiß ich noch alles....

Prinzip: DRY
(dont repeat yourself)

Total menschlich!
Tausendfach im praktischen Beispiel.
Einmal ein falsches Prinzip gelernt, ist es kaum noch auszurotten,
Einmal falsch angewendet, macht das Getriebe Späne, fährt das Auto vor die Wand und die Rakete plumpst in die Stadt.
Und sei es nur, dass die Blumengießanlage im Urlaub 3 Etagen flutet.

Wenn man weiß, wie es richtig geht, sollte man solche Fallen meiden.
Mein Rat:
Einmal tun, um den Fehler zu spüren, danach meiden, wie der Teufel das Weihwasser.

Bei einer Status LED vermutlich irrelevant. Bei einem Schrittmotor der einen Wagen in den Endstopp knallt vermutlich sehr fies zu debuggen.

da passt was nicht.
Angenommen du bist auf einem Arduino UNO.
Dann ist die interne LED auf 13
13 ist kein PWM fähiger Ausgang und dann macht deine ganze Fading-Tabelle und diese Zeile

 analogWrite(13, Fadearray[i]);

keinen Sinn mehr *)
Warum willst du einen reinen digitalAusgang "faden"?

UNO (R3 and earlier), Nano, Mini PWM Pins: 3, 5, 6, 9, 10, 11

oder welchen Microcontroller hast du genau?

Sinn machen würde eine Fading-Tabelle für die RGB LED.
Dort verwendest du es aber nicht - sonder da nimmst du hart Werte 0-100.

Wow, nettes Feedback. Danke erstmal für die Hilfe. Der Einwand mit der internen LED und PWM ist berechtigt. Die interne "blinkt nur" im Herzschlag. Habe das ganze jetzt mal auf einen PWM-Ausgang geschaltet und dort sieht man natürlich das Fading. Ich werde diesen Part anders lösen, so das die interne LED "digital" angesteuert wird, dürfte für diesen Zweck ausreichen. Eure anderen Tipps werde ich mir mal zu Gemüte führen und mich da durchkämpfen. Danke nochmals und schönen Abend noch...

sag noch was zum Faden der RGB LED.
Warum machst du das linear von 0 - 100 und nicht über die Fading-Tabelle?

Manche Termine rücken gnadenlos näher, da könnte Dein Durchkämpfen etwas spät kommen. Daher mal von mir ein

Notprogramm
const byte rotPin = 5;
const byte gruenPin = 6;
const byte blauPin = 9;
const byte herz = 10;
const byte fadearray[] = {
  0, 2, 4, 8, 12, 20, 32, 44, 56, 68, 80, 92, 104, 116, 128, 140,
  152, 164, 176, 188, 200, 212, 224, 236, 255, 240, 210, 180, 150,
  120, 90, 60, 40, 25, 25, 40, 60, 90, 120, 150, 180, 210, 240, 255,
  230, 205, 180, 155, 130, 105, 80, 55, 30, 20, 16, 8, 4, 2, 0,
};
const byte f_max = sizeof(fadearray);
byte i = 0;
unsigned long herzMillis, farbMillis;

byte r = 0;
byte g = 11;
byte b = 25;

void setup() {
  pinMode(rotPin, OUTPUT);
  pinMode(gruenPin, OUTPUT);
  pinMode(blauPin, OUTPUT);
  pinMode(herz, OUTPUT);
}

void loop() {
  herzschlag();
  farbwechsel();
}

void herzschlag() {
  if (millis() - herzMillis >= 11) {
    if (i < f_max) {
      i++;
    } else {
      i = 0;
    }
    analogWrite(herz, fadearray[i]);
    herzMillis = millis();
  }
}

void farbwechsel() {
  if (millis() - farbMillis > 50) {
    if (r < f_max) {
      r++;
    } else {
      r = 0;
    }
    if (g < f_max) {
      g++;
    } else {
      g = 0;
    }
    if (b < f_max) {
      b++;
    } else {
      b = 0;
    }
    analogWrite(rotPin, fadearray[r]);
    analogWrite(gruenPin, fadearray[g]);
    analogWrite(blauPin, fadearray[b]);
    farbMillis = millis();
  }
}

Sei ein nettes Skelett :slightly_smiling_face:

1 Like

Hallo,
wenn Du doch ein bisschen lesen magst zum Verstehen dann hab ich was für Dich

Boa, Jungs (und/oder Mädels, Diverse(s), etc.), vielen Dank für Eure Hilfe.
@agmue: ja, ist knapp. Werde es aus beruflichen Gründen nicht schaffen, jetzt noch was zu ändern, aber nächstes Jahr ist auch wieder Halloween. Die Idee kam auch relativ spontan. Jetzt habe ich ein Skelett mit einem permanent roten Brustkorb (Betriebs-LED) und einem tollen Farbwechsel, dass mit dem Herzschlag wäre jetzt nochmal das i-Tüpfelchen gewesen. Da ich an den Nano nicht mehr so einfach dran komme, hatte ich die Idee mit der internen LED. Nenne es Detailverliebtheit, nenne es Irrsinn, ich habe Spaß an solchen Sachen. Sobald ich dazu komme, schaue ich mir dein Notprogramm an und gebe dir Rückmeldung. Vielen, vielen Dank für deine Hilfe, schönen Abend noch und bleibt gesund.....

Das wäre nett, meist sind solche Anfragen nur Eintagsfliegen.

Du ahnst sicherlich, da geht noch mehr! Spätestens, wenn Du zur Stromversorgung eine Autobatterie um den Hals baumeln hast, wird es richtig gruselig :rofl:

Ich bekomme Angst....

Was soll es für einen Sinn machen, einen > 1 Jahr alten Thread zu kapern, um einen Sketch haben zu wollen und dann auch noch zeitnah?

Gruß Tommy

Was soll hier diese BASHING?

Also meines Wissens nach sind Oktober 24 bis heute 4 Monate und nicht über ein Jahr.

Die Frage war wirklich ernst gemeint, habe aber dann den Post gelöscht als ich gesehen habe, dass die Lösung noch nicht gefunden war.

Da ich zu dem besprochen Thema eine Frage, handelt es sich nicht um ein Karpern.

Ich frage mich eh was dieser Ton soll, du hattest doch eh keinen Post in dem Thraed.

Aber das zeigt mir einfach einmal mehr das der Umgang immer Unterirdischer wird.

Mache einfach einen neuen Thread auf und stelle die Fragen zu deinem Projekt.

So kann dir geholfen werden.

Der Thread war offen.
@freewind65 suchte genau das als fertiges Produkt.
Nu denn.
Suchte.

ungefragt und ungetestet:

const int rotPin = 5;
const int gruenPin = 6;
const int blauPin = 9;
const int herz = LED_BUILTIN;
unsigned long lmillis;
const long interval = 1000;

byte i = 0;
boolean up = true;
byte Fadearray[] =
{
  0, 2, 4, 8, 12, 20, 32, 44, 56, 68, 80, 92, 104, 116, 128, 140,
  152, 164, 176, 188, 200, 212, 224, 236, 255, 240, 210, 180, 150,
  120, 90, 60, 40, 25, 25, 40, 60, 90, 120, 150, 180, 210, 240, 255,
  230, 205, 180, 155, 130, 105, 80, 55, 30, 20, 16, 8, 4, 2, 0,
};

uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;

uint32_t lastmillis;
uint32_t dimTime;
uint8_t step;

void setup()
{
  pinMode(rotPin, OUTPUT);
  pinMode(gruenPin, OUTPUT);
  pinMode(blauPin, OUTPUT);
  pinMode(herz, OUTPUT);
}


void loop()
{
  herzschlag();
  farbwechsel();
}

void herzschlag()
{
  if (i != 58)
  {
    if (millis() - lmillis >= 11)
    {
      i++;
      lmillis = millis();
    }
  }
  else if (millis() - lmillis >= 650)
  {
    i = 0;
    lmillis = millis();
  }
  analogWrite(13, Fadearray[i]);
}

void adding(uint8_t &pwm, const int8_t stepping)
{
  if (millis() - lastmillis > dimTime)
  {
    pwm += stepping;
    lastmillis += dimTime;
  }
}

void checking(const uint8_t &pwm, const uint8_t &endValue)
{
  if (pwm == endValue)
  { step++; }
}

void farbwechsel()
{
  switch (step)
  {
    case 0:
      b = 0;
      dimTime = millis();
      digitalWrite(blauPin, LOW);
      digitalWrite(rotPin, LOW);
      digitalWrite(gruenPin, LOW);
      step++;
      break;
    case 1:
      adding(b, 1);
      analogWrite(blauPin, b);
      checking(b, 100);
      break;
    case 2:
      adding(r, 1);
      analogWrite(rotPin, r);
      checking(r, 100);
      break;
    case 3:
      adding(b, -1);
      analogWrite(blauPin, b);
      checking(b, 0);
      break;
    case 4:
      adding(g, 1);
      analogWrite(gruenPin, g);
      checking(g, 100);
      break;
    case 5:
      adding(r, -1);
      analogWrite(rotPin, r);
      checking(r, 0);
      break;
    case 6:
      adding(b, 1);
      analogWrite(blauPin, b);
      checking(b, 100);
      break;
    case 7:
      adding(g, -1);
      analogWrite(gruenPin, g);
      checking(g, 0);
      break;
    default:
      step = 0;
      break;
  }
}

Mit dem entsprechenden Hinweis, dass die Onboardled nicht das macht, was sie soll.
Sobald der Pin 13 gegen einen mit PWM getauscht und dort eine LED angebastelt wird, sollte das gehen.

1 Like