2x LED 2x drukknop.

Projecten die niet passen in bovenstaande onderwerpen
Gebruikers-avatar
Berichten: 1853
Geregistreerd: 06 Aug 2016, 01:03

Re: 2x LED 2x drukknop.

Berichtdoor Koepel » 26 Okt 2018, 23:10

Heel goed, dat is een finite-state-machine :D
Met al die if-statements is hoe het hoort. Zo verwerk je de gegevens binnen een FSM.
Nu nog een beetje netjes maken, en dan nog werkend maken.
Ik ga meteen voluit, probeer het maar bij te houden ;)

Alleen maar voordelen

Een FSM heeft alleen maar voordelen. Voor jouw eerste sketch was het nodig om heel de sketch te begrijpen om iets te wijzigen. Nu hoef je alleen maar één state te begrijpen om iets te wijzigen.
Je kunt altijd nieuwe states bijvoegen, of meerdere states combineren tot één state. Dat geeft niets, het blijft overzichtelijk.
Een FSM werkt ook heel goed samen met millis(): https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay.

Netter is beter

Dit forum heeft code-tags om code te laten zien.
Dat kan met de knop "Code" of met de drop-down-list "Select a Syntax" en dan "C++". Zet je code tussen die code-tags.

Ik zie graag dat iedere spatie, ieder inspringen, iedere nieuwe regel van een sketch goed staat.
Dan zou je ook meteen zien dat je een fout hebt met '{' en '}'. Bij state '2' heb je geen afsluitende '}' bij het if-statement.

State '2' past niet bij een FSM

Stel dat state '2' daar een tijd blijft hangen. Dan wordt toch iedere keer de twee digitalWrite() uitgevoerd. Dat geeft helemaal niets, en is normaal bij een Arduino, maar het mooie van een FSM is dat je zo iets kunt voorkomen.
Vanuit programmeer-denken is het mooier om die actie maar één keer te doen. Bijvoorbeeld met een transitional state daar nog voor.

Transitional states

Jouw state '3' en '5' zijn "transitional states". Ze doen een actie en gaan meteen door naar de volgende state.
Je mag "transitional states" gebruiken, maar je mag ze ook weglaten. Doe maar wat je zelf het beste lijkt.
Mijn vijf states die ik in gedachten had, was zonder de transitional states.

Zonder transistional state kun je binnen de huidige state al de overgang maken en alvast de acties doen. Dan krijg je zo iets:
Code: Alles selecteren
  case 2:
    // als de knoppen allebei ingedrukt zijn dan door naar de volgende state
    if ( digitalRead(knopLinks) == HIGH && digitalRead(knopRechts) == HIGH)
    {
      // initialiseer alvast de volgende state
      digitalWrite(ledRood, HIGH); // beide LEDs zijn aan
      digitalWrite(ledGroen, HIGH);
      state = 4;
    }
    break;


Eerst alle gegevens verzamelen

Je doet heel veel digitalRead() tijdens de FSM. Een knop zou dan kunnen wijzigen tijdens het doorlopen van de FSM. Dat geeft onduidelijkheid. Ook bijvoorbeeld het debouncen van de knoppen is zo niet toe te voegen.

Daarom is het mooier om eerst alle gegevens te verzamelen en met al die gegevens de FSM in te duiken.

Een knop is ingedrukt of niet, aktief of niet, true of false.
Dat klinkt als een "bool", dan worden de if statements ook meteen eenvoudiger.

Code: Alles selecteren
void loop()
{
  bool rechtsActief;   // true als rechterknop is ingedrukt
  bool linksActief;      // true als linkerknop is ingedrukt

  if( digitalRead( knopRechts) == HIGH)
  {
    rechtsActief = true;
  }
  else
  {
    rechtsActief = false;
  }

  if( digitalRead( knopLinks) == HIGH)
  {
    linksActief = true;
  }
  else
  {
    linksActief = false;
  }

  switch( state)
  {
    case 1:
      if( rechtsActief && !linksActief)
      {
        state = 2;
      }
      break;
  }
}


Zie je hoe eenvoudig de if-statement is? Een if-statement kijk of iets 'waar' of 'niet waar' is. Een "bool" variabele is ook 'waar' of 'niet waar'. Dus bijvoorbeeld "!linksActief" staat voor de linkerknop die niet ingedrukt is. Een "!" is een boolean NOT.

Ben je bekend met deze kortere notatie?
Code: Alles selecteren
bool rechtsActief = digitalRead( knopRechts) == HIGH ? true : false;
bool linksActief  = digitalRead( knopLinks) == HIGH ? true : false;


Het kan nog korter, aangezien 'true' een '1' is en een 'HIGH' is ook een '1' en 'false' = '0' = 'LOW'. Maar dat doe ik liever niet.

enum

Het wordt pas echt mooier met een "enum".
Jouw "static int state" kan 1, 2, 3, enzovoorts zijn. Het zou mooier zijn om daar geen getallen voor te gebruiken, maar namen.
Dan kun je meteen maar beter een "enum" gebruiken in plaats van de integer "state".
Een "enum" verteld de compiler dat een variabele een bepaald aantal dingen kan zijn, en de compiler kent daar getallen aan toe.

Dus jouw "static int state" verdwijnt dan, en daarvoor komt een globale variabele (boven de setup() functie) met een "enum". Die globale variable noem ik hier ook "state".
Code: Alles selecteren
enum
{
  STATE_RUST,               // in rust, idle
  STATE_INIT_ROOD,          // transitional state
  STATE_ROOD,               // rode led is aan
  STATE_INIT_ROOD_EN_GROEN, // transitional state
  STATE_ROOD_EN_GROEN,      // beide leds zijn aan
  STATE_INIT_GROEN,         // transitional state
  STATE_GROEN,              // groene led is aan
  STATE_NA_GROEN,           // alles uit, wachten op knop loslaten
} state;


De FSM is dan zo:
Code: Alles selecteren
switch( state)
{
  case STATE_RUST:
    ...
    break;
}


Tot slot

Wat denk je dat het belangrijkste is van wat hierboven staat?
Het belangrijkste is dat je sketch er netjes uit ziet, dus alle inspringen en ieder spatie en iedere komma op de juiste plaats. Dan zie je de structuur van de code en dan maak je het jezelf een stuk gemakkelijker.

Advertisement

Berichten: 9
Geregistreerd: 23 Okt 2018, 21:28

Re: 2x LED 2x drukknop.

Berichtdoor sjef » 27 Okt 2018, 10:41

Ik heb de code aangepast en overzichtelijker gemaakt.
Ook heb ik er weer een state extra bij, dit omdat dit voor mij nog even makkelijker is.
meteen maar even geprobeerd, maar wat blijkt>> helaas de code klopt nog niet voor het geen wat ik wil.

Zodra ik de rechter knop ingedrukt heb gaat zowel de rode led aan (en weer uit als ik hem los laat wat ook de bedoeling is), maar ook de groene led dan direct aan.
Deze blijft aan totdat de linker knop wordt ingedrukt dan gaat deze uit.

Nog een vraag over de default, is deze nog wel nodig en niet dubbel tegenover de STATE_RETURN 'state'?



cpp code
enum
{
STATE_RUST, //in rust, idle
STATE_INIT_ROOD, //transitional state
STATE_ROOD, //rode LED is aan
STATE_INIT_ROOD_EN_GROEN, // transitional state
STATE_ROOD_EN_GROEN, // beide LEDs zijn aan
STATE_INIT_GROEN, // transitional state
STATE_GROEN, // groene LED is aan
STATE_INIT_NA_GROEN, // transitional state
STATE_RETURN, // terug naar idle
} state;


int knopLinks = 2; // pinnen declareren
int knopRechts = 3;
int ledRood = 4;
int ledGroen = 5;


void setup() {
pinMode( knopLinks, INPUT); // linkerknop = een input
pinMode( knopRechts, INPUT); // rechterknop = een input
pinMode( ledRood, OUTPUT); // rode LED = een output
pinMode( ledGroen, OUTPUT); // groene LED = een output
}


void loop()


{
bool rechtsActief; //treu als rechterknop is ingedrukt
bool linksActief; //treu als linkerknop is ingedrukt
if( digitalRead( knopRechts) == HIGH)
{
rechtsActief = true;
}
else
{
rechtsActief = false;
}
if( digitalRead( knopLinks) == HIGH)
{
linksActief = true;
}
else
{
linksActief = false;
}

switch( state)
{

case STATE_RUST:
if( rechtsActief && !linksActief)
{
state = STATE_INIT_ROOD; // wachten totdat alleen de rechter knop wordt ingedrukt, zo ja dan naar vogende state
}
break;


case STATE_INIT_ROOD:
digitalWrite(ledRood, HIGH); // zet de rode LED aan
digitalWrite(ledGroen, LOW); // laat groene LED uit
state = STATE_ROOD;
break;


case STATE_ROOD:
if( linksActief && rechtsActief) // als de knoppen allebei ingedrukt zijn dan door naar de volgende state
{
state = STATE_INIT_ROOD_EN_GROEN;
}
break;


case STATE_INIT_ROOD_EN_GROEN:
digitalWrite( ledRood, HIGH); // beide LEDs zijn aan
digitalWrite( ledGroen, HIGH);
state = STATE_ROOD_EN_GROEN;
break;


case STATE_ROOD_EN_GROEN:
if( !rechtsActief && !linksActief) // als de knoppen los zijn gelaten
{
state = STATE_INIT_GROEN;
}
break;


case STATE_INIT_GROEN:
digitalWrite( ledGroen, HIGH); // laat groene led aan
digitalWrite( ledRood, LOW); // zet rode led uit
state = STATE_GROEN;
break;


case STATE_GROEN:
if( rechtsActief or linksActief) // als er op de linker of rechter knop wordt gedrukt dan volgende state
{
state = STATE_INIT_NA_GROEN;
}
break;


case STATE_INIT_NA_GROEN:
digitalWrite( ledGroen, LOW); // zet de groene LED uit
digitalWrite( ledRood, LOW); // om er zeker van te zijn dat de rode LED ook uit blijft?
break;


case STATE_RETURN:
if( !rechtsActief && !linksActief) // als knop links en rechts zijn lossgelaten dan terug naar idle
state = STATE_RUST;
break;


default:
state = STATE_RUST;
break;
}
}

Gebruikers-avatar
Berichten: 1853
Geregistreerd: 06 Aug 2016, 01:03

Re: 2x LED 2x drukknop.

Berichtdoor Koepel » 27 Okt 2018, 13:32

Een "default:" mag gerust om een fout in de sketch op te vangen. Je zou dan een foutmelding kunnen geven. Omdat de variabele state met een "enum" is, is het bijna onmogelijk om bij de "default:" terecht te komen.

Wanneer een programma uit verschillende software-modules bestaat, dan is het gebruikelijk om onbekende getallen af te vangen met een "default:".

Je hebt flinke stappen vooruit gemaakt. Vind je het zelf ook een stuk overzichtelijker geworden ?

Je zou in setup() dit kunnen toevoegen: state = STATE_RUST;

Je zet de '{' en de '}' teveel naar links bij een if-statement. Die horen bij het if-statement, dus kunnen op hetzelfde niveau (dezelfde hoeveelheid inspringen) als het if-statement. Kijk maar naar mijn voorbeelden.

Nu gaat het om de code van de verschillende states. Dus nu moet ik echt gaan nadenken :o
Ik ga uit van jouw beschrijving. Ik weet niet zeker of jouw beschrijving ook echt is zoals je het wilt hebben.

STATE_RUST
Okay.

STATE_INIT_ROOD
De groene led uitzetten is niet nodig als de code overal correct is.

STATE_ROOD
Daar toevoegen om te kijken of de rechterknop wordt losgelaten (met een tweede if-statement), en in dat geval de rode led uitzetten en naar STATE_RUST.

STATE_INIT_ROOD_EN_GROEN
De rode led aanzetten is niet nodig als de code overal correct is.

STATE_ROOD_EN_GROEN
Okay.

STATE_INIT_GROEN
De groene led aanzetten is niet nodig als de code overal correct is.

STATE_GROEN
Het woord "or" binnen de conditie van het if-statement is niet juist.
Een "or" is "||".
https://www.arduino.cc/reference/en/language/structure/boolean-operators/logicalor/

STATE_INIT_NA_GROEN
De rode led uitzetten is niet nodig als de code overal correct is.
Je zou de naam "STATE_INIT_NA_GROEN" kunnen wijzigen naar "STATE_INIT_RETURN".
Je bent dit vergeten: state = STATE_RETURN;

STATE_RETURN
Okay.

En dan werkt het. Mooi hè ? Tijd voor een vreugdedansje :lol:
Wil je zelf een functie maken voor debouncen van de knoppen ? Of anders is de Bounce2 een mooie library.

Berichten: 9
Geregistreerd: 23 Okt 2018, 21:28

Re: 2x LED 2x drukknop.

Berichtdoor sjef » 27 Okt 2018, 14:46

finally!

De code zo aangepast dat hij werkend is met dank aan Koepel. (eerste poging niet, maar toen bleek er nog een break; verkeerd te staan :roll:

Hij doet het precies zoals ik het in gedachten had.. ofja bijna.
Bij STATE_RETURN 'state' wil die rode LED niet altijd uit blijven als de knop ingedrukt blijft.
Dus we moeten er waarschijnlijk nog een 'debounce' aan toevoegen?
Nu weet ik dat dit middels een 'delay' gerealiseerd kan worden maar een millis is beter geschikt?

cpp code
enum
{
STATE_RUST, //in rust, idle
STATE_INIT_ROOD, //transitional state
STATE_ROOD, //rode LED is aan
STATE_INIT_ROOD_EN_GROEN, // transitional state
STATE_ROOD_EN_GROEN, // beide LEDs zijn aan
STATE_INIT_GROEN, // transitional state
STATE_GROEN, // groene LED is aan
STATE_INIT_NA_GROEN, // transitional state
STATE_RETURN, // terug naar idle
} state;


int knopLinks = 2; // pinnen declareren
int knopRechts = 3;
int ledRood = 4;
int ledGroen = 5;


void setup() {
pinMode( knopLinks, INPUT); // linkerknop = een input
pinMode( knopRechts, INPUT); // rechterknop = een input
pinMode( ledRood, OUTPUT); // rode LED = een output
pinMode( ledGroen, OUTPUT); // groene LED = een output
state = STATE_RUST;
}


void loop()


{
bool rechtsActief; //treu als rechterknop is ingedrukt
bool linksActief; //treu als linkerknop is ingedrukt
if( digitalRead( knopRechts) == HIGH)
{
rechtsActief = true;
}
else
{
rechtsActief = false;
}
if( digitalRead( knopLinks) == HIGH)
{
linksActief = true;
}
else
{
linksActief = false;
}

switch( state)
{

case STATE_RUST:
if( rechtsActief && !linksActief) // wachten totdat alleen de rechter knop wordt ingedrukt, zo ja dan naar vogende state
{
state = STATE_INIT_ROOD;
}
break;


case STATE_INIT_ROOD:
digitalWrite(ledRood, HIGH); // zet de rode LED aan
state = STATE_ROOD;
break;


case STATE_ROOD:
if( !rechtsActief && !linksActief) // als de linker en rechterknop zijn losgelaten dan naar idle state
{
digitalWrite( ledRood, LOW);
state = STATE_RUST;
}
if( linksActief && rechtsActief) // als de knoppen allebei ingedrukt zijn dan door naar de volgende state
{
state = STATE_INIT_ROOD_EN_GROEN;
}
break;


case STATE_INIT_ROOD_EN_GROEN:
digitalWrite( ledGroen, HIGH); // beide LEDs zijn aan
state = STATE_ROOD_EN_GROEN;
break;


case STATE_ROOD_EN_GROEN:
if( !rechtsActief && !linksActief) // als de knoppen los zijn gelaten
{
state = STATE_INIT_GROEN;
}
break;


case STATE_INIT_GROEN:
digitalWrite( ledGroen, HIGH); // laat groene led aan
digitalWrite( ledRood, LOW); // zet rode led uit <deze is nodig anders blijft de rode led aan?
state = STATE_GROEN;
break;


case STATE_GROEN:
if( rechtsActief || linksActief) // als er op de linker of rechter knop wordt gedrukt dan volgende state
{
state = STATE_INIT_NA_GROEN;
}
break;


case STATE_INIT_NA_GROEN:

digitalWrite( ledGroen, LOW); // om er zeker van te zijn dat de rode LED ook uit blijft?
state = STATE_RETURN;
break;

case STATE_RETURN:
if( !rechtsActief && !linksActief) // als knop links en rechts zijn lossgelaten dan terug naar idle
{
state = STATE_RUST;
}
break;


default:
state = STATE_RUST;
break;
}
}

Gebruikers-avatar
Berichten: 1853
Geregistreerd: 06 Aug 2016, 01:03

Re: 2x LED 2x drukknop.

Berichtdoor Koepel » 27 Okt 2018, 16:09

En? hoe reageerde de buurt op je "Band of the Bold" vreugdedansje ? (https://www.youtube.com/watch?v=aaGX4JdtQi8).

Wist je dat jouw loop() nu meer dan duizend keer per seconde wordt uitgevoerd? De FSM wordt dus heel veel doorlopen.
Dat is goed, want dan reageert het lekker snel. Je hebt dus ook genoeg tijd over om andere dingen te doen. Het is zelfs mogelijk om nog meer FSM's toe te voegen die heel andere dingen doen.

Wanneer je tegelijkertijd een ledje laad knippen met de Blink Without Delay (https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay), dan gebruiken zowel jouw FSM en het knipperen geen delay en draait alles op volle snelheid.
Je kunt ze ook beide combineren, door bij een bepaalde state met millis() een ledje te laten knipperen.

Omdat het op volle snelheid draait, wordt een glitch van de knop al snel gedetecteerd. Ik vermoed dat het debouncen van de knop het probleem zal oplossen.
De Bounce2 gebruikt intern millis() en zit in de "Bibliotheek Beheer" in de Arduino IDE.
Dit is een voorbeeld: https://github.com/thomasfredericks/Bounce2/blob/master/examples/bounce2buttons/bounce2buttons.ino.

Zelf iets maken met delay() kan ook, maar dan wordt de code in loop() helaas vertraagt. Bijvoorbeeld drie keer meten gedurende 6 ms.

Probeer maar iets voor het debouncen. Heb je contact spray ? Dat kan ook helpen. Bijvoorbeeld het erg dure "Kontakt Chemie Gold 2000".

Dit is een voorbeeld met zelf iets maken met delay():
Code: Alles selecteren
void loop()
{
  bool rechtsActief = getSwitch( knopRechts);
  bool linksActief  = getSwitch( knopLinks);

  ...
}


// Eenvoudige debounce
// Geeft 'true' als knop actief is (ingedrukt).
// De knop zit aan 5V, dus HIGH is actief.
// Drie keer lezen, met tussenpauze, meerderheid geeft doorslag.

bool getSwitch( int pin)
{
  int count = 0;
  for( int i=0; i<3; i++)
  {
    if( digitalRead( pin) == HIGH)  // sample de digitale input.
    {
      count++;
    }
    delay( 3);  // aantal milliseconden tussen de samples.
  }
  return( count > 2);  // minstens 2 van 3 drie HIGH, dan return true, anders false
}


Deze functie schreef ik zomaar op, maar ik schaam me een beetje voor zulke code :oops: Misschien weten anderen iets beters om zelf een eenvoudige debounce te maken.

Berichten: 9
Geregistreerd: 23 Okt 2018, 21:28

Re: 2x LED 2x drukknop.

Berichtdoor sjef » 03 Nov 2018, 15:46

Dat was wel een vreugde dansje waard :D

Na nog wat bezig te zijn geweest met andere projectjes ben ik toch weer op dit project terug gevallen om de debounce werkend te krijgen.

Ik wil de (voor jou beschamende debounce code :D) toch gaan proberen.
Maar de als ik de code controleer vraagt hij om een declaratie van 'getSwitch'?

Verder heb ik de code aangepast naar een PULLUP en een enkele Rode led die de functie van de groene led erbij krijgt.
Het principe werkt prima, behalve dan dat er in alle waarschijnlijkheid een debounce in moet komen. :evil:

Ook heb ik geprobeerd om de knop te vervangen door een optocoupler (dit omdat ik er een 24v op wil schakelen) maar dan brand de led wel maar blijft hij niet branden als als ik de knoppen allebei tegenlijkertijd indruk.

Of zie ik het over het hoofd dat er in de optocoupler een phototransistor zit die maar aan 1 richting stroom doorgeeft? :roll:

De aangepaste code:

cpp code
// pullup

enum
{
STATE_RUST, //in rust, idle
STATE_INIT_ROOD, //transitional state
STATE_ROOD, //rode LED is aan
STATE_ACTIVEER_ROOD, // transitional state
STATE_KNOPPEN_LOS, // beide LEDs zijn aan
STATE_ROOD_CONTINU, // groene LED is aan
STATE_INIT_NA_CONITNU, // transitional state
STATE_RETURN, // terug naar idle
} state;


int knopLinks = 5; // pinnen declareren
int knopRechts = 6;
int ledRood = 7;



void setup() {
pinMode( knopLinks, INPUT_PULLUP); // linkerknop = een input
pinMode( knopRechts, INPUT_PULLUP); // rechterknop = een input
pinMode( ledRood, OUTPUT); // rode LED = een output
state = STATE_RUST; // bij de idle state beginnen
}


void loop()
{


bool rechtsActief; //treu als rechterknop is ingedrukt
bool linksActief; //treu als linkerknop is ingedrukt

if( digitalRead( knopRechts) == LOW) // knopRechts = LOW dan = rechtsActief treu, anders false
{
rechtsActief = true;
}
else
{
rechtsActief = false;
}
if( digitalRead( knopLinks) == LOW) // knopLinks = LOW dan = linksActief treu, anders false
{
linksActief = true;
}
else
{
linksActief = false;
}




bool rechtsActief = getSwitch( knopRechts);
bool linksActief = getSwitch( knopLinks);
}
// Eenvoudige debounce
// Geeft 'true' als knop actief is (ingedrukt).
// De knop zit aan 0V, dus LOW is actief.
// Drie keer lezen, met tussenpauze, meerderheid geeft doorslag.

bool getSwitch( int pin)
{
int count = 0;
for( int i=0; i<3; i++)
{
if( digitalRead( int) == LOW) // sample de digitale input.
{
count++;
}
delay( 3); // aantal milliseconden tussen de samples.
}
return( count > 2); // minstens 2 van 3 drie LOW, dan return true, anders false
}


switch( state) // de switch state starten
{

case STATE_RUST:
if( rechtsActief && !linksActief) // wachten totdat alleen de rechter knop wordt ingedrukt, zo ja dan naar vogende state
{
state = STATE_INIT_ROOD;
}
break;


case STATE_INIT_ROOD:
digitalWrite(ledRood, HIGH); // zet de rode LED aan dan door naar volgende state
state = STATE_ROOD;
break;


case STATE_ROOD:
if( !rechtsActief && !linksActief) // als de linker en rechterknop zijn losgelaten dan naar idle state
{
digitalWrite( ledRood, LOW);
state = STATE_RUST;
}
if( linksActief && rechtsActief) // als de knoppen allebei ingedrukt zijn dan door naar de volgende state
{
state = STATE_ACTIVEER_ROOD;
}
break;


case STATE_ACTIVEER_ROOD:
digitalWrite( ledRood, HIGH); // activeer de rode LED stand continu
state = STATE_KNOPPEN_LOS;
break;


case STATE_KNOPPEN_LOS:
if( !rechtsActief && !linksActief) // als beide knoppen los zijn gelaten dan door naar volgende state
{
state = STATE_ROOD_CONTINU; //STATE_INIT_GROEN;
}
break;


case STATE_ROOD_CONTINU:
if( rechtsActief || linksActief) // als er op de linker of rechter knop wordt gedrukt dan volgende state
{
state = STATE_INIT_NA_CONITNU;
}
break;


case STATE_INIT_NA_CONITNU:

digitalWrite( ledRood, LOW); // zet de rode LED uit dan door naar vogende state
state = STATE_RETURN;
break;

case STATE_RETURN:
if( !rechtsActief && !linksActief) // als knop links en rechts zijn losgelaten dan terug naar idle
{
state = STATE_RUST;
}
break;


default:
state = STATE_RUST;
break;
}
}

Berichten: 9
Geregistreerd: 23 Okt 2018, 21:28

Re: 2x LED 2x drukknop.

Berichtdoor sjef » 03 Nov 2018, 19:18

Ik zie dat ik de 'niet nette' code had gestuurd :roll: .

hier de wat meer geordende code met in de 1 naar laatste case een delay van 5 ms toegevoegd (niet zoals het moet, maar hierdoor werkt het wel):

cpp code
/* 1 x LED en 2 Drukknoppen,
* Als er op de Rechtste drukknop gedrukt is, dan moet de RODE LED aangaan.
* Wordt de knop weer losgelaten, dan gaat de RODE LED uit.
* Druk op de LINKSE en RECHTSE knop tegelijk en laat deze allebij los, dan gaat de RODE LED aan en moet deze aanblijven (AND functie).
* Met de AND functie moet ook de teller (switch cases) geactiveerd worden die telt hoeveel keren er op de rechtse knop gedrukt wordt.
* De teller wordt doorlopen doormiddel van de RECHTSE drukknop.
* Druk je na de AND functie 1 x op de RECHTSE of LINKSE drukknop, dan moet de RODE LED uitgaan ook al blijft de rechtse of linkse knop ingedrukt.
* Druk je nu een 2e maal op de RECHTSE drukknop, dan moet de teller RESETTEN en weer zijn oude functie oppakken (RECHTSE drukknop drukken = RODE LED aan, laat de RECHTSE drukknop los, dan RODE LED uit).

* Aansluiting op de Arduino uno:
* PULLUP.
* Pin 5 gaat naar drukknop LINKS.
* Pin 6 gaat naar drukknop RECHTS.
* De andere zijde van de rechtse drukknop gaat naar de GRND.
* De Rode LED wordt met de anode aangesloten op digitaal pin 7.
* De kathode wordt via een weerstand van 220ohm op de GRND aangesloten.
*/

enum
{
STATE_RUST, // in rust, idle
STATE_INIT_ROOD, // transitional state
STATE_ROOD, // rode LED is aan
STATE_ACTIVEER_ROOD, // transitional state
STATE_KNOPPEN_LOS, // beide LEDs zijn aan
STATE_ROOD_CONTINU, // groene LED is aan
STATE_INIT_NA_CONITNU, // transitional state
STATE_RETURN, // terug naar idle
} state;


int knopLinks = 5; // pinnen declareren
int knopRechts = 6;
int ledRood = 7;



void setup()
{
pinMode( knopLinks, INPUT_PULLUP); // linkerknop = een input met PULLUP weerstand 20k (van de atmel)
pinMode( knopRechts, INPUT_PULLUP); // rechterknop = een input met PULLUP weerstand 20k (van de atmel)
pinMode( ledRood, OUTPUT); // rode LED = een output
state = STATE_RUST; // bij de idle state beginnen
}


void loop()
{

bool rechtsActief; // true als rechterknop is ingedrukt
bool linksActief; // true als linkerknop is ingedrukt


if( digitalRead( knopRechts) == LOW) // knopRechts = LOW dan = rechtsActief true, anders false
{
rechtsActief = true;
}
else
{
rechtsActief = false;
}
if( digitalRead( knopLinks) == LOW) // knopLinks = LOW dan = linksActief true, anders false
{
linksActief = true;
}
else
{
linksActief = false;
}



switch( state) // de switch state starten
{

case STATE_RUST:
if( rechtsActief && !linksActief) // wachten totdat alleen de rechter knop wordt ingedrukt, zo ja dan naar vogende state
{
state = STATE_INIT_ROOD;
}
break;


case STATE_INIT_ROOD:
digitalWrite(ledRood, HIGH); // zet de rode LED aan dan door naar volgende state
state = STATE_ROOD;
break;


case STATE_ROOD:
if( !rechtsActief && !linksActief) // als de linker en rechterknop zijn losgelaten dan naar idle state
{
digitalWrite( ledRood, LOW);
state = STATE_RUST;
}
if( linksActief && rechtsActief) // als de knoppen allebei ingedrukt zijn dan door naar de volgende state
{
state = STATE_ACTIVEER_ROOD;
}
break;


case STATE_ACTIVEER_ROOD:
digitalWrite( ledRood, HIGH); // activeer de rode LED stand continu
state = STATE_KNOPPEN_LOS;
break;


case STATE_KNOPPEN_LOS:
if( !rechtsActief && !linksActief) // als beide knoppen los zijn gelaten dan door naar volgende state
{
state = STATE_ROOD_CONTINU;
}
break;


case STATE_ROOD_CONTINU:
if( rechtsActief || linksActief) // als er op de linker of rechter knop wordt gedrukt dan volgende state
{
delay(5); // delay van 5 ms erin voor het debounce effect, niet helemaal zo als het hoort maar werkt wel.
state = STATE_INIT_NA_CONITNU;
}
break;


case STATE_INIT_NA_CONITNU:
digitalWrite( ledRood, LOW); // zet de rode LED uit dan door naar vogende state
state = STATE_RETURN;
break;

case STATE_RETURN:
if( !rechtsActief && !linksActief) // als knop links en rechts zijn losgelaten dan terug naar idle
{
state = STATE_RUST;
}
break;


default: // mocht er wat verkeerd gaan dan terug naar idle
state = STATE_RUST;
break;
}
}

Gebruikers-avatar
Berichten: 1853
Geregistreerd: 06 Aug 2016, 01:03

Re: 2x LED 2x drukknop.

Berichtdoor Koepel » 03 Nov 2018, 20:39

Het tekst layout kan nog iets netter.

Het begin '{' van de switch-statement staat niet op hetzelfde niveau als het bijbehorende '}'.
De 'case' keywords kunnen ingesprongen of op hetzelfde niveau als het 'switch' keyword. Maar jij hebt ze naar voren gesprongen, dat is raar. Hieronder een paar mogelijkheden:
cpp code
// enkele voorbeelden
switch( state)
{
case EEN:
digitalWrite( 13, HIGH);
break;
case ANDERHALF:
break;
}

switch( state)
{
case EEN:
digitalWrite( 13, HIGH);
break;
case ANDERHALF:
break;
}

switch( state) {
case EEN:
digitalWrite( 13, HIGH);
break;
case ANDERHALF:
break;
}


In de Arduino IDE kun je al die regels selecteren en met een 'Tab' schuift het naar rechts. Met 'Shift + Tab' weer naar links.

Die 5 ms om te debouncen is een beetje flauw. Maar als het werkt, dan vind ik het prima :D
Mocht er toch problemen ontstaan, dan pak je gewoon de Bounce2 library.

Gebruikers-avatar
Berichten: 1853
Geregistreerd: 06 Aug 2016, 01:03

Re: 2x LED 2x drukknop.

Berichtdoor Koepel » 04 Nov 2018, 10:35

Ik dacht dat jouw knoppen aan de 5V zaten ?
De sketch gaat er van uit dat het signaal HIGH is wanneer een knop is ingedrukt.
Dan is een INPUT_PULLUP niet nodig, alleen een externe pulldown weerstand.

Een optocoupler kan ook. Zowel de ingang als de uitgang laat de stroom in één richting door.
Kun je misschien een schema laten zien ?
Je mag een schetsje op papier maken en daar een foto van maken.

Vaak wordt een knop aan GND gehangen met een pullup weerstand. Dan is het nodig om de sketch te wijzigen omdat dan LOW actief is. Dat kan veiliger zijn, bijvoorbeeld als er lange draden naar de knoppen lopen en er een metalen kast is. Wanneer er iets mis gaat en er kortsluiting ontstaat, dan is het veiliger dat er een GND draad loopt in plaats van een 5V draad. Dat is vergezocht, maar ik heb de voorkeur voor een GND draad naar sensoren en knoppen :geek:

In dat geval kan de optocoupler uitgang gewoon aan een digitale ingang en GND verbonden worden.

Door die boolean variabelen te gebruiken (rechtsActief en linksActief) voor de knoppen, hoef je niet de hele FSM te gaan wijzigen als de knoppen LOW actief zouden zijn in plaats van HIGH. Alleen het stukje code dat kijkt of een knop is ingedrukt wijzigen.

De getSwitch() is een functie. Die zet je op hetzelfde niveau als de setup() en de loop() functies.
Je had de getSwitch tussen de code in de loop() gezet, dat mag niet in de taal 'c' en 'c++'.
Je mag de getSwitch() helemaal onderaan zetten, onder de loop() of je anders boven setup().
In mijn voorbeeld had ik drie puntjes "..." voor de rest van de code van de loop(), en daarna had ik de loop() afgesloten met een '}' en daarna kwam de getSwitch() functie. Logisch toch ?

Berichten: 9
Geregistreerd: 23 Okt 2018, 21:28

Re: 2x LED 2x drukknop.

Berichtdoor sjef » 04 Nov 2018, 18:01

Zoals ik in mijn vorige post had aangegeven:

"Verder heb ik de code aangepast naar een PULLUP en een enkele Rode led die de functie van de groene led erbij krijgt.
Het principe werkt prima, behalve dan dat er in alle waarschijnlijkheid een debounce in moet komen."

De sketch had ik ook veranderd naar PULLUP:

if( digitalRead( knopRechts) == LOW) // knopRechts = LOW dan = rechtsActief true, anders false
{
rechtsActief = true;

Dit had ik gedaan om te kijken of dat ook mogelijk was, en een weerstand + jumper minder.
In de pullup heb ik aan 1 kant van de knop pin 6 van de arduino, aan de andere kant van de knop rechtstreeks de gnd. zonder weerstand.

Ik heb gister nog de 'bounce2' bijgevoegd in de sketch. en die werkt nu prima. Dit omdat ik het toch wat netter vond staan in plaats van een verdwaalde delay. :D

De schets van de optoucoupler:

opto.jpg
Optocoupler pc817c
opto.jpg (82.21 KiB) 77 keer bekeken


Het betreft een pc817c optocoupler.

(ik heb eventueel ook nog een 4n35 opto. maar die lijkt me onnodig.


Verder kan er natuurlijk ook 24 v de relais schakelen aan de relais pin 6 en gnd hangen, maar wil ook graag weten of dat mogenlijk is met een optocoupler, dan hebben we dat ook weer een keer gedaan. ;)

De 24v is trouwens niet nodig, dit is puur om te kijken of de LED's ook op een andere manier te schakelen zijn en ik nog een inductive sensor heb liggen van 24v.

VorigeVolgende

Terug naar Overige projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 6 gasten