API pin watch
Se proviamo a tradurre watch in italiano, la prima traduzione sarà orologio, le altre, guardare e osservare sono più calzanti in questo caso. Osservare lo stato di un pin e agire in relazione allo stato di questo. La funzione pin_watch()
abilita l'osservazione di un pin, mentre pin_watch_stop()
la disabilità. Sotto vediamo il prototipo delle due funzioni che ci serve per capire come usarle.
L'argomento pin_t pin
sappiamo cosa essere, per cui concentriamoci sull'argomento di tipo pin_watch_config_t
, il quale è una struttura così composta:
user_data
deve contenere un puntatore che verrà usato come argomento nella funzione di callback pin_change
.
edge
ci permette di specificare per quale fronte del segnale vogliamo che sia chiamata la callback pin_change
. Il campo edge
può assumere i seguenti valori:
FALLING
Una transizioneHigh -> Low
determina la chiamata a funzione callback specificata nel campopin_change
.RISING
Una transizioneLow -> High
determina la chiamata a funzione callback specificata nel campopin_change
.BOTH
Una transizioneHigh -> Low
oLow -> High
determina la chiamata a funzione callback specificata nel campopin_change
.
Sembra complicato, ma come vedrete risulta abbastanza semplice configurare e abilitare l'osservazione di un pin. Attenzione però ad abilitare più osservazioni sullo stesso pin, vedremo dopo cosa possiamo fare e cosa no, per adesso lo usiamo nel modo più utile e frequente. Vediamo subito quanto semplice sia l'inizializzazione e la chiamata a pin_watch()
presente nella funzione chip_init()
:
Aggiungiamo l'implementazione della seguente callback dopo la funzione chip_init()
e proviamo a compilare:
Scopriamo che il compilatore esce con un messaggio di errore per niente chiaro, il messaggio mette in risalto il nome del simbolo wcb_inp
che è il nome che abbiamo dato alla funzione di callback. Risolviamo questo errore nel modo standard che prevede di inserire sempre i prototipi delle funzioni in testa dopo le include, oppure all'interno di un header file. Il codice seguente in effetti ora compila correttamente. Ricordiamoci che stiamo scrivendo codice C da dare in pasto al compilatore C e questo dovrebbe farci apprezzare la semplificazione di cui godiamo usando arduino.
Simulando il codice e premendo il pulsante, la CHIP CONSOLE
viene inondata di messaggi, il motivo di ciò è legato alla simulazione del pulsante vero, che è sempre afflitto da rimbalzi dei contatti elettromeccanici, difatti cliccando sul pulsante (vedi Fig.2) possiamo disabilitare i rimbalzi e ad ogni pressione avremo una sola stampa.
Fig.1: Collegamenti di test pin_watch |
Risulta sicuramente utile osservare questi rimbalzi dei contatti e wokwi ci permette di farlo in modo abbastanza semplice. Quindi riabilitiamo il rimbalzo (Fig.2), aggiungiamo l'analizzatore logico pigiando il pulsante blu (+), alla comparsa della lista dei componenti, scorriamo verso la fine fino ad incontrare l'analizzatore. Colleghiamo GND con il GND e il pin D7 con il pin INP. Avviamo la simulazione e premiamo il pulsante, proviamo a fare il tutto nell'arco di 1-2 secondi e fermiamo la simulazione. Wokwi ci chiede di salvare il file wokwi-logic.vcd, salviamolo. Questo file può essere visualizzato dal programma PulseView (sigrok) o da GtkWave. Possiamo osservare i rimbalzi dei contatti in Fig.3.
Fig.3: Primo rimbalzo alla pressione a 435ms. Rimbalzo al rilascio dopo 465ms |
Fig.2: Disabbilita/abilita il rimbalzo. |
Per fortuna i segnali digitali non rimbalzano, per tale motivo ci dobbiamo preoccupare dei rimbalzi solo quando colleghiamo pulsante, interruttore o relay ad un ingresso digitale.
Adesso vediamo come possiamo risolvere il problema del rimbalzo dei contatti con il solo fine di mostrare l'uso di pin_watch()
, pin_watch_stop()
e timer_start()
. Il programma è lo stesso del precedente a cui aggiungiamo dei campi alla struttura chip_state_t
e una funzione callback di un timer. Vediamo di seguito le modifiche alla struttura.
Tre campi, dove gcnt
è una variabile da 8-bit che useremo come contatore generico. wcfg_inp
è la variabile di tipo pin_watch_config_t
già usata in precedenza ma non faceva parte della struttura. tid_deb
ci serve che sia nella struttura perché nella funzione tcb_debounce
chiamiamo timer_stop(chip->tid_deb)
.
Passiamo alla funzione chip_init()
dove inizializziamo il timer chip->tid_deb
senza avviarlo, a seguire configuriamo chip->wcfg_inp
e abilitiamo l'osservazione del pin chiamando pin_watch()
. Nota che edge
è impostato a FALLING
, quindi ad ogni transizione da HIGH -> LOW verrà eseguita la funzione wcb_inp()
.
Passiamo ad analizzare la funzione wcb_inp()
:
Notate subito la chiamata a pin_watch_stop()
, seguendo c'è l'avvio del timer ciclico che chiama la funzione tcb_debounce()
ogni 5 millesimi di secondo. In questo momento l'osservazione del pin è disabilitata per cui il treno di impulsi del pulsante non ha conseguenze, allora invertiamo lo stato di chip->on_off
e stampiamo on o off. Il timer da 5ms ci serve per riabilitare l'osservazione del pin ma solo se il suo stato è HIGH
per 2 volte consecutive il che significa che il pulsante è stato rilasciato. Vediamo tutto ciò dentro la funzione seguente:
Tiriamo le somme: abbiamo imparato che quando ci serve avviare/abilitare timer/pin_watch durante la simulazione ci serve aggiungere nella struttura chip_state_t
una variabile di tipo timer_t
e pin_watch_config_t
. Mentre non ha alcuna utilità aggiungere una variabile di tipo timer_config_t
nella struttura perché timer_init()
non deve essere eseguita durante la simulazione ma soltanto all'inizio dentro la funzione chip_init()
. Questo vuole dire che il timer una volta configurato non può essere modificato, mentre una pin_watch_config_t
può essere modificata in ogni momento.
Adesso possiamo prenderci la briga di introdurre questa funzionalità per accendere/spegnere il generatore di segnale pwm desritto nell'articolo precendete con il solo scopi di vedere quanto abbiamo imparato e se questo è sufficiente da permetterci di integrare questa funzionalità.
Limiti di pin_watch
Osservando il prototipo di pin_watch()
notiamo che restituisce un valore di tipo bool
. Restituisce true
se l'osservazione del pin ha avuto successo, altrimenti restituisce false
. Quando restituisce false
vuole dire che c'è già abilitata l'osservazione dello stesso pin. Ad esempio:
L'ultima chiamata restituisce false
. Se rimuoviamo il commento alla pin_watch_stop(chip->inp)
, l'ultima chiamata restituisce true
. Quindi possiamo avere più configurazioni da abilitare con pin_watch, ma quella abilitata deve essere fermata prima di potere chiamare pin_watch sullo stesso pin. In altre parole non ci possono essere più osservazioni attive sullo stesso pin.
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Condividi allo stesso modo 4.0 Internazionale