Newsgroup: it.hobby.elettronica.digitale
Titolo: Antirimbalzo software

ciao!
qual è il metodo migliore per gestire un pulsante collegato a un uC ? mi
riferisco a un ambiente di sviluppo in C.
intendo una soluzione software per un antirimbalzo. ne ho provate diverse,
dall'aspettare 100-150 ms dopo la prima pressione per vedere se è cambiato
lo stato, a intecettare i fronti di discesa e salita e aspettare *dopo* un
mezzo secondo circa...
un'altra domanda.
spesso lavorando con i micro e i display capita di dover gestire diverse
funzioni con pochi tasti. quale soluzione è migliore (dal punto di vista
della facilità d'uso e dell'efficienza computazionale) per ad esempio creare
un menu a livelli ? del tipo - anche se moooolto più semplice - dei
telefonini. un pulsante fa avanzare la funzione, e altri controllano il
valore. intendo proprio a basso livello. dal un punto di vista logico è
chiarissimo, ma quando si tratta di implementarlo ci sono parecchie
soluzioni: vorrei trovare la più indicata. potreste magari segnalarmi un
sorgente da cui prendere spunto ?
grazie ancora!
Marco

 valore. intendo proprio a basso livello. dal un punto di vista logico è
molto più semplice del menù di un telefonino c'è solo il menù del ristorante
;-)
cmq una macchina a stati e direi 4 pulsanti (su/giù e (conferma/annulla)
tra poco devo modificare una qualche versione di player mp3 su HD con Pic e
andavo in questa ottica (stile iPod)
ciauzz

 cmq una macchina a stati e direi 4 pulsanti (su/giù e (conferma/annulla)
io ne uso solo tre.... ;-)
l'annulla non lo uso, anche perchè è un orologio e quindi le impostazioni
sono molto semplici.
mi interessa la macchina a stati: ma una volta disegnata su carta, in che
modo si può implementare (tipo in C) nel modo più lineare possibile ? hai
qualche esempio da passarmi ?
tieni conto che vorrei imparare a gestire (in modo che fatta una volta una
libreria la potrò riutilizzare con poche modifiche) a parte la normale
pressione di un tasto, la pressione tenuta per più di x secondi e una
assenza di input per più di y secondi (una specie di time-out per
intenderci).
grazie ancora!
Marco


Controlla l'ingresso costantemente (tipo con interruzioni ogni 5 o 10 mS),
quando vedi che il livello è diverso da quello rilevato precedentemente
inizi a contare e quando hai rilevato almeno 5- 10 volte (o quanto vuoi, io
di solito faccio almeno 50 mS) lo stesso livello, aggiorni un bit di memoria
che ti indica lo stato dell'ingresso.
Nel caso che il livello cambi prima di essere arrivato al termine del
conteggio, ricominci da zero senza aggiornare il bit di memoria.
Ciao
Lucio

 conteggio, ricominci da zero senza aggiornare il bit di memoria.
interessante! grazie per il suggerimento!
Marco

 intenderci).
puoi per esempio impostare la variabile alla pressione del tasto su
"KEY_PRESS" e se alla fine delle operazioni hai ancora il tasto premuto
metti su "KEY_PRESS_LONG" etc etc
devi solo stare attento a quanto tempo passi in ogni stato, in quanto magari
vorresti poter gestire un "interrupt" e allora ogni tanto metti un controllo
sulla variabile, nel caso in esempio non distingui il doppio click fatto ad
esattamente 1 secondo di distanza l'uno dall'altro da una pressione lunga...
sta a te modificare lo schema di base per le tue esigenze.
Tieni conto che in ogni stato deve essere garantita l'uscita per andare in
un altro stato, altrimenti sei in loop sempre sullo stesso.
E' una strada semplice ma da testare per bene (magari con l'aiuto di terzi)
ciao

 sorgente da cui prendere spunto ?
Se hai tre tasti immagino tu abbia un UP e DOWN (o LEFT e RIGHT) ed un
OK (o ENTER).
Naturalmente in questo modo non hai la possibilità di implementare
funzioni
di ESC (annullamento) a patto di non identificarle con pressioni
particolari
(tipo la pressione contemporanea dei tasti UP e DOWN per un certo
periodo di tempo).
Normalmente io faccio così:
while(1) {
   ...
   display(REFRESH);
   gestione_tasti();
   ...
}
La routine gestione_tasti() è praticamente l'esempio scritto in
precedenza per
verificare se un tasto è premuto o meno con la funzione di antirimbalzo.
A sua volta la routine gestione_tast() richiama la funzione
display(KEY_UP)
o display(KEY_DOWN) o display(KEY_ESC) se si accorge che uno dei tasti
è stato premuto (era la funzione gestione_tasto() dell'esempio
precedente).
Ora devi scrivere una funzione display() che accetta un parametro che
può
essere REFRESH, KEY_DOWN, KEY_UP, KEY_ESC. Se il parametro è REFRESH
devi
solo preoccuparti di aggiornare la schermata attuale (tipo i secondi se
stai visualizzando un'ora). Se il parametro è KEY_UP, KEY_DOWN, KEY_ESC,
invece, ti devi preoccupare di effettuare un'aziona in funzione del
tasto
premuto.
La cosa non è proprio semplicissima ma credo di averti avviato.
Fammi sapere se hai bisogno di altre info.

             sleep(1000); //aspetti un secondo
Non mi piace molto questo metodo. Una pausa cosě lunga puň dare problemi
altrove. Ovviamente molto dipende da quello che fa il uC ma bloccare
l'esecuzione
del programma per un secondo solo per implementare un antirimbalzo mi
sembra esagerato. Immagina che ci sia anche una seriale da gestire. Se
sei
sfigato č possibile aspettare un secondo prima che il uC possa gestire
la
seriale e, per esempio, rispondere ad un comando di interrogazione o
simile.

 l'esecuzione
infatti spiegavo solo cos'è una macchina a stati.
infatti avevo precisato che non era una soluzione "seria" perchè nel
frattempo l'aplicazione è bloccata, in ogni caso dipende dall'applicazione.
Se è un'applicazione a batteria è meglio uno sleep che risparmia corrente
;-P
ciao

 frattempo l'aplicazione è bloccata, in ogni caso dipende
dall'applicazione.
infatti, ho fatto qualche prova e ho visto che in realtà la storia è moolto
più complessa...
diciamo che mentre gestisco i pulsanti il micro deve "solo" aggiornare
l'orario corrente, sincronizzarsi con l'RTC di quando in quando, ricevere e
decodificare il segnale DCF77 e infine visualizzare quel che serve sul
display...
non ho ancora provato per bene la procedura per il DCF ma l'ho riscritta
usando un solo timer anzichè due come ho visto fare su esempi tratti dal
web. così il timer risparmiato lo uso per l'antirimbalzo. l'ho caricato in
modo che vada in overflow ogni 20 ms. quando premo il tasto lo avvio e conto
10 overflow "puliti" cioè senza che cambi lo stato del tasto, altrimenti
ricomincio. il problema che si verificava è che visto che testa lo stato del
tasto ogni 20 ms, se per caso cambiava stato nel frattempo entrava in una
specie di loop. allora ho previsto anche un timeout (sempre con il giochino
di contare gli overflow) in modo che dopo un certo tempo esca dal ciclo.
ho poi implementato la macchina a stati e devo dire che per quanto sia
abbastanza esosa in termini di spazio sul micro è molto comoda da gestire.
sembra che le cose comincino a funzionare: ci sono ancora dei comportamenti
"strani" che non riesco a capire da dove arrivino. tipo che ogni tanto
alcuni tasti (gestiti ovviamente allo stesso modo) impazziscano e mi
facciano avanzare il contatore - per impostare l'ora ad esempio - di 2 o 3
passi. teoricamente non potrebbe visto che c'è il discorso del debouncing ma
temo che possa capitare se degli spike di commutazione arrivino in
coincidenza di lettura dei pin o altre sfighe del genere.... boh ?!?
Marco

 display...
il tutto è coperto da segrato militare o puoi fornire dettagli (anche
implementativi) meglio se schemi/codice?
Ciauzz

 di contare gli overflow) in modo che dopo un certo tempo esca dal ciclo.
ma non potresti gestire in interrupt il cambiamento di stato?
metti un flag quando premi, un timer della durata del tuo concetto di
"pressione lunga" e la prima volta (pulsante premuto) metti press=1 e fai
partire il timer la seconda volta (pulsante rilasciato) guardi quanto vale
il timer...
cmq cerca Salvo OS č un kernel multitasking free per PIC ( c'č una versione
commerciale piů completa) č molto esoso di risorse (infatti gira solo su
Pic18XXX) ma uno sguardo agli esempi ti puň allargare le vedute

 dall'applicazione.
Dipende da come si gestisce la macchina. Io uso le macchine a stati proprio
per liberare il micro dalle attese inutili e permettere l'esecuzione
parallela di tutti i processi e temporizzazioni che servono, anche senza
l'uso di interrupt.
Le FSM dovrebbero essere chiamate ciclicamente come sottoprogrammi,
elaborare rapidamente lo stato attivo in quel momento (che tipicamente
esegue qualche controllo e qualche aggiornamento) e cedere di nuovo il
controllo al loop principale che le richiama. In questo modo si possono
eseguire una dietro l'altra tutte le FSM che servono in tempi brevissimi. I
compiti complessi come tenere sotto controllo diversi processi magari
indipendenti tra loro diventano quasi banali, e lo stesso algoritmo puo'
essere spezzato in parti molto elementari piu'semplici da gestire e da
pensare che non grandi strutture nidificate o flowchart chilometrici. Se la
chiamata avviene con cadenza periodica precisa, ogni FSM puo' contare il
tempo reale (e/o produrre sequenze temporizzate) indipendentemente dalle
altre o dalle periferiche presenti nel micro... sempre compatibilmente con
la velocita' dei segnali da gestire si intende.
Un aspetto interessante e' che si possono aggiungere modularmente su
necessita'altre FSM al software gia' esistente semplicemente aggiungendo la
loro chiamata nel loop principale. Ogni FSM puo' leggere/scrivere su alcuni
pin di ingresso/uscita, o leggere/scrivere su alcuni bit o bytes della
memoria per scambiare informazioni con le altre.
Il mio ricevitore DCF77 e' fatto in questo modo, il software si trova in
fondo alla pagina:
http://net.supereva.it/stor2.freemail/dcf/dcf.htm
...e' in assembler, sorry;)
Claudio F

 impazziscano e mi facciano avanzare il contatore
Hanno le resistenze di pull-up, interne od esterne?
Claudio F

 Hanno le resistenze di pull-up, interne od esterne?
ehm... interne...
dici che può essere questo il problema ? speravo si fossero altrettando
affidabili...
ciao!
Marco

 implementativi) meglio se schemi/codice?
affatto, ci mancherebbe altro!
ecco, qui c'è il sorgente C (non ho ovviamente incluso le librerie che ho
scritto/modificato visto che funzionano e non sono importanti)
http://digilander.libero.it/marcotrapanese/main.c
qui invece lo schema:
Sezione uC, RTC, ecc...
http://digilander.libero.it/marcotrapanese/MCU.GIF
Sezione Display:
http://digilander.libero.it/marcotrapanese/Display.GIF
ciao e grazie!
Marco

 Pic18XXX) ma uno sguardo agli esempi ti puň allargare le vedute
vado subito a cercare qualcosa!
grazie,
Marco

 altrettando affidabili...
Beh, la domanda era solo per capire se almeno una delle due fosse presente;)
Per quanto ne so alcuni contatti... contattano un po' a fatica se non
vengono attraversati da una corrente minima di qualche mA, non ricordo
esattamente quanto. Per piccoli pulsanti da stampato vicini al micro ho
sempre usato le pull-up interne, per pulsanti piu' lontani (anche decine di
metri), ho messo delle pull-up esterne da 1k o anche meno, in modo da far
circolare quel po'di corrente e da ridurre l'impedenza della linea (leggi
ridurre i possibili disturbi).
Claudio F

 ridurre i possibili disturbi).
sembra che ho risolto il problema: ho giocato un po' con i parametri del
debouncing e pur avendo una risposta pronta, non mi ha più dato problemi di
falsi contatti, speriamo bene... :)
scusa, volevo domandarti un'altra cosa sul DCF77, volevo scriverti in pvt ma
non so se l'e-mail è quella giusta. però magari interessa anche a qualcun
altro.
dunque, con il solito moduletto Conrad e l'antennina in ferrite messa un po'
lontano da PC e dal micro riceve a meraviglia anche durante il giorno. come
da datasheet ho collegato all'uscita (npn open collector) una resistenza di
pull-up e un diodo LED (che ho provato anche a togliere). Con
l'oscilloscopio si vede chiaramente il segnale ad onda quadra e il diodo
lampeggia che è un piacere. l'unico problema che non riesco a spiegarmi è il
valore della tensione in uscita. Con alimentazione a 5 V ottengo (ho provato
anche con altre tensioni ma si riporta scalato in maniera analoga):
livello logico 1, 5V ovvero tensione di alimentazione. (corretto, l'npn è
interdetto e il LED è spento)
livello logico 0, 3.8 V circa, perchè mai ?!?! se il transistor fosse acceso
come dovrebbe dovrei avere una tensione molto prossima a zero volt visto che
tra il collettore e massa non c'è altro che la giunzione del transistor!
come mai accade questo ?
ciao!
Marco

 livello logico 0, 3.8 V circa, perchè mai ?!?!
Mi pare strano, pero' mi da l'impressione che non ce la faccia ad assorbire
tutta la corrente che gli arriva attraverso led e resistenza.... c'e'
scritto nulla sul datasheet riguardo a questo limite? Fa cosi' anche
mettendo solo una semplice R da 10..47k?
Claudio F

 mettendo solo una semplice R da 10..47k?
urca... mi sa che hai centrato... il datasheet č il tedesco (1 pagina)... e
da una parte dice qualcosa riguardo alla corrente di uscita, < 2 mA. ma io
l'avevo intesa come corrente disponibile direttamente. possibile che abbiano
messo un transistor che sul collettore non accetti piů di 2 mA ?!? proverň
in giornata a metterci una R piů grande, se funziona allora dovrň metterci
un altro transistor per accendere il LED, giusto ?
questo perchč avendo fatto una scatolina da mettere lontano dall'orologio,
vorrei che il LED stesse sulla scatola, poi con un cavo porto il segnale DCF
alla scheda. farň sapere se il problema era quello!
grazie,
Marco
ps. nel caso usassi un altro npn per pilotare il LED, la base come mi
conviene polarizzarla ? cioč, uscendo dal collettore del modulino, basta la
R di pull-up opportunamente dimensionata (in modo che la corrente sia < ai 2
mA ma sufficiente a saturare l'npn successivo) ?

 mA ma sufficiente a saturare l'npn successivo) ?
dunque, era proprio quello il problema. con una R da 5.6 Kohm il segnale č
perfetto, da 0 a 5V.
perň prima ho detto una cavolata... non posso usare un npn come normale
interruttore, o almeno io non sono riuscito a trovare una soluzione. ho
pensato che forse la cosa piů furba potesse essere un inseguitore a
collettore comune tipo questo:
[FIDOCAD ]
MC 95 60 0 0 300
MC 110 70 1 0 220
MC 110 85 1 0 080
MC 110 95 0 0 040
MC 90 40 1 0 080
LI 90 35 90 40
LI 110 70 135 70
LI 110 50 110 35
LI 110 35 90 35
MC 90 30 3 0 010
LI 90 30 90 35
SA 90 35
SA 90 60
SA 110 70
TY 85 15 5 3 0 0 0 * 5V
MC 135 70 0 0 000
TY 145 65 5 3 0 0 0 * Out
MC 55 70 0 0 300
MC 70 80 0 0 040
LI 70 60 90 60
LI 90 50 90 60
LI 95 60 90 60
LI 55 50 80 50
LI 80 50 80 95
LI 80 95 55 95
TY 45 90 5 3 90 0 0 * modulo DCF77
TY 95 85 5 3 0 0 0 * 180
TY 95 40 5 3 0 0 0 * 5k6
adesso provo se funziona....
ciao!
Marco

Marco Trapanese ha scritto:




Ma non faresti meglio ad usare un pnp invece di tenere un npn sempre in
saturazione? Con un pnp avresti l'uscita normalmente a 0 ed avresti un 1
quando l'uscita del modulo DCF77 va in saturazione. Mi sono perso
qualcosa??
[FIDOCAD]
MC 110 70 1 0 220
MC 110 85 1 0 080
MC 110 95 0 0 040
MC 90 40 1 0 080
LI 90 35 90 40
LI 110 70 135 70
LI 110 50 110 35
LI 110 35 90 35
MC 90 30 3 0 010
LI 90 30 90 35
SA 90 35
SA 90 60
SA 110 70
TY 85 15 5 3 0 0 0 * 5V
MC 135 70 0 0 000
TY 145 65 5 3 0 0 0 * Out
LI 90 50 90 60
LI 95 60 90 60
TY 95 85 5 3 0 0 0 * 180
MC 95 60 0 0 310
MC 45 70 0 0 300
MC 60 80 0 0 040
LI 45 50 70 50
LI 70 50 70 95
LI 70 95 45 95
TY 35 90 5 3 90 0 0 * modulo DCF77
LI 60 60 75 60
MC 85 60 2 0 080
LI 85 60 90 60
TY 75 65 5 3 0 0 0 * 5k6
TY 75 40 5 3 0 0 0 * 15K
Ciao Fil
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 qualcosa??
si, che non ho ancora imparato a usare i pnp... :-)
e che a scuola non li abbiamo mai visti e cosě mi sono abituato a ragionare
con gli npn... e mi risulta ancora difficile pensare al contrario... :(
thx,
Marco

Marco Trapanese ha scritto:


Buon motivo allora per cominciare !!!


> Buon motivo allora per cominciare !!!
esatto!
dunque, ho modificato il circuito e ho montato il transistor come da tuo
schema.
funziona bene ed effettivamente è ottima come soluzione.
l'unico inconveniente è che a livello logico 0, il LED rimane debolmente
illuminato (ho usato un BC557)
Questo vuol dire cosa ? che devo alzare o abbassare la resistenza di base
(quella da 15k) ?
mi faresti un favore se mi fai al volo il ragionamento corretto, non solo la
risposta, così vedo di capirlo.
grazie!
Marco

 debolmente illuminato (ho usato un BC557)
1) stacchi il modulo DCF e cio' che eventualmente si trova a valle. Il LED
potrebbe essere leggermente alimentato o dal transistor, o eventualmente da
qualcosa di collegato piu' avanti. A questo punto dovrebbe risultare
perfettamente spento (a meno che il transistor non sia mezzo andato, ma non
credo)
2) con un corto manuale tra massa e il terminale libero della R da 5k6 provi
a simulare la presenza del modulo DCF, se il LED si comporta bene la colpa
e' di nuovo di quel modulo... che non solo non assorbe molta corrente quando
e' a 0, ma ad 1 continua comunque ad assorbirne un pochina lo stesso....
mmm... DUBBIO... l'emettitore del transistor si trova allo stesso potenziale
di alimentazione del modulo DCF vero?
3) Un pnp e' un npn alla rovescia. Per far condurre un npn devi alzare la
tensione di base di almeno 0,6V rispetto all'emettitore. Per far condurre un
pnp la devi invece abbassare almeno 0,6 al di sotto. In questo caso il
presunto assorbimento residuo del modulo la fa abbassare troppo nel punto
intermedio del partitore 15k-5k6 (dove e'collegata la base). Per aumentarla
un po' basta abbassare la R da 15k... o alzare quell'altra.
4) A me sta uscita del modulo comincia a starmi antipatica;)
Claudio F

 Claudio F
ciao e grazie 1000,
Marco

> capito il concetto... proverò a fare il test che dici.
urgh...... mi vergogno a dirlo......
ehm, era rimasto attivo per sbaglio il pull-up interno al micro.... 0:-|
sorry...
Marco