Leidiges Thema millis()

Servus, ich schon wieder :sweat_smile:
Kann mir mal jemand erklären wo hier der Fehler liegt? Ich will drei leds in unterschiedlichen abständen Blinken lassen. Mal funktioniert es, und mal blitzt die led nur ganz leicht und kurz auf. WAAAARUUUUM?? Hab auch schon mehrmals alles neu verkabelt und an UNO und NANO getestet. Häng da jetz schon ewig dran :roll_eyes:

int ledgruen = 2;
int ledgelb = 3;
int ledrot = 4;
int taster1 = 5;
int tasterst;
int intervall1 = 1000;
int intervall2 = 3000;
int intervall3 = 2000;
int intervall4 = 5000;
int intervall5 = 3000;
int intervall6 = 3000;
unsigned long vergmillis1;
unsigned long vergmillis2;
unsigned long vergmillis3;
unsigned long vergmillis4;
unsigned long vergmillis5;
unsigned long vergmillis6;
unsigned long aktmillis;



void setup() {

  pinMode (ledgruen, OUTPUT);
  pinMode (ledgelb, OUTPUT);
  pinMode (ledrot, OUTPUT);
  pinMode (taster1, INPUT);
  Serial.begin (9600);


}

void loop() {
  
aktmillis = millis();

ledgruenn();
ledgelbb(); 
ledrott();
}

void ledgruenn () {
  if (aktmillis-vergmillis1>=intervall1)
  {vergmillis1=aktmillis;
  digitalWrite (ledgruen, HIGH);}
  if (aktmillis-vergmillis2>=intervall2)
  {vergmillis2=aktmillis;
  digitalWrite (ledgruen,LOW);}
}
void ledgelbb () {
  if (aktmillis-vergmillis3>=intervall3)
  {vergmillis3=aktmillis;
  digitalWrite (ledgelb, HIGH);}
  if (aktmillis-vergmillis4>=intervall4)
  {vergmillis4=aktmillis;
  digitalWrite (ledgelb,LOW);}
}
void ledrott () {
  if (aktmillis-vergmillis5>=intervall5)
  {vergmillis5=aktmillis;
  digitalWrite (ledrot, HIGH);}
  if (aktmillis-vergmillis6>=intervall6)
  {vergmillis6=aktmillis;
  digitalWrite (ledrot,LOW);}
}

probier mal so:

void ledgruenn () {
  if (digitalRead(ledgruen) == LOW && aktmillis - vergmillis1 >= intervall1)
  { 
    vergmillis1 = aktmillis;
    digitalWrite (ledgruen, HIGH);
  }
  if (digitalRead(ledgruen) == HIGH && aktmillis - vergmillis1 >= intervall2)  // gleiche Zeitstempel nur der intervall ist anders...
  { vergmillis1 = aktmillis;
    digitalWrite (ledgruen, LOW);
  }
}

entspricht das eher dem was du dir vorstellst?

Nach Deiner Logik gewinnt immer das kürzere Intervall. @noiasca zeigt wie man es besser machen kann.

Weil Du was falsch machst. :wink:
Du kommst ständig in den Bereich, wo sich beide Intervalle überschneiden.

    if (aktmillis - vergmillis2 >= intervall2)
    {
      vergmillis2 = aktmillis;
// und 
    if (aktmillis - vergmillis1 >= intervall1)
    {
      vergmillis1 = aktmillis;

Kleinstes gemeinsames Vielfache - es blitzt.

Mal umgebaut:
Edit: Mir ist da die LED weggeraten...

void ledgruenn ()
{
  if (digitalRead(ledgruen)) // Wenn HIGH
  {
    if (aktmillis - vergmillis1 >= intervall2)
    {
      vergmillis2 = aktmillis;
      digitalWrite (ledgruen, LOW);
    }
  }
  else
  {
    if (aktmillis - vergmillis1 >= intervall1)
    {
      vergmillis1 = aktmillis;
      digitalWrite (ledgruen, HIGH);
    }
  }
}

Also die Variante mit der Abfrage von noiasca hat nicht funktioniert. Habs jetzt so gemacht wie my xy projekt. Aaaaaber warum leuchtet jetz die rote led dauerhaft?? Ich checks nicht :smirk:

int ledgruen = 2;
int ledgelb = 3;
int ledrot = 6;
int taster1 = 5;
int tasterst;
int intervall1 = 1000;
int intervall2 = 3000;
int intervall3 = 2000;
int intervall4 = 5000;
int intervall5 = 3000;
int intervall6 = 3000;
unsigned long vergmillis1;
unsigned long vergmillis2;
unsigned long vergmillis3;
unsigned long vergmillis4;
unsigned long vergmillis5;
unsigned long vergmillis6;
unsigned long aktmillis;



void setup() {

  pinMode (ledgruen, OUTPUT);
  pinMode (ledgelb, OUTPUT);
  pinMode (ledrot, OUTPUT);
  pinMode (taster1, INPUT);
  Serial.begin (9600);


}

void loop() {
  
aktmillis = millis();

ledgruenn();
ledgelbb(); 
ledrott();
}

void ledgruenn () {
  if (aktmillis-vergmillis1>=intervall1)
  {vergmillis1=aktmillis;
  digitalWrite (ledgruen, LOW);}
  if (aktmillis-vergmillis2>=intervall2)
  {vergmillis2=aktmillis;
  digitalWrite (ledgruen,HIGH);}
}
void ledgelbb () {
  if (aktmillis-vergmillis3>=intervall3)
  {vergmillis3=aktmillis;
  digitalWrite (ledgelb, LOW);}
  if (aktmillis-vergmillis4>=intervall4)
  {vergmillis4=aktmillis;
  digitalWrite (ledgelb,HIGH);}
}
void ledrott () {
  if (aktmillis-vergmillis5>=intervall5)
  {vergmillis5=aktmillis;
  digitalWrite (ledrot, LOW);}
  if (aktmillis-vergmillis6>=intervall6)
  {vergmillis6=aktmillis;
  digitalWrite (ledrot,HIGH);}
}

Weil beide Bedingungen gleichzeitig wahr sind. Die zuletzt ausgeführte schaltet die LED ein.

const byte ledgruen = 2;
const byte ledgelb = 3;
const byte ledrot = 6;
const byte taster1 = 5;
int tasterst;
const unsigned long intervall1 = 1000;
const unsigned long intervall2 = 3000;
const unsigned long intervall3 = 2000;
const unsigned long intervall4 = 5000;
const unsigned long intervall5 = 3000;
const unsigned long intervall6 = 3000;
unsigned long vergmillis1;
unsigned long vergmillis2;
unsigned long vergmillis3;
unsigned long vergmillis4;
unsigned long vergmillis5;
unsigned long vergmillis6;
unsigned long aktmillis;



void setup()
{
  Serial.begin (115200);
  Serial.println(F("Start..."));
  digitalWrite(ledgruen, LOW);
  digitalWrite(ledgelb, LOW);
  digitalWrite(ledrot, LOW);
  pinMode (ledgruen, OUTPUT);
  pinMode (ledgelb, OUTPUT);
  pinMode (ledrot, OUTPUT);
  pinMode (taster1, INPUT);
}

void loop()
{
  aktmillis = millis();
  ledgruenn();
  ledgelbb();
  ledrott();
}

void ledgruenn ()
{
  if (digitalRead(ledgruen))
  {
    if (aktmillis - vergmillis1 >= intervall1)
    {
      vergmillis2 = aktmillis;
      digitalWrite (ledgruen, LOW);
      Serial.print(aktmillis);
      Serial.println(F(" gruen aus"));
    }
  }
  else
  {
    if (aktmillis - vergmillis2 >= intervall2)
    {
      vergmillis1 = aktmillis;
      digitalWrite (ledgruen, HIGH);
      Serial.print(aktmillis);
      Serial.println(F(" gruen an"));
    }
  }
}

void ledgelbb ()
{
  if (digitalRead(ledgelb))
  {
    if (aktmillis - vergmillis3 >= intervall3)
    {
      vergmillis4 = aktmillis;
      digitalWrite (ledgelb, LOW);
      Serial.print(aktmillis);
      Serial.println(F(" gelb aus"));
    }
  }
  else
  {
    if (aktmillis - vergmillis4 >= intervall4)
    {
      vergmillis3 = aktmillis;
      digitalWrite (ledgelb, HIGH);
      Serial.print(aktmillis);
      Serial.println(F(" gelb an"));
    }
  }
}

void ledrott ()
{
  if (digitalRead(ledrot))
  {
    if (aktmillis - vergmillis5 >= intervall5)
    {
      vergmillis6 = aktmillis;
      digitalWrite (ledrot, LOW);
      Serial.print(aktmillis);
      Serial.println(F(" rot aus"));
    }
  }
  else
  {
    if (aktmillis - vergmillis6 >= intervall6)
    {
      vergmillis5 = aktmillis;
      digitalWrite (ledrot, HIGH);
      Serial.print(aktmillis);
      Serial.println(F(" rot an"));
    }
  }
}
Start...
3000 gruen an
3000 rot an
4000 gruen aus
5000 gelb an
6000 rot aus
7000 gruen an
7000 gelb aus
8000 gruen aus
9000 rot an
11000 gruen an
12000 gruen aus
12000 gelb an
12000 rot aus
14000 gelb aus
15000 gruen an
15000 rot an
16000 gruen aus
18000 rot aus
19000 gruen an
19000 gelb an
20000 gruen aus
21000 gelb aus
21000 rot an
23000 gruen an
24000 gruen aus
24000 rot aus
26000 gelb an
27000 gruen an
27000 rot an
28000 gruen aus
28000 gelb aus
30000 rot aus
31000 gruen an
32000 gruen aus

Die Zahl gibt die Zeit in ms wieder.

Nein. @my_xy_projekt prüft zusätzlich, ob aktuell die LED an ist oder nicht.

Dies tust du nicht.

Ich möchte mich an dieser Stelle auch wieder gegen extensive if Konstruktionen aussprechen!

// die CombieLib.zip findest du im Form mit der Suche
#include <TaskMacro.h>
#include <CombiePin.h>


template<uint8_t led, unsigned long leuchtdauer,unsigned long pausedauer>
Task blink()
{
  taskBegin();
  Combie::Pin::OutputPin<led>{}.init();
  while(1)
  {
    Combie::Pin::OutputPin<led>{} = 1;
    taskPause(leuchtdauer);
    Combie::Pin::OutputPin<led>{} = 0;
    taskPause(pausedauer);
  }
  taskEnd();
}



void setup() 
{
}

void loop() 
{
 blink<2,1000,3000>();
 blink<3,2000,5000>();
 blink<4,3000,3000>();
}

da war eine Klammer falsch. ist jetzt richtig gestellt.

@combie: schön kompakt

Da haste jetzt ordentlich Tipparbeit gespart. Wie wäre es die eingesparte Tipparbeit in anfängerfreundliche Dokumentation zu stecken? Du sollst sie auch nicht vorlesen sondern schreiben. Wenn es einen Link gibt wo das schon steht dann wäre das ja auch schnell erledigt.
vgs

Meine Lösung ist nicht so kompakt wie die von Combie. viele If-Anweisungen.
Da könnte man jetzt argumentieren auch eine Lernmethode

Und um bei Combie durchzusteigen lernt man auch ordentlich was

const byte ledgruen_pin = 2;
const byte ledgelb_pin  = 3;
const byte ledrot_pin   = 6;
const byte taster1_pin  = 5;
int tasterst;

unsigned long ledGruenOn  = 100;
unsigned long ledGruenOff = 300;

unsigned long ledGelbOn   = 200;
unsigned long ledGelbOff  = 500;

unsigned long ledRotOn    = 300;
unsigned long ledRotOff   = 301;

unsigned long warteZeitGruen = ledGruenOn;
unsigned long warteZeitGelb  = ledGelbOn;
unsigned long warteZeitRot   = ledRotOn;

unsigned long TimerGruen;
unsigned long TimerGelb;
unsigned long TimerRot;

// helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

void setup() {
  pinMode (ledgruen_pin, OUTPUT);
  pinMode (ledgelb_pin, OUTPUT);
  pinMode (ledrot_pin, OUTPUT);
  pinMode (taster1_pin, INPUT);
  Serial.begin (115200);
}


void ledGruen() {
  if ( TimePeriodIsOver(TimerGruen,warteZeitGruen) ) {

    if (warteZeitGruen == ledGruenOn) {
      digitalWrite(ledgruen_pin,LOW);
      warteZeitGruen = ledGruenOff;
    }
    else {
      digitalWrite(ledgruen_pin,HIGH);
      warteZeitGruen = ledGruenOn;
    }
  }
}

void ledGelb() {
  if ( TimePeriodIsOver(TimerGelb,warteZeitGelb) ) {
    
    if (warteZeitGelb == ledGelbOn) {
      digitalWrite(ledgelb_pin,LOW);
      warteZeitGelb = ledGelbOff;
    }
    else {
      digitalWrite(ledgelb_pin,HIGH);
      warteZeitGelb = ledGelbOn;
    }
  }
}

void ledRot() {
  if ( TimePeriodIsOver(TimerRot,warteZeitRot) ) {
    
    if (warteZeitRot == ledRotOn) {
      digitalWrite(ledrot_pin,LOW);
      warteZeitRot = ledRotOff;
    }
    else {
      digitalWrite(ledrot_pin,HIGH);
      warteZeitRot = ledRotOn;
    }
  }
}


void loop() {
  ledGruen();
  ledGelb();
  ledRot();
}

Naja...

Zu beiden Libs gibts hier Threads.
Des weiteren sind die Libs mit Beispielen geflutet.
Eine hat gar eine Readme.md

Hast du ein Talent für schöne/verständliche Dokus?

@benjixx
wenn du magst, kannst du zum Blinken auch eine Library verwenden:

/*
  https://forum.arduino.cc/t/leidiges-thema-millis/961953
  by noiasca
*/

#include <Noiasca_led.h>   // download library from http://werner.rothschopf.net/microcontroller/202202_tools_led_en.htm
BlinkPin ledgruen {2};     // declare blinking LED and assign a pin
BlinkPin ledgelb {3};      
BlinkPin ledrot {4};       

void setup() {
  ledgruen.begin();   // you have to call the .begin() method for each LED object
  ledgelb.begin();
  ledrot.begin();
  // you can set different blink intervals for your LEDs
  ledgruen.setOnInterval(1000);
  ledgruen.setOffInterval(3000);
  ledgelb.setOnInterval(2000);
  ledgelb.setOffInterval(5000);
  ledrot.setOnInterval(3000);
  ledrot.setOffInterval(3000);
}

void loop() {
  ledgruen.update();       // you have to call update() for each LED object
  ledgelb.update();
  ledrot.update();
}

möglicherweise kommen später noch Taster dazu, dann könntest das Blinken relativ einfach ein/ausschalten:

  //ledgruen.off(); // zum Abschalten des Blinken, z.B. wenn später mal ein Taster dazukommen soll.
  //ledgruen.on();  // zum wieder Einschalten des Blinken
  //ledgruen.toggle(); // zum Umschalten - weitere Funktionen siehe Beschreibungslink

Zu finden gibts die Library hier: Noiasca Took Kit for LEDs

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.