Op 30 december 2019 21:27:22 schreef deKees:
@fcapriDe 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.
Pin-change wordt weldegelijk ondersteund. De ondersteunde modes zijn LOW, FALLING, RISING en CHANGE.
EDIT: Wacht, je bedoelde wat anders denk ik. PCINT[x] zijn niet ondersteund in de arduino IDE, maar INT0 en INT1 wel. INT0 en INT1 zijn wel triggerbaar op pin change.
[Bericht gewijzigd door Deskinspin op (19%)]
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Dat (2 posts terug) is precies zoals ik bedoel in een van mijn vorige posts.
En de ontdender moet hier er natuurlijk ook nog bij.
Je moet die nu ook per pin bijhouden en zowel laag als het hoog niveau "debouncen".
Dat is niet zo simpel als "ohm pi" en "fcapri" zeggen.
Het makkelijkste gaat dat door ook een teller array per pin bij te houden voor de debounce zowel aan de HIGH als LOW kant. Je telt tot de pin minimaal x-keer als echt continue hoog gezien wordt, hetzelfde doe je voor de detectie van een laag signaal. Effectief maak je zo een digitaal filter.
Daarna doe je pas de edge detectie.
In de loop waar je de knop leest (met een niet al te hoge frequentie) doe je hetvolgende:
Gebruik bijvoorbeeld een 16-bit register, de pin status schuif je als bit er van rechts naar links in.
Dan compare je de waarde met 0xffff, is dat waar dan is de button hoog en doe je wat er moet gedaan worden als de knop hoog is.
Dan compare je de waarde met 0x0000, is dat waar dan is de button laag en doe je wat er moet gedaan worden als de knop laag is.
In alle andere gevallen doe je NIETS.
Stel je loopsnelheid is ca 2 ms dan kun je tot 32 ms "kraken" in de schakelaar wegwerken. Uiteraard kun je meerdere bitjes gebruiken of nog beter in een timer interrupt deze read + debounce doen en dan globale variablen zetten (zo doe ik het meestal). Dan heb je 100% controle over de snelheid en het filtergedrag wat er gebeurd.
Maar het blijft beperkt tot de INT0 en INT1 pin. De PCINTxx op alle 24 andere pinnen zit niet in de Arduino IDE maar wel in de processor, of ik moet me al sterk vergissen. Ik doe weinig met arduino dus misschien heb ik het gemist.
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Een interrupt gebruiken om mechanische switches te lezen is niet fijn. Je krijgt een hele bak interrupts binnen bij bounces en je moet alsnog met timers gaan klooien om het te debouncen. Het wordt daar zeker niet simpeler op.
@deKees
PCINTxx werkt en wordt wel degelijk ondersteund in de Arduino IDE.(Uno,Nano,etc...)
Er is wel een groot verschil tussen INT en PCINT
Bij INT kun je kiezen wat de interrupt trigerd (Rising,Faling,Both,High,Low)
Bij PCINT is dit bij elke verandering.
Maar hier is TS waarschijnlijk niet verder mee geholpen.
Ik zou ook met interrupts werken en een functie debounce.
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Op 30 december 2019 22:01:08 schreef Gij Kieken:
Ik zou ook met interrupts werken en een functie debounce.
Ik zeker niet, zie mijn vorige post. Een interrupt behoort minimale code te bevatten en zeker geen blocking functies.
De gehele debounce code en waarschijnlijk ook de toggle functie moet je nu in de interrupt handler gaan prakken.
Sommige functies mag je zelfs niet aanroepen in een interrupt handler. Geen idee of die millis() functie interrupt safe is.
Het wordt nog ingewikkelder omdat, zoals ik nu hier van jullie hoor dat er maar een interrup handler is, je dus zelf moet uitzoeken welke INT het was. Als je weet dat er misschien wel 2 of meer knoppen ingedrukt kunnen worden kun je die ook missen als je de status per pin niet goed kunt resetten. Daar ken ik de chip niet goed genoeg voor, daarvoor moet ik in het datasheet duiken om het precies te kunnen zeggen of het problematisch wordt.
[Bericht gewijzigd door henri62 op (30%)]
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Een interrupt gebruiken om mechanische switches te lezen is niet fijn.
Je krijgt een hele bak interrupts binnen bij bounces en je moet alsnog met timers gaan klooien om het te debouncen.
Je moet ook helemaal geen pin interrupts gebruiken, maar alleen een timerinterrupt.
Ik lees bijv. iedere 1 of 5mS de ingangen uit, en bepaal dan wat er moet gebeuren. Simpel, universeel toepasbaar; debounce kun je dan ook meteen doen.
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Op 30 december 2019 22:10:25 schreef Arco:
[...]
Je moet ook helemaal geen pin interrupts gebruiken, maar alleen een timerinterrupt.
Ik lees bijv. iedere 1 of 5mS de ingangen uit, en bepaal dan wat er moet gebeuren. Simpel, universeel toepasbaar; debounce kun je dan ook meteen doen.
Dat is een open deur intrappen: Dat is ook precies wat ik een paar posts geleden zei.
Inside the attached function, delay() won’t work and the value returned by millis() will not increment.
Als je al met interrupts werkt dan kun je inderdaad beter gaan pollen in een timer interrupt. Dan kun je ook een state machientje bouwen om te debouncen zonder dat je in de interrupt routine moet blijven hangen. Pin change interrupts zijn niet handig voor toetsen.
En PCINTxx kun je inderdaad wel gebruiken in de arduino IDE, maar alleen omdat die door de onderliggende avr-gcc compiler wordt ondersteund. En dan moet je de datasheets gaan lezen om te zien hoe het werkt. De arduino reference gaat niet verder dan max 2 interrupts voor een NANO en een UNO.
Inderdaad bij gebruik van hardware interrupts is het niet makkelijk om te debouncen.
millis werkt niet in een ISR micro's wel maar je kunt best de boel niet ophouden met delays of serial prints een ISR.
Wat ik soms gebruik in dergelijke gevallen is direct port manipulation.
Je leest één byte in van het betreffende port register en je bent weg op,er is wel wat rekenwerk aan, maar het is veel vlugger dan de gebruikelijke manier.
Op 30 december 2019 20:55:39 schreef henri62:
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).
Ja sorry, je hebt gelijk.
Heb over het hoofd gezien dat het de bedoeling is dat de led maar eenmaal toggled als je de knop indrukt (en vasthoud).
Op 30 december 2019 21:38:15 schreef henri62:
En de ontdender moet hier er natuurlijk ook nog bij.
Je moet die nu ook per pin bijhouden en zowel laag als het hoog niveau "debouncen".Dat is niet zo simpel als "ohm pi" en "fcapri" zeggen.
Het makkelijkste gaat dat door ook een teller array per pin bij te houden voor de debounce zowel aan de HIGH als LOW kant. Je telt tot de pin minimaal x-keer als echt continue hoog gezien wordt, hetzelfde doe je voor de detectie van een laag signaal. Effectief maak je zo een digitaal filter.
Daarna doe je pas de edge detectie.
Zo ingewikkeld hoeft het niet.
Je hebt gelijk. Het is iets ingewikkelder dan ik dacht. Je moet de ingang bufferen. Zodra je een flank aan de ingang ziet kopieer je het ingangssignaal in een bufferbitje en start je een timer en gedurende het lopen van die timer kijk je gewoon niet naar de ingang. Na afloop van de timer kijk je weer naar de ingang net zolang totdat de ingangstoestand weer verandert. Tijdens de bounce-periode weet je zeker dat het ingangssignaal van laag naar hoog of van hoog naar laag gaat. Je hoeft niet te wachten totdat het ingangssignaal uitgestuiterd is. Uiteraard heeft iedere ingang zijn eigen timer en bufferbitje. Of je leest alle ingangen eens per 100 milliseconde in. Dan heb je één timer nodig. Binnen 100 ms is een contact wel uitgestuiterd. Het gebufferde signaal deel je door twee
-------------- --------------
|||| ||||| |||| |||||
------------- ------------- ----
gebufferde ingang:
+-------------+ +-------------+
| | | |
-----------+ +-----------+ +-----
het toggle signaal:
+-------------------------+
| |
-----------+ +-------------------
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Ik vind een 1mS timer toch wat handiger. (timer heb je toch vaak al nodig om leds e.d. te laten knipperen)
Je hoeft dan alleen vast te stellen dat de switch 20x (20mS) achtereen ingedrukt was om een valid key te vinden...
Je zou best wel eens gelijk kunnen hebben. Het verhaaltje van mij is toch vrij ingewikkeld. In mijn werkzame leven las ik eens per 100 ms alle ingangssignalen tegelijk in. Dan had ik geen last van contactdender.
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Op 30 december 2019 23:47:29 schreef Arco:
Ik vind een 1mS timer toch wat handiger. (timer heb je toch vaak al nodig om leds e.d. te laten knipperen)
Je hoeft dan alleen vast te stellen dat de switch 20x (20mS) achtereen ingedrukt was om een valid key te vinden...
Vandaar dat ik zeg om een byte (of word) te gebruiken (afhankelijk van je timer loop tijd en debounce gedrag) waar je iedere read loop een bitje in schuift. Code technisch is dat bijna niks en het comparen kost ook bijna niks. Dat kan zeer efficient met een heleboel contacten.
Een timertje gebruiken is veel meer code en complexiteit, zeker als je meer contacten moet lezen dan je echte timers hebt. Je moet dan je timer tick bewaren, ophogen als je een 1 ziet, resetten als die weer nul is comparen met 8 16 of 20 whatever etc. en dat voor beide flanken dat is echt een stuk minder efficient. Zowiezo wil je je hardware timers niet "verspillen" aan dit soort futiliteiten.
En zoals arco zegt: bijna altijd heb je wel een timer interrupt al ergens draaien waar je deze read loop in kunt proppen. Bij voorkeur in assembly geschreven als het echt efficient moet.
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Volgens mij zijn jullie de klant (de TS) een beetje uit het oog verloren met jullie interrupts... Is ie geholpen nu?
Op 30 december 2019 21:28:28 schreef Deskinspin:
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; } } }
TS is het beste geholpen met bovenstaande code. Deze is volgens mij foutvrij of vrijwel foutvrij.
Geen interrupts en geen bestrijding contactdender.
Mocht bovenstaande code niet lekker werken, dan horen wij dat wel van TS.
BmB
Frysk bloed tsjoch op! wol no ris brûze en siede, en bûnzje troch ús ieren om!
Ik leest nog altijd mee, boeiende reacties!
momenteel lijkt onderstaande code te werken maar er is altijd ruimte voor optimalisatie en verbetering natuurlijk. Dit is combinatie van antwoorden hier en op youtube zijn gegeven 
Ik moet de boel nog even goed in elkaar solderen, dan weet ik het zeker.
int LED1State=0;
int LED2State=0;
int LED3State=0;
int LED4State=0;
int LED5State=0;
int LED6State=0;
int ButtonPin1 = 02; //ingangen
int ButtonPin2 = 03;
int ButtonPin3 = 04;
int ButtonPin4 = 05;
int ButtonPin5 = 06;
int ButtonPin6 = 07;
int LEDPin1 = 8; //uitgangen
int LEDPin2 = 9;
int LEDPin3 = 10;
int LEDPin4 = 11;
int LEDPin5 = 12;
int LEDPin6 = 13;
int Button1New; //Knopstatus
int Button1Old=1;
int Button2New;
int Button2Old=1;
int Button3New;
int Button3Old=1;
int Button4New;
int Button4Old=1;
int Button5New;
int Button5Old=1;
int Button6New;
int Button6Old=1;
int dt=100;
void setup(){
pinMode(ButtonPin1, INPUT);
pinMode(ButtonPin2, INPUT);
pinMode(ButtonPin3, INPUT);
pinMode(ButtonPin4, INPUT);
pinMode(ButtonPin5, INPUT);
pinMode(ButtonPin6, INPUT);
pinMode(LEDPin1, OUTPUT);
pinMode(LEDPin2, OUTPUT);
pinMode(LEDPin3, OUTPUT);
pinMode(LEDPin4, OUTPUT);
pinMode(LEDPin5, OUTPUT);
pinMode(LEDPin6, OUTPUT);
}
void loop(){
//KNOP1
Button1New=digitalRead (ButtonPin1);
if (Button1Old==0 && Button1New==1){
if (LED1State==0){
digitalWrite(LEDPin1, HIGH);
LED1State=1;
}
else{
digitalWrite(LEDPin1, LOW);
LED1State=0;
}
}
Button1Old=Button1New;
delay(dt);
//KNOP2
Button2New=digitalRead (ButtonPin2);
if (Button2Old==0 && Button2New==1){
if (LED2State==0){
digitalWrite(LEDPin2, HIGH);
LED2State=1;
}
else{
digitalWrite(LEDPin2, LOW);
LED2State=0;
}
}
Button2Old=Button2New;
delay(dt);
//KNOP3
Button3New=digitalRead (ButtonPin3);
if (Button3Old==0 && Button3New==1){
if (LED3State==0){
digitalWrite(LEDPin3, HIGH);
LED3State=1;
}
else{
digitalWrite(LEDPin3, LOW);
LED3State=0;
}
}
Button3Old=Button3New;
delay(dt);
//KNOP4
Button4New=digitalRead (ButtonPin4);
if (Button4Old==0 && Button4New==1){
if (LED4State==0){
digitalWrite(LEDPin4, HIGH);
LED4State=1;
}
else{
digitalWrite(LEDPin4, LOW);
LED4State=0;
}
}
Button4Old=Button4New;
delay(dt);
//KNOP5
Button5New=digitalRead (ButtonPin5);
if (Button5Old==0 && Button5New==1){
if (LED5State==0){
digitalWrite(LEDPin5, HIGH);
LED5State=1;
}
else{
digitalWrite(LEDPin5, LOW);
LED5State=0;
}
}
Button5Old=Button5New;
delay(dt);
//KNOP6
Button6New=digitalRead (ButtonPin6);
if (Button6Old==0 && Button6New==1){
if (LED6State==0){
digitalWrite(LEDPin6, HIGH);
LED6State=1;
}
else{
digitalWrite(LEDPin6, LOW);
LED6State=0;
}
}
Button6Old=Button6New;
delay(dt);
}
Zou moeten werken volgens mij.
Maar het wordt wel traag met 6 x delay(dt).
Die kun je beter weghalen(of alleen de laatste laten staan).
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Waarom zit die delay() er uberhaupt tig keer in? Moet dat niet gewoon 1 keer zijn? [damn, Kees zeg hetzelfde]
Verder zou je nog eens kunnen kijken of je van dat stukje code wat je steeds herhaalt niet in een functie kunt doen die je meerdere keren aanroept. Kan zijn dat het niks uithaalt hoor.
Boudie
Vervangen DOOR.
Op 1 januari 2020 20:20:07 schreef flipflop:
Kan zijn dat het niks uithaalt hoor.
Maar het is wel betere techniek.
Op 1 januari 2020 20:26:40 schreef Boudie:
[...]
Maar het is wel betere techniek.
DRY; Don't Repeat Yourself. En de oplossing daarvoor heb ik al gegeven, dus die ga ik ook niet herhalen, want DRY.
Een funktie maken gaat zomaar niet omdat je telkens andere variabelen gebruikt. En dat is misschien iets teveel gevraagd van TS?
Maar dat kan wel als je alle variabelen per toets in een struct opslaat. Of als je er arrays van maakt zoals in het voorbeeld van OhmPi.
Ik zou zelf kiezen voor een struct. Dat wordt dan zoiets:
struct LED_BUTTON
{ int ButtonPin;
int LedPin;
int LedState;
int ButtonNew;
int ButtonOld;
};
LED_BUTTON Button1;
LED_BUTTON Button2;
LED_BUTTON Button3;
LED_BUTTON Button4;
LED_BUTTON Button5;
LED_BUTTON Button6;
int dt=100;
void Setup(LED_BUTTON &MyButton, int ButtonPin, int LedPin)
{
MyButton.ButtonPin = ButtonPin;
MyButton.LedPin = LedPin;
MyButton.LedState = 0;
MyButton.ButtonNew = 0;
MyButton.ButtonOld = 1;
pinMode(MyButton.ButtonPin, INPUT);
pinMode(MyButton.LedPin, OUTPUT);
}
void HandleButton(LED_BUTTON &MyButton)
{
MyButton.ButtonNew = digitalRead (MyButton.ButtonPin);
if (MyButton.ButtonOld == 0 && MyButton.ButtonNew == 1)
{
if (MyButton.LedState == 0)
{
digitalWrite(MyButton.LedPin, HIGH);
MyButton.LedState = 1;
}
else
{
digitalWrite(MyButton.LedPin, LOW);
MyButton.LedState = 0;
}
}
MyButton.ButtonOld = MyButton.ButtonNew;
}
void setup()
{
Setup(Button1, 2, 8);
Setup(Button2, 3, 9);
Setup(Button3, 4, 10);
Setup(Button4, 5, 11);
Setup(Button5, 6, 12);
Setup(Button6, 7, 13);
}
void loop()
{
HandleButton(Button1);
HandleButton(Button2);
HandleButton(Button3);
HandleButton(Button4);
HandleButton(Button5);
HandleButton(Button6);
delay(dt);
}
Op 1 januari 2020 20:54:38 schreef deKees:
Maar dat kan wel als je alle variabelen per toets in een struct opslaat. Of als je er arrays van maakt zoals in het voorbeeld van OhmPi.
Was niet 'mijn' voorbeeld, maar van Deskinspin.
Op 1 januari 2020 20:54:38 schreef deKees:
Een funktie maken gaat zomaar niet omdat je telkens andere variabelen gebruikt. En dat is misschien iets teveel gevraagd van TS?Maar dat kan wel als je alle variabelen per toets in een struct opslaat. Of als je er arrays van maakt zoals in het voorbeeld van OhmPi.
Ik zou zelf kiezen voor een struct.
Nu heb je een functie genaamd setup() en een functie genaamd Setup().
Die had je beter initializeButton() o.i.d. kunnen noemen. En je hebt nog steeds rijtjes met variabelen button1, button2, etc. Dat is een aanwijzing dat je eigenlijk een array moet gebruiken waar je overheen gaat met een for-loopje.