BmB
Frysk bloed tsjoch op! wol no ris brûze en siede, en bûnzje troch ús ieren om!
Hallo,
Momenteel ben ik bezig met een op het eerste gezicht simpel projectje.
Ik heb een aantal druktoetsen (maakcontact) en wil daar een aan-uit schakeling (Toggle) van maken met behulp van een Arduino.
Op het internet staan meerdere voorbeelden die Digitalread gebruiken. (zie onderstaande voorbeeld).
Ik kan alleen niet vinden hoe dit werkt met meerdere schakelaars en meerdere uitgangen, aangezien digitalread per pin werkt.
Het is misschien simpel maar wie kan me op weg helpen 
// Define the pins being used
int pinLed = 08;
int pinSwitch = 02;
// declaring variables to hold the new and old switch states
boolean oldSwitchState = LOW;
boolean newSwitchState = LOW;
boolean LEDstatus = LOW;
void setup()
{
pinMode(pinLed, OUTPUT);
digitalWrite(pinLed, LOW);
pinMode(pinSwitch, INPUT);
}
void loop()
{
newSwitchState = digitalRead(pinSwitch);
if ( newSwitchState != oldSwitchState )
{
// has the button switch been closed?
if ( newSwitchState == HIGH )
{
if ( LEDstatus == LOW ) {
digitalWrite(pinLed, HIGH);
LEDstatus = HIGH;
}
else {
digitalWrite(pinLed, LOW);
LEDstatus = LOW;
}
}
oldSwitchState = newSwitchState;
}
}
Misschien voor de details, ik heb nu 6 ingangen (02-07) en 6 uitgangen (08-13).
buckfast_beekeeper
Van Lambiek wordt goede geuze gemaakt.
Je hebt de keuze. Ofwel werk je met een byte en is elke toets een bit. Ofwel maak je per schakelaar een boolean aan.
Voor de uitgangen doe je dan hetzelfde.
die code doet niet wat jij wil.
die laat de code branden als de knop is ingedrukt, en doet de led uit als de knop wordt losgelaten
simpelste methode, alles in 1 groot stuk code:
int button1 = 2; //ingangen
int button2 = 3;
int button3 = 4;
...
int led1 = 8; //uitgangen
int led2 = 9;
int led3 = 10;
...
int setLed1 = 0;
int setLed2 = 0;
int setLed3 = 0;
void setup(){
pinMode(button1, INPUT);
pinMode(button2, INPUT);
pinMode(button3, INPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
}
void loop(){
//KNOP1
if ( (digitalRead(button1) == HIGH) ) { //is knop 1 ingedrukt?
if (setLed == 0){ //staat de led nu uit?
setLed1 = 1; //indien uit, zet nu aan
} else {
setLed1 = 0; //indien niet, zet led uit
}
}
//KNOP2
if ( (digitalRead(button2) == HIGH) ) { //is knop 2 ingedrukt?
if (setLed == 0){ //staat de led nu uit?
setLed2 = 1; //indien uit, zet nu aan
} else {
setLed2 = 0; //indien niet, zet led uit
}
}
//KNOP3
if ( (digitalRead(button3) == HIGH) ) { //is knop 3 ingedrukt?
if (setLed3 == 0){ //staat de led nu uit?
setLed3 = 1; //indien uit, zet nu aan
} else {
setLed3 = 0; //indien niet, zet led uit
}
}
...
//dit herhaal je voor al je knoppen
//LEDS LATEN BRANDEN
//LED1
if (setled1 == 1){ //moet de led1 aan?
digitalWrite(led1,HIGH) //led aan
} else {
digitalWrite(led1,LOW) // led uit
}
...
//dit herhaal je voor al je leds
}hier zit het probleem dat je led verschillende keren gaat aan en uit springen, omdat het indrukken van een schakelaar voor contactdender zorgt
daarom gaan we een stuk toevoegen zodat elke knop maar geactiveerd kan worden na 200ms
//bovenaan bijzetten
unsigned long buttonPressTime = 0;en dan overal onze "if" van de buttons aanpassen naar dit
if ( (digitalRead(button1) == HIGH) ) && (millis() - buttonPressTime > 200) ) {
if (setLed == 0){
setLed2 = 1;
} else {
setLed2 = 0;
}
buttonPressTime = millis();
}
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Op 30 december 2019 00:47:41 schreef BmB:
..Ik kan alleen niet vinden hoe dit werkt met meerdere schakelaars en meerdere uitgangen, aangezien digitalread per pin werkt.
Het zit eigenlijk al in de eerdere antwoorden, maar wat je doet is gewoon voor elke schakelaar een digitalread uitvoeren. Je leest dus achter elkaaar een toets in en niet allemaal in 1 keer. Voor de dig.write hetzelfde verhaal.
buckfast_beekeeper
Van Lambiek wordt goede geuze gemaakt.
if (setled1 = 1){ //moet de led1 aan?
digitalWrite(led1,HIGH) //led aan
} else {
digitalWrite(led1,HIGH) // led uit
}Gaat niet werken.
if (setled1 = 1){ //moet de led1 aan?
digitalWrite(led1,HIGH) //led aan
} else {
digitalWrite(led1,LOW) // led uit
}flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Is dat een spelletje "zoek de verschillen"? [edit] ah, nu zie ik 'm! 
Die compare if (setled1 = 1) gaat niet goed. Dat moet een == zijn. Nu doe je gelijk een assignment naar setled1 en die is altijd true.
beide gefixt. is ook maar code uit de losse hand
ik schrijf normaal zo niet, dit was het eenvoudigste om het idee begrijpbaar over te brengen.
ik zou 2 sub procedures programmere.
één voor een schakelaar te lezen, en één voor de uitgang te wisselen indien knop ingedrukt.
in deze stijl. je moet niet iemand tonen hoe je programmeert, je moet uitleggen hoe het werkt. en dat lukt al minder met onderstaande code
void setup(){
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
...
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
...
}
void loop(){
for (int a = 2; a < 7; a++){ //buttons 2->7
if (checkButton(a)){
toggleLed(a+6); //outputs 8-13
}
}
int checkButton(int buttonnr){
if ( (digitalRead(buttonnr) == HIGH) ) && (millis() - buttonPressTime > 200) ) {
buttonPressTime = millis();
return 1; //knop is ingedrukt na 200ms
}
}
void toggleLed(int lednr){
digitalWrite(lednr,!digitalRead(lednr)); //wissel de uitgang status
}
}flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Om iemand uit te leggen hoe het zou kunnen, kun je beter pseudo-code gebruiken en niet de exacte syntax. Immers, het lijkt dan of het volledige, correcte code is. En als het dat niet is, dan geeft dat weer vragen, opmerkingen en onbegrip bij de vraagsteller. Het coderen kan TS zelf wel.
Boudie
Vervangen DOOR.
In het kader van "geen code geven", maar "leren programmeren", zou het dan niet beter zijn te wijzen op het gebruik van interrupts in plaats van de buttons te pollen?
Interrupts zijn lang niet altijd nodig, en voor een beginner al snel een brug te ver. Pollen is al moeilijk genoeg blijkbaar. 
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Interrupts zijn vrij simpel, en 't werkt een stuk makkelijker/mooier.
(je hebt je main routine dan vrij voor belangrijkere zaken...)
Op 30 december 2019 12:54:20 schreef Boudie:
In het kader van "geen code geven", maar "leren programmeren", zou het dan niet beter zijn te wijzen op het gebruik van interrupts in plaats van de buttons te pollen?
een gewone arduino heeft maar een 2-3 pinnen waar interrupts op werken
Op 30 december 2019 13:38:37 schreef Arco:
Interrupts zijn vrij simpel, en 't werkt een stuk makkelijker/mooier.
(je hebt je main routine dan vrij voor belangrijkere zaken...)
het hangt er vanaf wat de arduino nog van taken heeft. als het enkel het aan/uit met de knoppen besturen is, hoef je de main niet te sparen.
ook kan je geen 8 interupts op de ingangen zetten. dan zou je met diodes elke knop gaan linken naar 1 interrupt pin en dan in de interupt gaan uitlezen welke knop was ingedrukt.
veel simpeler om de code te optimaliseren dat die een paar 100keer door de loop loopt om de knoppen te bekijken, en de andere routines te laten verwerken op fixe tijdstippen.
ik ga ook een arduino in de ligfiets steken samen met een altijd FETS op de uitgang, om alle verlichting aan te sturen.
veel gemakkelijker dan 10fysieke knoppen te gaan inbouwen, nu gewoon 2x zo een 4button plak strip monteren, stel weerstanden eraan en alles met 2draden naar de arduino
[Bericht gewijzigd door fcapri op (13%)]
Je kan eventueel booleaanse algebra gebruiken om de bits te toggelen.
Met een "exlusief of" instructie. ( eor in assembly )
Je hoeft nu niet eerst te lezen en vergelijken maar toggle je in directe modus met 1 instructie, 8 bits in 1 keer.
Ben niet zo thuis in C, dus een voorbeeldje in assembly,
b.v.
ldi ToggleBits,0b00101000 ; bit 3 en 5
ldi Resultaat,0b00000000 ; resultaat wordt naar de "output port" verzonden ( b.v. PORTB )
eor Resultaat,ToggleBits ; toggle bits 3 en 5 in Resultaat
out PORTB,Resultaat ; 0b00101000 wordt gezet in PORTB
eor Resultaat,ToggleBits ; toggle bits 3 en 5 in Resultaat
out PORTB,Resultaat ; 0b00000000 wordt gezet in PORTB
eor Resultaat,ToggleBits ; toggle bits 3 en 5 in Resultaat
out PORTB,Resultaat ; 0b00101000 wordt gezet in PORTB
etc.
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Ik hoop dat je assembly alleen als voorbeeld bedoeld 
Het kan met logische functies, maar ik vindt het zelf mooier en vooral duidelijker om met if/then/else te werken. Op die manier is het meer "spreektaal" en staat er in de code wat je echt bedoeld. Met logische functies zie je dat niet meer.
Interrupts: zou ik TS in dit geval zeker niet aanraden. Keep It Simple, pollen maar.
ps, waar zit ie eignelijk? Oh wacht, leeft 's-nachts...
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
ook kan je geen 8 interupts op de ingangen zetten.
Tja,
Ik wist niet dat een arduino zo beperkt was... (pic heeft interrupt op elke ingang)
Ik gebruik daar trouwens een timer interrupt voor: iedere mS test ik of/welke key er ingedrukt is. Ook handig voor maken van 'repeats'...
Een AtMega328 uit een arduino nano en de uno heeft 3 pin change interrupt vectors die je kunt koppelan aan 24 I/O pinnen.
Maar om dat te gebruiken moet je de datasheets bestuderen, en de meeste arduino programmeurs doen dat niet. Die komen niet verder dan de arduino reference manual en het downloaden van libraries.
Dat is juist de kracht van de arduino omgeving. Dat je applikaties kunt bouwen zonder je te moeten verdiepen in technische details.
Dan maar zonder interrupts, gaat ook heel goed (meestal dan).
Op 30 december 2019 15:38:28 schreef flipflop:
Ik hoop dat je assembly alleen als voorbeeld bedoeldHet kan met logische functies, maar ik vindt het zelf mooier en vooral duidelijker om met if/then/else te werken. Op die manier is het meer "spreektaal" en staat er in de code wat je echt bedoeld. Met logische functies zie je dat niet meer.
Ach ja, het is maar wat men echt eenvoudiger vindt....
Denk dat het veel belangrijker is, dat men begrijpt wat er voor akties plaats vinden in de microcontroller.
"exclusief of" is een instructie speciaal bedoeld om bits te "toggelen" zonder omwegen.
Dus, men hoeft niet eerst de staat van de bit te lezen om het te "toggelen" van 0 naar 1 of 1 naar 0.
Plus je kan alle 8 bits in 1 keer "toggelen" met 1 instructie. ( een 1 = bit "toggelen", een 0 = bit in originele staat laten )
Simpeler kan niet.
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Alleen de code van de TS zelf (als eerste) werkt, alle andere voorbeelden missen een belangrijk stukje: Het moet een TOGGLE worden als de knop ingedrukt wordt, de edge detectie van de knop ontbreekt in de code van "fcapri". Als je daar de knop indrukt gaat de pin als een gek staan toggelen totdat je die los laat.
Zit wel in de code die de TS zelf gepost heeft. In die code heet die oldSwitchState.
Effe in pseudo code:
oldpin = LOW; //-> moet in de setup komen
pin = readButton();
if ((pin == HIGH)&& (oldpin != pin)) {
// toggle output
led ^= 1;
}
// Bewaar huidige pin status
oldpin = pin;
Ook moet er nog iets van ont-dender tussen.
Deze code moet je dus tig-keer herhalen voor iedere knop.
Je zou een array-tje kunnen maken voor alle "oldpin" statussen en de led status en dan die array indexeren met het pin nummer. Dat is denk ik het meest begrijpbaar/leesbaar.
Kan efficienter met bits in bytes. Maar is voor een leek lastiger te lezen.
hmm, idd, nu ik TS zijn code opnieuw lees, begrijp ik het.
ik had het eerst verstaan dat de led getoggeld wordt, als de knop is ingedrukt en verschillend van de vorige status
dus knop los = led uit
knop ingedrukt = led aan.
er wordt dus éérst gekeken of de status is veranderd, en dan pas een toggle als de nieuwe status hoog is.
bij mij gaat elke 200ms de led toggelen. ben nu niet meer thuis en internet via telefoon, dus programmeren is niet handig
bestaan er in arduino niet een functie dat je de flank kan zien (rising of faling)?
@ dekees: ik heb die info ook gewoon op arduino.cc gevonden, omdat ik mijn interrupt niet aan de praat kreeg op pin 6
https://www.arduino.cc/reference/en/language/functions/external-interr…
en hier staat toch echt dat de nano maar 2 poorten heeft met interrupt erop
Op 30 december 2019 17:46:43 schreef henri62:
Alleen de code van de TS zelf (als eerste) werkt, alle andere voorbeelden missen een belangrijk stukje: Het moet een TOGGLE worden als de knop ingedrukt wordt, de edge detectie van de knop ontbreekt in de code van "fcapri". Als je daar de knop indrukt gaat de pin als een gek staan toggelen totdat je die los laat.Zit wel in de code die de TS zelf gepost heeft. In die code heet die oldSwitchState.
Effe in pseudo code:
oldpin = LOW; //-> moet in de setup komen pin = readButton(); if ((pin == HIGH)&& (oldpin != pin)) { // toggle output led ^= 1; } // Bewaar huidige pin status oldpin = pin;Ook moet er nog iets van ont-dender tussen.
Deze code moet je dus tig-keer herhalen voor iedere knop.
Je zou een array-tje kunnen maken voor alle "oldpin" statussen en de led status en dan die array indexeren met het pin nummer. Dat is denk ik het meest begrijpbaar/leesbaar.
Kan efficienter met bits in bytes. Maar is voor een leek lastiger te lezen.
Je hoeft de pin status niet te bewaren.
oldpin = LOW; //-> moet in de setup komen
pin = readButton();
if ((pin == HIGH)&& (oldpin != pin)) {
// toggle output
led ^= 1;
}
// Bewaar huidige pin status
oldpin = pin;
Doet exact hetzelfde als:
pin = readButton();
led ^= pin;
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Dat is niet hetzelfde, kijk maar eens goed. Bij indrukken van de button blijft de led togglen in jouw code.
Het is de bedoeling dat de led maar eenmaal toggled als je de knop indrukt (en vasthoud).
buckfast_beekeeper
Van Lambiek wordt goede geuze gemaakt.
Een ATmega kan je heus wel een interrupt genereren op elke pin. Lees de datasheet er maar op na. Het enige verschil is dat de interrupt geld voor a0-a7, b0-b7, ... Als er een interrupt is, moet je kijken welke pin de interrupt veroorzaakt heeft.
[Bericht gewijzigd door buckfast_beekeeper op (36%)]
Kijken naar flanken zoals oa henri62 doet is goed, maar je moet toch iets doen tegen contactdender. Dat kan door bijvoorbeeld eens in de 100 milliseconde de input inlezen of de code van fcapri "(millis() - buttonPressTime > 200)" erbij plakken.
@fcapri
De arduino IDE gebruikt alleen INT0 en INT1. De pin change interrupts worden in de IDE niet ondersteund, maar zijn in de processor wel degelijk beschikbaar.
Het is wel zo makkelijk om for loopjes en arrays te gebruiken als je 6 inputs en outputs wil schakelen. Dus de globale variabelen arrays van maken en de rest in dikke for-loops. Zoiets dus:
const uint8_t inputs[] = { 2, 3, 4, 5, 6, 7 };
const uint8_t outputs[] = { 8, 9, 10, 11, 12, 13 };
boolean oldStates[] = { 0, 0, 0, 0, 0, 0 };
void setup() {
for (int i = 0; i < 6; i++)
{
pinMode(inputs[i], INPUT);
pinMode(outputs[i], OUTPUT);
digitalWrite(outputs[i], LOW);
}
}
void loop() {
boolean currentState;
for (int i = 0; i < 6; i++)
{
currentState = digitalRead(inputs[i]);
if (currentState != oldStates[i]) {
if (currentState == HIGH) {
digitalWrite(outputs[i], !digitalRead(outputs[i])); // flip ouput
}
oldStates[i] = currentState;
}
}
}