So che se ne è parlato fin troppo, ma ci sto provando da più di un'ora senza riuscirci...
Sono partito dallo schema di Etem che ho trovato in un post (vedi sotto lo schema).
Nello specifico sto provando con la parte sinistra dello schema (pull-up):
resistenza di pull-up da 4k7
altra resistenza da 220
condensatore da 100nf
I collegamenti li vedete nella foto.
Con questo codice:
#define BUTTON 7
unsigned long i = 0;
void setup() {
pinMode(BUTTON, INPUT);
Serial.begin(9600);
}
void loop() {
if (digitalRead(BUTTON) == LOW) {
Serial.println(i++);
}
}
mi aspetterei di vedere sul monitor seriale il numero che si incrementa di 1 ogni pressione, invece vedo sfilze di 40 / 50 valori progressivi ad ogni pressione...
Sono sicuro che sto sbagliando da qualche parte, ma non capisco dove...
Tu premi una volta, ma il loop legge decine di volte ad ogni tua pressione, perche' e' molto piu veloce di te ... il debounce serve a fare in modo che il pulsante non dia un sacco di segnali ad ogni pressione, non a fare in modo che il contatore avanzi solo di uno alla volta, quello lo deve fare il modo in cui leggi l'ingresso ... devi rivedere il software per fare in modo che il conteggio avanzi di uno, e poi non faccia piu nulla finche' non hai rilasciato il pulsante prima di una nuova pressione ... ci sono diversi esempi anche di quello, in giro, ti serve una variabile byte ed un paio di if che controllino due cose insieme ...
Ok, ho capito dove vuoi arrivare.
Io sono convinto di premere una volta, invece la mia pressione dura diversi millisecondi più diversi apri/chiudi dovuti al pulsante, ecc...
Ma allora non ho capito a cosa serve il debounce...
Credevo che servisse per evitare questo effetto. Io premo "una volta" (con tutti i difetti del caso) e il debounce fa in modo che il micro veda veramente una sola pressione.
Ho capito male?
Se ci devo mettere comunque tutta la parte sw allora faccio tutto via sw...
Edit: mi spiego meglio... credevo che resistenza e condensatore introducessero una sorta di "ritardo" in modo che pressioni inferiori a un tot di millisecondi venissero viste come una sola pressione
fratt:
Ma allora non ho capito a cosa serve il debounce...
Te lo spiego subito ... prendi un codice appena più complesso come questo:
/* DIGITAL READ OF A BUTTON - SIMPLE METHOD
The code shows how to read an external button.
gpb01 - 11.03.2018
*/
//declare the pins used into the sketch
const byte BUTTON_PIN = 9; //button pin
const byte LED_PIN = 13; //integrated LED
//global variables
byte ledStatus = 0; //keep the LED status
byte butStatus = HIGH; //actual button status
byte prevButStat = HIGH; //previous button status
//setup routine
void setup() {
pinMode(BUTTON_PIN, INPUT); //input pin (try pull-up)
pinMode(LED_PIN, OUTPUT); //output pin with LED
digitalWrite(LED_PIN, ledStatus); //light off the LED
}
//loop routine
void loop() {
// check the button status
butStatus = digitalRead(BUTTON_PIN);
//check if the button has been pressed
if ( (butStatus == LOW) && (prevButStat == HIGH)) {
ledStatus ^= 1; //flip LED status (XOR)
digitalWrite(LED_PIN, ledStatus);
}
prevButStat = butStatus;
}
... è senza debounce software, ed usalo anche senza debounce hardware. Vedrai che NON sempre la pressione del pulsante effettua un singolo cambio di stato, ma magari il LED è spento e fa un lampetto e poi torna spento o viceversa. NON è cosa che capita regolarmente, quindi fai parecchie prove e vedrai apparire il problema.
No, il debounce evita tutti quei piccoli "apri e chiudi" del rimbalzo, che falserebbero anche le letture fatte con un programma corretto ... ma nel tuo loop non leggi il pulsante una sola volta, lo leggi ad ogni ciclo del loop, quindi finche' rimane chiuso, ogni ciclo aggiunge 1 ... uno dei modi possibili per evitarlo e' usare una variabile byte ed un if-else ...
stato iniziale variabile 0
SE pulsante premuto E variabile a zero, aggiungi 1 E metti variabile ad 1
ALTRIMENTI SE pulsante RILASCIATO e variabile ad 1, rimetti variabile a 0
ok, ho capito cosa intendi e cosa fa il tuo sketch.
ammetto che attribuivo al debouce una funzione diversa.
pensavo che essendo il condensatore "lento" a caricarsi "rallentasse" la sfilza di pressioni che il micro legge.
a questo punto però mi sorge spontanea la domanda...
c'è un modo per far vedere al micro una sola pressione anche per quella che io umano intendo una sola pressione?
cioè introdurre una sorta di "ritardo" hw che fa vedere some singole pressioni tutte le pressioni che durano meno di 100ms per esempio. o si fa sempre e solo via sw?
fratt ... hai provato il codice? ? ? ... ecco prima provalo, poi proseguiamo, perché, da quello che scrivi ... mi sembra che NON hai ancora le idee chiare.
Quando premi (o rilasci) un pulsante succede questo:
... hai idea quante volte il programma sopra scritto fa cambiare stato a quel LED (magari in modo così veloce che tu manco te ne accorgi) ? ? ?
Per evitare il problema, due sono le soluzioni, una software, che usa dei delay() ed una hardware che usa una rete integratrice R/C.
Il problema delle "pressioni multiple" dovute ai contatti fisici del pulsante l'avevo già capito.
E adesso ho capito che il debounce risolve "solo" quella parte del problema.
Rimane, dal mio punto di vista, il problema del loop che gira molto veloce e legge "molte" pressioni perché io sono lento a premere. Via software ho già risolto in vari modi (quei sul forum c'è pieno di esempi).
Forse con un esempio riesco a farmi capire: per evitare pressioni multiple "misuro" la durata della pressione con millis e considero valide solo le pressioni superiori a 200ms (valore empirico ottenuto con qualche prova).
Con questo sistema ogni volta che premo il pulsante il mio sketch vede una ed una sola pressione. Problema risolto.
Mi chiedevo solo se esiste un modo per risolvere via hardware anche questo "problema".
Ok grazie, ma da una ricerca veloce mi pare di capire che va oltre le mie possibilità.
Grazie a tutti, ho capito che avevo interpretato erroneamente lo schema di debounce.
fratt:
avevo interpretato erroneamente lo schema di debounce
Il debounce serve sempre, ma in più quello che volevi fare è l'edge detect, cioè il riconoscimento di un fronte, che si fa sempre confrontando la lettura attuale con la precedente, questo è il tuo codice con l'aggiunta dell'edge detect:
Il fatto che con un debounce software ottieni anche l'edge detect dipende da come è scritto il debouncer.
E comunque se lo scopo è rilevare un fronte (istante di pressione), l'idea di contare più o meno empiricamente la durata di una pressione non mi sembra una buona idea per due motivi, primo perché deve trascorre del tempo, e poi perché l'utente pigiatore deve prestare un'attenzione "innaturale": se comando qualcosa con una pressione non devo avere anche l'ansia di premere troppo a lungo o troppo poco.
Tutti i ragionamenti fatti "contro" le mie osservazioni non fanno una piega. Come ho scritto in precedenza, tutto è nato da una mia errata interpretazione del debounce.
Sul modo di fare dobounce software ne ho lette e viste di quasi tutti i colori. E in quasi tutte ho visto utilizzare un qualche ritardo (che fosse col delay o col millis). Io ho "estremizzato" il concetto valutando solo questa durata/ritardo in modo da poter distinguere tra pressioni brevi e pressioni lunghe.
Probabilmente sono un utente fortunato e in numerose pressioni non ho mai avuto problemi anche senza prestare attenzione a come premevo il pulsante.
Sicuramente non è l'unico modo di risolvere la cosa, ma diciamo che è quello che mi è venuto meglio.
Grazie per lo schema.
Tutto sto casino è nato perché io pensavo che il classico schema di debounce con resistenza e condensatore facesse già tutto da solo...