Arduino Millis () 2x knipperen

Bij het opstarten van mijn Arduino wil ik een tweetal LEDs 2x kort laten knipperen.

Nu heb ik de volgende code (met daarachter nog een heel stuk, maar dat is voor deze vraag niet relevant).

c code:


int BG1_LED = 4;                     // StatusLED 1
int BG2_LED = 5;                     // StatusLED 2

void setup() {
    pinMode(BG1_LED, OUTPUT);
    pinMode(BG2_LED, OUTPUT);

// ------------knipperen LED's bij opstarten-------------------

      digitalWrite(BG1_LED, HIGH);          // LED1 aan
      digitalWrite(BG2_LED, HIGH);          // LED2 aan
      delay(250);
      digitalWrite(BG1_LED, LOW);          // LED1 uit
      digitalWrite(BG2_LED, LOW);          // LED2 uit
      delay(250);
      digitalWrite(BG1_LED, HIGH);          // LED1 aan
      digitalWrite(BG2_LED, HIGH);          // LED2 aan
      delay(250);
      digitalWrite(BG1_LED, LOW);          // LED1 uit
      digitalWrite(BG2_LED, LOW);          // LED2 uit
}


void loop() {

// Hier worden diverse andere LEDs aangestuurd door drukknoppen

}

Het jammere is dat ik hier een paar delays in heb staan. Ik wil het netjes doen en dus die delays er eigenlijk uit hebben, zodat de arduino al andere dingen kan doen terwijl de LEDs nog aan het knipperen zijn.
Nu had ik al de volgende code om een LED te laten branden en weer uit te laten gaan met de functie Millis. In onderstaande code brandt de LED 1 seconde vanaf het moment dat de knop wordt ingedrukt. Maar ik ben zodanig een beginner dat ik deze 2 niet gecombineerd krijg.

c code:

int led = 8;
int knop = 7;
unsigned long Timer1;

void setup() {
pinMode(led, OUTPUT);
pinMode(knop, INPUT);
}

void loop() {

if (digitalRead(knop) == HIGH) {
Timer1 = millis();
digitalWrite(led, HIGH);
}

if (millis()-Timer1 >= 1000 ) {
digitalWrite(led, LOW);
}
}

Zou iemand mij kunnen helpen om deze 2 code's te combineren, om dus 2 LEDs bij het opstarten van de Arduino 2x kort te laten knipperen (en dan uit te blijven, om ze verderop in het programma met knoppen te kunnen besturen).
Beide LEDs moeten 2x kort (bijv 250 ms) tegelijkertijd knipperen.

dit kan wel, maar het probleem is alweer de delays.
Als jij in je verdere programma nog delays hebt zitten, gaan die je startup leds verknoeien.

is het de bedoeling dat je in de rest van het programma nog de leds laat uitschakelen?

snel wat code.

c code:


int led1 = 8;
int led2 = 9;
int knop = 7;
unsigned long boottimer;
unsigned long Timer1;



void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(knop, INPUT);
digitalWrite(led1, HIGH);          // LED1 aan
digitalWrite(led2, HIGH);          // LED2 aan
boottimer = millis();
}


void loop(){
if (millis()-boottimer > 250){     //check als meer dan 250ms voorbij zijn
   digitalWrite(led1, LOW);          // LED1 aan
   digitalWrite(led2, LOW);          // LED2 aan
}
if (millis()-boottimer > 250){     //check als meer dan 250ms voorbij zijn
   digitalWrite(led1, HIGH);          // LED1 aan
   digitalWrite(led2, HIGH);          // LED2 aan
}
if (millis()-boottimer > 750){     //check als meer dan 250ms voorbij zijn
   digitalWrite(led1, LOW);          // LED1 aan
   digitalWrite(led2, LOW);          // LED2 aan
}

...rest van programma doorlopen...

}

beter zou zijn om een losse procedure te maken om de leds te laten flippen. dan kan je die hier oproepen, en ook later in het programma. heb dat ooit eens gemaakt, zal even zoeken achter de code.
initialisatie en de setup van hierboven, maar de loop aangepast:

c code:


void loop(){
  if (millis()-boottimer > 250){     //check als meer dan 250ms voorbij zijn
    flipled(led1);
    flipled(led2);
    boottimer = millis();
  }

... rest van programma

}


void flipled(int led){
    if (digitalRead(led) == LOW)   {
       digitalWrite(led,HIGH);
    } else {
       digitalWrite(led,LOW);
    }
}
ik hou van werken ..., ik kan er uren naar kijken
buckfast_beekeeper

Golden Member

Krijg je op deze manier niet het probleem dat de leds voortdurend gaan knipperen als er 250ms voorbij zijn? Nergens wordt deze cyclus gestopt.

Van Lambiek wordt goede geuze gemaakt.

Ik zou er voor de duidelijkheid een state machine omheen vouwen denk ik.

Lucky Luke

Golden Member

Die delays tijdens het opstarten lijken mij geen probleem. Wat zou je mcu ondertussen moeten doen dat ècht niet driekwart seconde later kan? Het is maar 1 keer tijdens het opstarten...

Een simpele delay is IMHO in elk geval een stuk leesbaarder dan “if(millis()-iets>c)”.

Tijdens een delay(...) lopen interrupts ook gewoon door, dus zelfs in je main loop hòeft het geen probleem te zijn maar dat hangt erg van de rest van je code af. En als je extra zuinig wil zijn zou je ipv een busy-wait lusje kunnen slapen tot een timer afloopt, maar dat is (tenzij er al een library voor is) meer iets voor gevorderden...

Eluke.nl | De mens onderscheid zich van (andere) dieren door o.a. complexe gereedschappen en bouwwerken te maken. Mens zijn is nerd zijn. Blijf Maken. (Of wordt, bijvoorbeeld, cultuurhistoricus)
bprosman

Golden Member

Zit me ook af te vragen wat je eigenlijk wil.
Die "Startup" is juist om je schakeling te initialiseren, in- uitgangen goed te zetten etc. alles ter voorbereiding van je hoofdprogramma in "Loop".
Dus die delays kunnen daar inderdaad helemaal niet zoveel kwaad.
Als het hoofdprogramma zo snel mogelijk moet starten (weet de reden niet) en dan leds moet laten knipperen zou ik het verhuizen naar je hoofdprogramma want is het geen onderdeel meer van je initialisatie.

lopen interrupts ook gewoon door, dus zelfs in je main loop hòeft het geen probleem te zijn maar dat hangt erg van de rest van je code af.

Inderdaad , maar we weten niet of, en wanneer TS interrupts aanzet. In dat geval zou ik ook een timer interrupt maken me een state machine er omheen. En zo min mogelijk in "Startup".

De jongere generatie loopt veel te vaak zijn PIC achterna.

Op 23 augustus 2020 07:55:35 schreef buckfast_beekeeper:
Krijg je op deze manier niet het probleem dat de leds voortdurend gaan knipperen als er 250ms voorbij zijn? Nergens wordt deze cyclus gestopt.

de eerste oplossing niet, de 2de idd wel.
daar moet dan nog een extra teller in die na 3x ermee stopt.

of combinatie van de 2 maken door de flipled in de eerste zijn ifs te zetten.

persoonlijk zou ik ook alles met delay in de setup loop houden. voor die 0.75sec dat het maar duurt

[Bericht gewijzigd door fcapri op zondag 23 augustus 2020 09:37:48 (20%)

ik hou van werken ..., ik kan er uren naar kijken

Eventueel korter:

code:


loop () 
{
  int t; 
  t = millis () - boottimer 
  if (t <  1200) {
    digitalWrite (led1, (t/250) &1);
    digitalWrite (led2, (t/250) &1);
  }
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 23 augustus 2020 21:50:29 schreef rew:
Eventueel korter:

code:


loop () 
{
  int t; 
  t = millis () - boottimer 
  if (t <  1200) {
    digitalWrite (led1, (t/250) &1);
    digitalWrite (led2, (t/250) &1);
  }

Netjes! Je kan ook nog de boottimer weglaten:

code:


loop () 
{
   
  if (millis() <  1200) {
    digitalWrite (led1, (millis()/250) &1);
    digitalWrite (led2, (millis()/250) &1);
  }

Ik ga er vanuit dat 'boottimer' redelijk laag zal zijn.

Allemaal alvast bedankt voor de reacties!
Nog even wat achtergrond van de bedoeling van de schakeling. Het is om enkele kleppen aan te sturen in een stofafzuiginstallatie oor houtbewerkingsmachines.
Deze 2 LEDs zijn de statusLEDs die aangeven of een klep open of dicht staan en worden verderop in het programma aangestuurd door een drukknop (microswitch die wordt ingedrukt als de klep open staat en dus de statusLED laten branden).
Er zullen uiteindelijk meerdere drukknoppen, meerdere LEDs en meerdere relais aangestuurd worden.

Als de Arduino aan gaat, zit er op het bedieningspaneel meteen na de knop om de Arduino van stroom te voorzien en dus aan te zetten, de knoppen om de juiste klep te selecteren. Doordat de opstartprocedure nu dus een seconde duurt, kan het zijn dat ik binnen deze tijd al de klepselectieknop ingedrukt hebben, waardoor deze dus niet wordt geregistreerd door de delays.

Ik heb een start/stopschakelaar (die de stroom op de Arduino zet als ik de startschakelaar indruk) en de stopschakelaar; die activeert een programmareeks van de Arduino (sluiten van alle regelkleppen en nogmaals knipperen van enkele LEDs, en vervolgens de stroom naar de Arduino afsluiten waardoor deze uitvalt). Hier is het dus niet erg dat er delays in blijven zitten tijdens deze shutdown-procedure.

Op 23 augustus 2020 07:30:22 schreef fcapri:
dit kan wel, maar het probleem is alweer de delays.
Als jij in je verdere programma nog delays hebt zitten, gaan die je startup leds verknoeien.

is het de bedoeling dat je in de rest van het programma nog de leds laat uitschakelen?

In de rest van het programma zitten inderdaad ook nog delays, maar alleen in de shutdown-procedure. En daarin worden ook juist deze LEDs weer in- en uitgeschakeld.
En ja, in de rest van het programma worden deze beide LEDs (en meerdere andere) geschakeld; zowel aan als uit.
In de huidige opstelling werkt dat, behalve dat ik dus de selectieknop in kan drukken voordat de startup is afgerond.

Op 23 augustus 2020 09:30:05 schreef bprosman:
Die "Startup" is juist om je schakeling te initialiseren, in- uitgangen goed te zetten etc. alles ter voorbereiding van je hoofdprogramma in "Loop".

In mijn startup wordt inderdaad de voorbereiding gedaan. In mijn definitieve programma zal hierin waarschijnlijk ook standaard 1 van de kleppen worden geopend, maar dit is nog niet 100% zeker.

Dus die delays kunnen daar inderdaad helemaal niet zoveel kwaad.
Als het hoofdprogramma zo snel mogelijk moet starten (weet de reden niet) en dan leds moet laten knipperen zou ik het verhuizen naar je hoofdprogramma want is het geen onderdeel meer van je initialisatie.

Er is dus een kans dat ik te snel, dus tijdens de delays, al een selectieknop indruk waardoor het indrukken hiervan gemist wordt.
Als ik het knipperen van de LEDs naar het hoofdprogramma verplaats, blijven ze dan niet knipperen omdat dit steeds herhaald wordt?

Ik kijk morgen naar de voorgestelde codes; heb nu ff geen arduino met bijbehorende schakeling bij de hand om te testen wat ze doen.

rew / K7Jz, over jullie code. Lees ik het goed dat je hier dit stuk programma alleen in de eerste 1200 ms na opstarten laat uitvoeren?
En zou je de regel digitalWrite (led1, (millis()/250) &1); willen uitleggen? Ik begrijp dat het een samenvoeging is van eea (waarschijnlijk de code van fcapri?), maar mijn kennis is te beperkt om 'm te begrijpen. En ik wil hier natuurlijk wel iets van leren en niet klakkeloos jullie mooie code overnemen...

Op 23 augustus 2020 22:01:33 schreef K7Jz:
[...]

Netjes! Je kan ook nog de boottimer weglaten:

code:


loop () 
{
  
  // alleen de eerste 1000ms gaan we iets doen met leds, 
  // letop na 49 dagen (32 bits milliseconden knipperen ze weer een keer
  if (millis() =<  1000) {
    digitalWrite (led1, (millis()/250) &1);
    digitalWrite (led2, (millis()/250) &1);

   /* voorbeeld:  200 / 250 = 0,8
                  0,8 AND 1 = 0 (bitwise and)
                  250/250 = 1
                  1 & 1 = 1 led gaat aan bij 250ms
                  500/250 = 2
                  2 & 1 in bits:
                  10 & 01 = 00 led uit

                  750/250 = 3
                  11 & 01 = 01 led weer aan

                  1000/4 = 4
                  100 & 001 = led uit, verder gaan tot 1200ms heeft dus geen zin
     */
  }

Ik ga er vanuit dat 'boottimer' redelijk laag zal zijn.

De 1200 aangepast die bleek iets onnodig door te lopen.

Met interactie moet je delays zien te vermijden. Je kan timer interrupts gebruiken of met de hand de 'millis' bijhouden. De knop op een interrupt kan ook nog natuurlijk.

Iemand was daarmee begonnen en ook ik verwacht dat het "weinig" zal zijn. Dat hangt er natuurlijk vanaf wat je allemaal in "setup" zet.

Zet je bijvoorbeeld 5 keer knipperen in "setup" dan duurt het een paar seconden voordat je voor het eerst in "loop" komt.

Het is wel lekker "veilig" om het er in te laten: Als je dan eens een andere knipper of langdurige opstart in setup zet blijven de knippers hier het gewoon doen zolang je het VOOR de boottimer=millis (); in setup zet.

Mijn code is trouwens een beetje (boel) fout: Ik sla de millis op in een "int". Na zo'n 32 seconden wordt die negatief en weer kleiner dan 1200.... dan gaat ie een 32 seconden lang constant lopen knipperen. Hmm. Een "unsigned long" zou beter zijn als datatype voor mijn "t" variabele. En na 4.95 dagen krijg je dan onverwachts(?) ineens weer twee knippers.

Ik weet niet hoe "duur" de "millis ()" aanroep is. Ik gebruik ook een variabele om wat zekerder te zijn dat dat "dure" ding niet meerdere keren achter mekaar aangeroepen wordt.... Anderzijds, millis () kan gewoon een define of inline functie zijn die gewoon een variabele returned. Maar die variabele moet dan wel "volatile" gedeclareerd zijn dus in

c code:

if (millis() <  1200) {
    digitalWrite (led1, (millis()/250) &1);
    digitalWrite (led2, (millis()/250) &1);

wordt ie drie keer uit ram gehaald!

c code:

loop () 
{
  unsigned long t; 
  t = millis () - boottimer 
  if (t <  1200) {
    unsigned char l;
    l = (t / 250) & 1;
    digitalWrite (led1, l);
    digitalWrite (led2, l);
  }
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

code:


digitalWrite (led1, (millis()/250) &1);

millis() is een teller die elke seconde met 1000 wordt opgehoogd.
Door die te delen door 250 krijg je een teller die 4 keer per seconde verandert. Dus 1 2 3 4 5 6 7 8 etc in de eerste 2 seconden.

"& 1" voert een AND operatie uit op die teller. Dat heeft hetzelfde effect als een modulo 2 berekening. Alleen het laagste bit blijft dan staan.

De teller verandert daardoor in 0 1 0 1 0 1 0 1 in een tempo van 4 per seconde.

Door die teller naar de digitalWrite() te sturen gaat het lampje knipperen. 2 keer aan en uit per seconde.

code:


if (millis() < 1200)

En dat dus alleen zolang millis() kleiner is dan 1200. Dus na 1.2 seconden stopt het (net voordat het lampje voor de derde keer aan gaat.

code:


unsigned long millis()
{
	unsigned long m;
	uint8_t oldSREG = SREG;

	// disable interrupts while we read timer0_millis or we might get an
	// inconsistent value (e.g. in the middle of a write to timer0_millis)
	cli();
	m = timer0_millis;
	SREG = oldSREG;

	return m;
}

millis() is tamelijk goedkoop. Precies wat je zou verwachten. timer0_millis wordt opgehoogd in een timer interrupt.

De 1200 aangepast die bleek iets onnodig door te lopen.

Die kun je beter laten staan. Anders heb je kans dat je de eindwaarde mist en dan gaat het lampje nooit meer uit.

c code:

  if (millis() =<  1000) {

Ik schreef 1200 en heb daar (een beetje) over nagedacht.

Als de rest van "loop" soms (*) iets doet wat langer dan 1ms duurt dan gaat jou code "niet altijd" op 1000ms nog net het ledje uitzetten.

Dan krijg je dus het effect dat ie "soms" de tweede knipper niet afmaakt. Worst-case, is het ledje waar je mee knippert ook een "error" ledje wat aangeeft dat er wat mis IS. Als iemand dan naar het ding kijkt krijg je een service call: Hij geeft aan dat er wat mis is, wat nu? En dan herstarten en het werkt weer... Een lastig te vinden bug, zeker als het bijna nooit gebeurt.

Waar bugs te voorzien zijn, wil ik het liefst die bugs hebben die de compiler opmerkt. Dan dingen die evident zijn en als laatste bugs die veel tijd en werk kosten om te vinden en op te lossen. Kwestie van defensief programmeren. Sure.... De write naar het ledje gebeurt nu 200x te vaak.... Who cares?

Edit: Ah dekees had hem zonder de uitleg ook correct gespot. :-)

(*) Of zelfs "altijd"?

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Hensz

Golden Member

Op 24 augustus 2020 00:32:23 schreef Oudholland:
Als de Arduino aan gaat, zit er op het bedieningspaneel meteen na de knop om de Arduino van stroom te voorzien en dus aan te zetten, de knoppen om de juiste klep te selecteren. Doordat de opstartprocedure nu dus een seconde duurt, kan het zijn dat ik binnen deze tijd al de klepselectieknop ingedrukt hebben, waardoor deze dus niet wordt geregistreerd door de delays.

Het is daarom ook beter om een led aan te laten gaan als alles klaar is. Een soort 'in bedrijf'- of 'actief'-led.
Je laat de leds nu ook knipperen, dat lijkt op een alarmsituatie. Zet gewoon alle leds aan, initialiseer alles en zet ze daarna weer uit. Dan mag de 'in bedrijf'-led aan.

Op 24 augustus 2020 00:32:23 schreef Oudholland:
de stopschakelaar; die activeert een programmareeks van de Arduino (sluiten van alle regelkleppen en nogmaals knipperen van enkele LEDs.

Dát zou ik al helemaal niet doen, nu lijkt het net alsof er bij het afsluiten iets mis gaat. Bij het afsluiten hoef je geen led-test meer te doen, dat doe je bij het begin. Zet dus gewoon alles, in de juiste volgorde uit als je klaar bent. Klep dicht, bijbehorende led uit, volgend klep idem etc. De disco is er in je vrije tijd. :+

Don't Panic!

Op 25 augustus 2020 11:47:39 schreef rew:

c code:

  if (millis() =<  1000) {

Ik schreef 1200 en heb daar (een beetje) over nagedacht.

.. De write naar het ledje gebeurt nu 200x te vaak.... Who cares?

Edit: Ah dekees had hem zonder de uitleg ook correct gespot. :-)
...

Ja eens, jij en de Kees hebben het goed. Te strak gedacht ;)

Nouja, als je het iets anders opzet, dan kan het wel.

code:


volatile unsigned char tick, tack;

ISR _TIM1_VECT ()
{
  tick++;
}

[...]

void loop (void)
{

   while (tack != tick) {
      // Doe dingen die 1x per "tick" moeten gebeuren. 
      
      tack++;
   }
}

Nu wordt voor iedere "tick" dat stukje code PRECIES 1x gedaan, en dat wordt ingehaald als er een keer een "tack" is die wat langer duurt dan de periode. Je kan nu precies op de 250, 500, 750 en de 1000 een "dingetje" met je ledje triggeren.

Ik heb dit een paar keer toegepast buiten "arduino". Dus zelf timer instellen en dan zelf een mainloop met de tick!=tack... Met de huidige declaratie mag de boel dus 255 ticks achter lopen voordat eea fout gaat. Als je dan dus een keer "makkelijk" doet en led_aan () ; delay (100); led_uit (); dan kost dat 100 ms, maar alle 100 (ik had hem op 1kHz draaien) tackjes worden dan wel ingehaald.

Ik raad aan om niet een int of nog langere variabele te nemen op AVR: dan moet je net als bij millis interrupts uit gaan zetten om de compare te doen en zo. Dus als "rekenregel" mag je niet iets doen wat langer dan 10ms duurt, dan komt alles goed....

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/