Go Down

Topic: Lettura Tasti con PCF8574 (Read 5603 times) previous topic - next topic

riciweb

Jan 31, 2014, 06:55 pm Last Edit: Feb 01, 2014, 02:18 pm by riciweb Reason: 1
Ciao a tutti,  :)
purtroppo, con il mio progetto, per motivi vari sono un po' fermo, così mi concentro un po' sulle ottimizzazioni…
Una cosa che volevo fare da tempo, era migliorare la lettura dei tasti: attualmente, nel mio sketch, vengono letti utilizzando la libreria IOexp che interroga a ripetizione il PCF8774AP a cui sono collegati i tasti sperando che prima o poi venga premuto un tasto, di fatto il bus I2C è perennemente spazzolato inutilmente e questo non mi piaceva affatto…
L'obiettivo quindi era interrogare il PCF incriminato solo se effettivamente premo un tasto ed ho avuto il compito facilitato dal PCF stesso che ha un bel piedino INT open drain, ovvero attivo quando è basso (ha bisogno di una R di pull up da 4K7).
Mi ha un po' messo in difficoltà perché a causa di un'errata traduzione del datasheet, non avevo capito che ad ogni lettura l'INT si disabilita, poi però è andato tutto bene, in allegato c'è lo sketch (che poi implementerò in quello del controller), nel quale è incluso anche l'utilizzo di un buzzer per avere un feedback sonoro quando viene premuto un tasto.
Non contento del lavoro fatto, mi sono dedicato sul lato hardware al debouncing dei tasti, attualmente, sempre nel mio progetto, uso un semplice circuito basato su RC, ma non ero soddisfatto, così ho voluto migliorare anche questa parte; ho fatto un po' di ricerche ed alla fine ho scelto di realizzare quello che ho trovato a questo link: http://www.ikalogic.com/de-bouncing-circuits/
Fatte un po' di prove su breadboard, ho disegnato il circuitino ed il PCB in allegato che poi diventerà il modulo tasti del mio progetto. Non sono ancora però sicuro di aver fatto un buon lavoro, così eccomi a chiedervi cosa ne pensate.  :smiley-red:
Grazie in anticipo per il tempo che vorrete dedicarmi.

Documentazione:
http://www.ti.com/lit/ds/symlink/pcf8574a.pdf
http://www.settorezero.com/wordpress/utilizzare-l-io-expander-pcf8574/
http://www.ti.com/lit/ml/scyb031/scyb031.pdf
http://www.ikalogic.com/de-bouncing-circuits/

P.S. Ho postato in "Generale" generale perché tratto sia di hardware che di software e non nel topic del mio progetto, perché ho pensato che l'input con i tasti così come l'ho realizzato può tornare utile in altre applicazioni, spero di aver fatto la cosa giusta.


Riccardo

PaoloP

#1
Jan 31, 2014, 07:00 pm Last Edit: Jan 31, 2014, 07:14 pm by PaoloP Reason: 1
Intanto mi segno e ti faccio i complimenti per la realizzazione.
Nel fine settimana leggo tutto con calma.

Riporto qui la parte sull'interrupt del PCF
Quote
The PCF8574A provides an open-drain output (INT) that can be connected to the interrupt input of a microcontroller. An interrupt is generated by any rising or falling edge of the port inputs in the input mode. After time, tiv, INT is valid. Resetting and reactivating the interrupt circuit is achieved when data on the port is changed to the original setting or data is read from, or written to, the port that generated the interrupt.
Resetting occurs in the read mode at the acknowledge bit after the rising edge of the SCL signal, or in the write mode at the acknowledge bit after the high-to-low transition of the SCL signal. Interrupts that occur during the acknowledge clock pulse can be lost (or be very short) due to the resetting of the interrupt during this pulse.
Each change of the I/Os after resetting is detected and, after the next rising clock edge, is transmitted as INT. Reading from, or writing to, another device does not affect the interrupt circuit.
By sending an interrupt signal on this line, the remote I/O can inform the microcontroller if there is incoming data on its ports without having to communicate via the I2C bus. Therefore, the PCF8574A can remain a simple slave device.

marinaio67


leo72

Complimenti per il progettino.

Due suggerimenti, sono sciocchezze, ma mi preme dirle perché poi te le ritrovi anche in altri progetti  ;)
1. Quando nei casi in cui usi millis per il debounce, io suggerisco di fare l'assegnazione alla variabile che contiene il momento dell'attivazione all'uscita del blocco di codice.
Tu fai un oldtasto = millis() prima di eseguire diverse cose che ti portano via del tempo, comprese accesi sul bus I2C e scritture seriali. Perdi poco, ma quel poco in caso di un intoppo potrebbe diventare molto. E sfalsarti il dato.

2. Fai un controllo if (counter == 1) per controllare se è stato premuto un tasto, ma c'è la possibilità che counter possa diventare maggiore di 1?
Per evitare questi dubbi, farei un controllo generico sul fatto che counter sia 0 o maggiore, quindi metterei un semplice if(counter), che risulta vero in tutti i casi in cui counter abbia un valore diverso da 0.


riciweb

#4
Jan 31, 2014, 08:19 pm Last Edit: Jan 31, 2014, 08:21 pm by riciweb Reason: 1

Intanto mi segno e ti faccio i complimenti per la realizzazione.
Nel fine settimana leggo tutto con calma.


Grazie Paolo, aspetto le tue conclusioni  :)


Complimenti!  :)


Grazie, ma non è che abbia fatto poi chissa cosa, ho voluto però condividere per i principianti come me..


Complimenti per il progettino.
Due suggerimenti, sono sciocchezze, ma mi preme dirle perché poi te le ritrovi anche in altri progetti  ;)
1. Quando nei casi in cui usi millis per il debounce, io suggerisco di fare l'assegnazione alla variabile che contiene il momento dell'attivazione all'uscita del blocco di codice.
Tu fai un oldtasto = millis() prima di eseguire diverse cose che ti portano via del tempo, comprese accesi sul bus I2C e scritture seriali. Perdi poco, ma quel poco in caso di un intoppo potrebbe diventare molto. E sfalsarti il dato.

2. Fai un controllo if (counter == 1) per controllare se è stato premuto un tasto, ma c'è la possibilità che counter possa diventare maggiore di 1?
Per evitare questi dubbi, farei un controllo generico sul fatto che counter sia 0 o maggiore, quindi metterei un semplice if(counter), che risulta vero in tutti i casi in cui counter abbia un valore diverso da 0.


Grazie Leo, ma perdonami se non ho capito bene cosa vuoi dirmi...
1. Non ho usato millis per fare il debounce, di fatto è proprio quello che ho cercato di evitare complicando, ma nemmeno poi tanto, la parte hardware, in realtà oldtasto lo uso per fare un timing sulla ripetizione del valore del tasto nel caso lo si tenga premuto, appena lascio tasto torna=0.
2. Appena ti ho letto, ho subito pensato che era così, ma appena ho provato, leggitasto() ha smesso di funzionare, ma non ho capito perché...  :smiley-red:

Ciao Riccardo.
Riccardo

leo72

1. Ho visto che esegui un blocco di codice solo se la pressione del pulsante è avvenuta a più di 200 ms dalla precedente. E' una specie di debounce, per evitare che l'utente si diverta a pigiare sui pulsantini magari 2 volte, o mi sbaglio?
Comunque, tu fai un'assegnazione a oldtasto del valore di millis, poi esegui tutta la pappardella del blocco di codice. Se la metti in fondo al blocco, quell'assegnazione, in questo modo la prox volta il controllo viene eseguito su 200 ms dal termine del blocco di codice. Consideri, cioè, una specie di "comporto" tutto qui  ;)

2. if (counter) equivale ad un if(counter>=1) oppure a if(counter!=0).
Non vedo perché non debba funzionare, a meno che non abbia tralasciato qualche altra porzione del tuo codice che fa qualcos'altro.

nid69ita

Complimenti e grazie per la condivisione.
Una cosa pero'
Nel titolo citi pcf8574 ma nel post PCF8774AP, quale usi?
my name is IGOR, not AIGOR

riciweb


1. Ho visto che esegui un blocco di codice solo se la pressione del pulsante è avvenuta a più di 200 ms dalla precedente. E' una specie di debounce, per evitare che l'utente si diverta a pigiare sui pulsantini magari 2 volte, o mi sbaglio?
Comunque, tu fai un'assegnazione a oldtasto del valore di millis, poi esegui tutta la pappardella del blocco di codice. Se la metti in fondo al blocco, quell'assegnazione, in questo modo la prox volta il controllo viene eseguito su 200 ms dal termine del blocco di codice. Consideri, cioè, una specie di "comporto" tutto qui  ;)

2. if (counter) equivale ad un if(counter>=1) oppure a if(counter!=0).
Non vedo perché non debba funzionare, a meno che non abbia tralasciato qualche altra porzione del tuo codice che fa qualcos'altro.


Ciao Leo,
ora ho compreso la parte 1 ed ho modificato lo sketch.
Per la parte 2, non ho tralasciato nessuna parte di codice.
Provo a spiegare cosa succede nello sketch:
1. premo il tasto e la ISR statotasto() incrementa counter a 1
2. leggitasto verifica counter ed esegue la lettura del pcf, qui di fatto può effettivamente valere solo la condizione if (counter == 1) ciò è dovuto al fatto che la ISR si riattiva anche se rilascio a causa del fatto che INT del PCF si disattiva e dopo una lettura torna basso ed ecco quindi che la condizione if (counter) equivale ad un if(counter>=1) oppure a if(counter!=0) mi fa rientrare nella lettura effettiva del tasto e non reset del PCF che di fatto esegue si una lettura ma ha lo scopo di riattivare appunto l'INT del PCF, non o se sono riuscito a farmi capire, ma di fatto è ciò che succede.
3. rilascio il tasto INT del PCF va basso per il motivo di cui sopra, la ISR statotasto incrementa nuovamente counter che diventa 2 ed attiva l'else in cui resetto il pcf con una lettura a vuoto ed azzero la variabile tasto.


Complimenti e grazie per la condivisione.
Una cosa pero'
Nel titolo citi pcf8574 ma nel post PCF8774AP, quale usi?


Hai ragione, in effetti esistono due versioni di questo expander: PCF8574 e PCF8574A, i miei hanno anche una P finale ma non so cosa significhi.
Di fatto in ogni caso le differenza tra le due versioni è unicamente nell'indirizzamento degli IC, in allegato ti ho messo delle immagini che spero spieghino quello che ho appena scritto  ;)

Ciao Riccardo.

P.S. In allegato anche il codice corretto con il suggerimento di Leo sulla variabile oldtasto.

Riccardo

Etemenanki


... http://www.ikalogic.com/de-bouncing-circuits/...


Solo un'appunto ... gli esempi "hardware" di questa pagina non sono completamente corretti ...

Quando si usa un debounce "hardware", andrebbe sempre messa anche una resistenza in serie al pulsante (di solito, un decimo o meno del valore della resistenza verso il positivo, mai troppo alta, altrimenti non da un corretto stato LOW) ... per due ragioni ...

Prima di tutto, se il condensatore e' di capacita' abbastanza elevata, chiuderlo a massa quando e' carico provoca sempre un picco di corrente, seppure istantaneo, nel pulsante, e se i contatti del pulsante sono molto deboli (tipo ad esempio pulsantini a membrana in inchiostro conduttivo o SMD sigillati da segnali o simili) a lungo termine si possono rovinare e smettere di funzionare correttamente, (si "brucia" il punto di contatto, cosa che fra l'altro aumenta esponenzialmente i falsi contatti che si volevano evitare :P) ... e poi il debounce si basa sulla costante RC del circuito, con una sola resistenza verso il positivo hai una costante RC in fase di apertura, ma per avere una costante RC decente anche in fase di chiusura (e quindi eliminare il massimo possibile dei rimbalzi) la resistenza di 0 ohm del pulsante e' "un tantino" bassa ... certo, va messa piu bassa, ma 10K e 470 ohm funzionano decisamente meglio che 10K e 0 ohm :P XD
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

riciweb

Ciao Etemenanki,
grazie, mi stai suggerendo quindi un circuito come quello in allegato?

Ciao Riccardo.
Riccardo

Etemenanki

Esatto, solo con la differenza che, probabilmente, la porta logica non serve neppure ... in un'altra discussione si accenava al fatto che gli ingressi di Arduino hanno gia una loro isteresi intrinseca (di circa 1,5V per 5V di alimentazione, o comunque di un terzo del valore dell'alimentazione), quindi in teoria non dovrebbe servirne una esterna ... almeno se i cavi non sono troppo lunghi ...

Poi io in alcune shield ho messo anche degli zener in parallelo al condensatore, come ulteriore protezione (zener del valore della VCC, catodo al pin ed anodo a massa), cosi proteggono anche da sovratensioni e da inversione di tensione, ma dipende dall'applicazione, probabilmente nella maggior parte dei casi sono superflui ... voglio dire, se il circuito e' in un contenitore con i fili corti, non e' che servano piu di tanto, se invece ci devo collegare roba a 10 metri di distanza con cavi che non so dove passano, preferisco metterceli ...

Oppure, se attivi il pullup interno dei pin digitali usati come ingresso, che e' da 20K, puoi togliere la resistenza che va al positivo (utile con stampati piccoli, tanti ingressi e poco spazio :)) ed usare 1K per quella in serie (il pulsante reagira' con qualche millisecondo in piu di ritardo, ma i valori piu alti aumenteranno la soppressione dei rimbalzi)
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

leo72

@ricdata:
tra PCF8574 e PCF8574A cambia in pratica solo l'ID dell'integrato da usare sul bus I2C.
La "P" finale indica che il chip è in formato DIP  ;)

riciweb

@Etemenanki
Grazie per il tempo che mi stai dedicando...  :)
ti scrivo come ho ragionato, ma ricorda che sono un autodidatta, quindi ti prego non scatenare una delle tue guerre termonucleari  :P ...
1. Leggo i tasti con il pcf, quindi l'isteresi di arduino di cui avevo letto qualche tempo fa anche io non l'ho considerata
2. Ho pensato che i rimbalzi dei tasti potessero a lungo andare o generare errori di lettura del pcf stesso o comunque danneggiarlo in qualche modo
3. Nei miei esperimenti iniziali proprio il bouncing mi ha dato più di un grattacapo (leggi tastini o bread di scarsa qualità o mia incapacità stessa), il tarlo/ansia del debouncing ormai mi accompagna, ma ho cercato cmq una soluzione relativamente semplice.
4. Ho voluto usare la porta logica proprio per mandare al PCF uno stato logico pulito e blindarne la lettura, poi l'SN74HC14 costa veramente una sciocchezza.
5. Ho visto anche io soluzioni in cui si usano gli zener, ma proprio per avere un circuito un pochino più semplice li ho evitati, leggendoti poi in relazione alla lunghezza dei cavi, se guardi il pcb il problema non lo ho quindi preferisco non metterli ma implementare la resistenza che mi hai suggerito.
Grazie ancora.

@leo72
Grazie, ho imparato un'altra cosa anche io.

Ciao Riccardo.

Ciao Riccardo.
Riccardo

leo72

Ops, ti ho chiamato ricdata, più sopra  :smiley-sweat:

Etemenanki


... Leggo i tasti con il pcf, ...


Giusto, errore mio per non averlo considerato ... in quel caso si, o gli hc14 o i 40106 (sempre 6 inverter con isteresi) sono un'ottima soluzione ;)
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

Go Up