Probleem met millis vertraging

Hallo allemaal,

Ik ben bezig om ledjes te laten schakelen als er op een knop gedrukt word.
Ze gaan met 2sec vertraging aan, tot zover werkt het goed, enkel als ik de knop even indruk en loslaat, gaan er maar 3 aan van de 4 en dan gaan ze allemaal ineen keer weer uit, maar dat zal ook te maken hebben met iets wat niet klopt in de code van de 'timer'.
Zodra de knop weer losgelaten word zouden ze met vertraging na elkaar uit moeten gaan, maar op een of andere manier krijg ik het niet werkend.
Ik heb al verschillende manieren geprobeerd met de millis, maar de juiste manier blijkbaar nog niet.
Is er iemand die me kan zeggen wat ik niet goed doe en waarom, en hoe ik het wel werkend zou kunnen krijgen?
Dankjewel alvast!

unsigned long previousMillis = 0;

const long TimerA = 5000UL;
const long TimerB = 10000UL;
const long TimerC = 15000UL;
const long TimerD = 20000UL;


const int button = 6;
const int led1 = 8;
const int led2 = 9;
const int led3 = 10;
const int led4 = 11;

int buttonState = 0;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(button, INPUT);
  


}

void loop() {
  
      buttonState = digitalRead(button);
  if (buttonState == HIGH) {
    
  digitalWrite(led1, HIGH);   
  delay(2000);              
  digitalWrite(led2, HIGH);
  delay(2000);
  digitalWrite(led3, HIGH);
  delay(2000);
  digitalWrite(led4, HIGH);
  

  }
  
  unsigned long currentMillis = millis();
  
  if (buttonState!= HIGH)  {

  
  if (currentMillis - previousMillis >= TimerA) {
  digitalWrite(led1, LOW);    // turn the LED off by making the voltage LOW
  }

  if (currentMillis - previousMillis >= TimerB) {
  digitalWrite(led2, LOW);
  }
  
  if (currentMillis - previousMillis >= TimerC) {
  digitalWrite(led3, LOW);
  }
  {
  if (currentMillis - previousMillis >= TimerD) {
  digitalWrite(led4, LOW);
  }

  }
  
  }

}

verlichting1.ino (1.15 KB)

Je vierde ledje gaat wel heel even aan, maar te kort om het te zien.
Neem na digitalWrite(led4, HIGH);
ook even een delay(2000) op en het werkt zoals je verwachtte.

edit:
Ik had iets te snel gekeken en daardoor niet helemaal je vraag begrepen.

maar als je aan het einde , vlak voor de laatste '}' de regel:
else { previousMillis = millis();}

opneemt lijkt het te werken zoals je beschrijft.
previousMillis kan geen 0 blijven maar moet 'meelopen' met de echte millis() en dus gelijk worden gemaakt aan het einde van de loop anders wordt nooit aan de voorwaarde voldaan om de LED's vertraagd uit te schakelen en worden ze direct uitgeschakeld.

Heel hartelijk bedankt!
Het werkt nu inderdaad zoals de bedoeling was.
Mijn bedoeling met deze code is om een tegelpad waar ik ledjes in wil plaatsen vanaf de straat tot mijn voordeur te schakelen.
Dus dat als het hek open gaat, de verlichting in stapjes aan gaat, en met vertraging uit, zodat er licht is om te lopen zolang het nodig is.

Dat laatste stukje code moet er in omdat de timer gewoon door loopt/op blijft tellen en er anders nooit meer een verschil kan zijn van het gewenste aantal seconden dat de ledjes aan moeten blijven?

MatthijsB:
Dat laatste stukje code moet er in omdat de timer gewoon door loopt/op blijft tellen en er anders nooit meer een verschil kan zijn van het gewenste aantal seconden dat de ledjes aan moeten blijven?

millis() is een unsigned long integer functie, 4 bytes dus 32 bits . millis() - Arduino Reference
dat betekent in normale taal:
2^32 = na 4.294.967.296 milliseconde loopt de teller over en begint weer op 0
4,3 miljoen seconden is ongeveer 50 dagen.
Dus een keer in de 50 dagen kun je onverwacht gedrag krijgen.
Met wat extra code is dit te omzeilen.
Ik zoek het wel even na.

edit:
De code in gedachten nog eens laten lopen:
na 49 dagen wordt het hek geopend en weer gesloten maar previousMillis wordt op die dag een heel groot getal.
Op dag 50 wordt het hek geopend, de LED's gaan branden en daarna wordt currentMillis gelijk gemaakt aan millis().
Maar de millis() is vanwege overflow weer op 0 begonnen, dus currentMillis wordt een klein getal.

De loop wordt steeds doorlopen en aan het begin wordt de buttonState gelezen.
Aan het einde staat "else { peviousMillis = millis(); } " en dit zorgt ervoor dat previousMillis altijd weer kleiner wordt dan currentMillis.
Dus er is nooit een probleem met deze code.

Heel hartelijk bedankt!
Nu is het nog even wachten tot de ledjes binnen zijn, en dan kan ik aan het spelen ermee.
Als het af is (en gelukt) zal ik hier een foto van het resultaat plaatsen.

In het begin keek ik nogal op tegen het coderen, maar nu ik er mee bezig ben valt het eigenlijk best wel mee.
Het is veel bekijken en proberen wat iets doet.
Enkel sommige dingen blijven lastig, maar gelukkig is er dit forum!

Hoi MatthijsB, welkom nog.

Het leukste is nog dat je straks die LEDjes ziet doen wat jij ze met je code vertelt te doen.
Je kunt met een handjevol LEDs, weerstanden en de Arduino heel veel doen.
Nog een potmetertje erbij, weer allemaal leuks.
Zijn hele kleine variaties op het voorbeeld dat je hebt genomen, maar van die variaties leer je ontzettend veel.
Vooral als ze juist niet doen wat je bedacht had.

Met dat handjevol onderdelen en wat code kun je dus veel leuke (maar verder vrij nutteloze) dingen doen, waarbij je stiekem een hoop leert.

Veel plezier.

Dankjewel MAS3!

Ik heb inmiddels in korte tijd al het een en ander in elkaar gezet en gecodeerd, een hoop dingen lijken best simpel maar als ik ze uitvoer werkt er vaak iets niet of net anders dan ik verwacht had.
Door meerdere projectjes te maken komt er zo nu en dan een pling in mijn hoofd waarbij ik denk, dit stukje code moet ik gebruiken bij een ander project, dan zal het moeten werken.
Soms is dat ook het geval, maar niet altijd.

Nu ben ik wat verder gegaan met dit led projectje, ik wilde dat als het hek van het tuinpad open ging, de ledjes sectie voor sectie aan zouden gaan, en na een bepaalde tijd weer uit.
Toen kreeg ik het idee om het zo te maken dat als ik de deur open zou doen, dat de ledjes dan ook aan zouden gaan, enkel in omgekeerde volgorde.
Zo gezegd zo gedaan, enkel werkt het weer eens niet zoals gepland.
Als ik op de "button" knop druk, gaan de ledjes keurig aan en na een bepaalde tijd weer uit.
Druk ik op de "buttond" dan gebeurd er helemaal niks.
De knopjes werken beide prima, dus ergens in de code zal ik iets niet helemaal goed hebben staan, maar ik zie niet in wat dat is.

unsigned long previousMillis = 0;
unsigned long previousMillisd = 0;

const long TimerA = 5000UL;
const long TimerB = 10000UL;
const long TimerC = 15000UL;
const long TimerD = 20000UL;

const int buttond = 5;
const int button = 6;
const int led1 = 8;
const int led2 = 9;
const int led3 = 10;
const int led4 = 11;

int buttonState = 0;
int buttonStated = 0;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(button, INPUT);
  pinMode(buttond, INPUT);


}

void loop() {
  {
      buttonState = digitalRead(button);
  if (buttonState == HIGH) {
    
  digitalWrite(led1, HIGH);   
  delay(2000);              
  digitalWrite(led2, HIGH);
  delay(2000);
  digitalWrite(led3, HIGH);
  delay(2000);
  digitalWrite(led4, HIGH);
  delay(2000);

  }
  
  unsigned long currentMillis = millis();
  
  if (buttonState!= HIGH)  {

  
  if (currentMillis - previousMillis >= TimerA) {
  digitalWrite(led1, LOW);    // turn the LED off by making the voltage LOW
  }

  if (currentMillis - previousMillis >= TimerB) {
  digitalWrite(led2, LOW);
  }
  
  if (currentMillis - previousMillis >= TimerC) {
  digitalWrite(led3, LOW);
  }
  {
  if (currentMillis - previousMillis >= TimerD) {
  digitalWrite(led4, LOW);
  }

  }
  
  }
  else { previousMillis = millis();}
  return; 
  }
  
  {
        buttonState = digitalRead(buttond);
  if (buttonState == HIGH) {
    
  digitalWrite(led4, HIGH);   
  delay(2000);              
  digitalWrite(led3, HIGH);
  delay(2000);
  digitalWrite(led2, HIGH);
  delay(2000);
  digitalWrite(led1, HIGH);
  delay(2000);

  }
  
  unsigned long currentMillisd = millis();
  
  if (buttonState != HIGH)  {

  
  if (currentMillisd - previousMillisd >= TimerA) {
  digitalWrite(led4, LOW);    // turn the LED off by making the voltage LOW
  }

  if (currentMillisd - previousMillisd >= TimerB) {
  digitalWrite(led3, LOW);
  }
  
  if (currentMillisd - previousMillisd >= TimerC) {
  digitalWrite(led2, LOW);
  }
  {
  if (currentMillisd - previousMillisd >= TimerD) {
  digitalWrite(led1, LOW);
  }

  }
  
  }
  
  
  
else { previousMillisd = millis();}
return;
  }

}

Probeer het eens zonder de twee regels ' return; ' .

Ook heb je te veel accolades in het programma staan, die maken het nogal onoverzichtelijk.
In het bijzonder de extra accolades rond de beide constructies

  {
  if (currentMillis - previousMillis >= TimerD) {
  digitalWrite(led4, LOW);
  }

Ik zou de loop van je oorspronkelijke programma zo opschrijven.

void loop() 
{  
  buttonState = digitalRead(button);   //  kijkt naar het hek HIGH=open LOW=dicht
  if (buttonState == HIGH)          // hek open
  {
    digitalWrite(led1, HIGH);   
    delay(2000);              
    digitalWrite(led2, HIGH);
    delay(2000);
    digitalWrite(led3, HIGH);
    delay(2000);
    digitalWrite(led4, HIGH);
  }
  
  unsigned long currentMillis = millis();

  if (buttonState == LOW)    // hek dicht
  { 
    if (currentMillis - previousMillis >= TimerA) digitalWrite(led1, LOW); 
    if (currentMillis - previousMillis >= TimerB) digitalWrite(led2, LOW); 
    if (currentMillis - previousMillis >= TimerC) digitalWrite(led3, LOW); 
    if (currentMillis - previousMillis >= TimerD) digitalWrite(led4, LOW); 
  }
  else  { peviousMillis = millis();  }  
}

Het doet exact hetzelfde alleen is er een berg accolades weggelaten . Ook de accolades rond

" if (currentMillis - previousMillis >= TimerA) digitalWrite(led1, LOW); "

mogen weggelaten worden omdat er maar een enkele opdracht achter de if (voorwaarde == ZusOfZo) statement staat.
Alleen als er meerdere opdrachten na een if-statement moeten worden uitgevoerd zijn de accolades verplicht.
De return is sowieso overbodig en in dit geval verstorend. Als je een return gebruikt is het meestal aan het einde van een routine en niet middenin.

een syntaxfoutjes uit de code gehaald.

Die 2 regels return had ik er eerst niet in, omdat het niet werkte dacht ik dat het misschien met return erbij wel zou werken omdat ik in een andere code de return tegen kwam en die ongeveer net zo'n functie had als deze code.
Maar helaas bleek dat niet de oplossing.

Ik heb inderdaad veel { } erin zitten, dat was me ook al opgevallen, dat moest ik nog een beetje opschonen, enkel leek het me handig het eerst werkend te krijgen en dan pas weer zulke aanpassingen eraan te gaan doen.
Ook is het me nog niet helemaal duidelijk wanneer ik wel en wanneer ik niet een stuk code tussen { } moet zetten.
In elk geval moet het uitvoerende gedeelte achter de if tussen {}, verder is het me niet helemaal duidelijk.

Misschien zou je eens wat meer energie moeten steken in de basis van C en C++? Tutorials zat te vinden. Daarnaast is er een functie in de IDE om je source te formatteren zodat het wat meer leesbaar wordt.

MatthijsB:
Ook is het me nog niet helemaal duidelijk wanneer ik wel en wanneer ik niet een stuk code tussen { } moet zetten.
In elk geval moet het uitvoerende gedeelte achter de if tussen {}, verder is het me niet helemaal duidelijk.

Als er maar een enkele opdracht achter een IF-statement of ELSE-statement staat dan zijn de accolades niet verplicht maar wel toegestaan ter verduidelijking.
De accolades maken duidelijk dat een aantal opdrachten bijelkaar hoort en dus allemaal uitgevoerd moeten worden. Bij een enkele opdracht vervalt de noodzaak van accolade gebruik.

cartoonist:
Als er maar een enkele opdracht achter een IF-statement of ELSE-statement staat dan zijn de accolades niet verplicht maar wel toegestaan ter verduidelijking.
De accolades maken duidelijk dat een aantal opdrachten bijelkaar hoort en dus allemaal uitgevoerd moeten worden. Bij een enkele opdracht vervalt de noodzaak van accolade gebruik.

Zelf ben ik een voorstander om consequent accolades te gebruiken. En dat dateert al uit mijn PL/1 tijd :). Dan hoef je ook nooit na te denken :grin: Maar ieder zijn keus. compiler technisch zal het weinig tot niets uitmaken omdat die toch wel gaat optimaliseren.

nicoverduin:
Misschien zou je eens wat meer energie moeten steken in de basis van C en C++? Tutorials zat te vinden. Daarnaast is er een functie in de IDE om je source te formatteren zodat het wat meer leesbaar wordt.

Zeker aan te raden voor diegenen die wat serieuzer willen programmeren. maar niet iedereen voelt zich aangetrokken tot de nogal saaie literatuur can de C-programmeertaal.

Het raadplegen van de Reference-HomePage is in de meeste gevallen meer dan voldoende voor het juiste gebruik van de Arduino variant van de C-taal.

Nadeel voor sommigen is dat deze pagina's in het engels zijn.
Deze kunnen een beknopte NL-referentie vinden op: http://www.kompanje.nl/arduino/Arduino%20manual%201_0%20NL.pdf

nicoverduin:
Zelf ben ik een voorstander om consequent accolades te gebruiken. En dat dateert al uit mijn PL/1 tijd :). Dan hoef je ook nooit na te denken :grin: Maar ieder zijn keus. compiler technisch zal het weinig tot niets uitmaken omdat die toch wel gaat optimaliseren.

Is zo, maar een enkele keer laat ik de accolades wel eens weg achter een voorwaardelijke opdracht.
Misschien niet consequent maar ja .... mensen zijn geen computers

De basis van C en C++ heb ik wel geprobeerd, maar dat krijg ik er niet in door middel van tutorials. Op de een of andere manier blijft het niet hangen dan, of het dringt niet goed genoeg door waarvoor of waarom iets zo werkt als omschreven, ik weet niet precies wat het is.
Ik leer dingen vaak door te doen en te proberen en vooral door te kijken hoe codes in elkaar zitten en wat wat doet. Door code's te zoeken bij wat ik van plan ben en daar delen uit over te nemen en eventueel aan te passen, komt de kennis er wel in. De dingen die ik niet begrijp zoek ik zoveel mogelijk op. Net zoals het millis verhaal, dat heb ik gemaakt door te zoeken hoe dat werkte, maar daar had ik niet bij gevonden dat je previous millis gelijk moest maken aan millis om het geheel werkende te krijgen.

Dat is duidelijk Cartoonist, dat scheelt inderdaad een heleboel {} in de code.

Ik heb de {} nu dus verwijderd en de returns, en nu werkt mijn 2e knopje in elk geval wel, maar nu gaan de leds bij het knopje dat goed werkte na 1 seconde allemaal ineens uit en bij het 2e knopje gaan ze uit in een vreemde volgorde, eerst links dan rechts dan de middelste 2.

MatthijsB:
De basis van C en C++ heb ik wel geprobeerd, maar dat krijg ik er niet in door middel van tutorials. Op de een of andere manier blijft het niet hangen dan, of het dringt niet goed genoeg door waarvoor of waarom iets zo werkt als omschreven, ik weet niet precies wat het is.

Het valt me altijd weer op dat ik hier nog nooit een vraag heb gezien over de tutorials.....

Ik zei ook niet dat ik het niet begreep, het blijft op die manier niet hangen bij mij.
Als ik met zo'n tutorial bezig ben, en heb ook wel een online cursus gedaan, dan gaat het prima, maar blijkbaar dringt het op die manier niet goed door bij me.
Vroeger op school had ik daar ook altijd al moeite mee.
Ik kan heel veel dingen, maar ik kan ze niet leren zoals de meeste mensen dat doen en kunnen.

De basiskennis van veel dingen heb ik geleerd in de praktijk door dingen te gaan maken en te kijken wat er fout en goed ging en te kijken waarom dingen zo werken als ze doen.