Dopo aver visto una panoramica dei file creati dal template apriamo il file main.c
La funzione main come consueto sarà il punto d’ingresso per il nostro programma, notiamo le prime due istruzioni con suffisso _init, avremo spesso a che fare con funzioni di inizializzazione che spesso andranno semplicemente chiamate come in questo caso, diciamo che è una convenzione dei moduli ASF.
La prima istruzione ioport_init() inizializza il servizio IOPORT e va necessariamente chiamata prima di utilizzare qualsiasi altra funzione di questo servizio che permette di gestire i pin GPIO (General Purpose Input/Output)
La seconda funzione board_init() in realtà chiama una nostra funzione, nel senso non appartenente dal principio ad ASF ma scritta durante la stesura del template.
Una domanda che è lecito chiedersi è come fa il compilatore a sapere dove sono le due funzioni che abbiamo visto, il trucco è presto svelato, nell’header asf.h sono presenti le inclusioni ai file header (es. ioport.h, board.h) che contengono le definizioni delle funzioni ed il compilatore è già normalmente impostato per includere i percorsi che gli serviranno per recuperare tali file.
La funzione board_init() è all’interno del file asf\common\boards\user_board\init.c presente nel nostro progetto, qui sotto riportato
La funzione utilizza a sua volta due funzioni del servizio IOPORT che quindi è stato necessario chiamare prima di board_init.
Il codice è molto semplice, il suo funzionamento si basa su due funzioni del modulo IOPORT, il codice di ASF è sostanzialmente C quindi non ci sono classi complesse da istanziare e risulta di semplice comprensione:
ioport_set_pin_dir: imposta la direzione per una singolo pin specificato dal primo parametro che potrà quindi essere un pin di ingresso (IOPORT_DIR_INPUT) o di uscita (IOPORT_DIR_OUTPUT) in base a quanto specificato nel secondo parametro
ioport_set_pin_mode: imposta la modalità per un singolo pin specificato dal primo parametro, in questo caso le modalità specificate nel secondo parametro posso essere molteplici
Il codice imposta i pin relativi ai 3 led presenti sulla scheda come uscite ed il pulsante come ingresso con modalità pull-up, ovvero il pin sarà collegato tramite una resistenza interna al micro alla linea di alimentazione VCC ed alla pressione del pulsante si instaurerà un collegamento verso GND ma non un cortocircuito grazie proprio alla resistenza di pull-up di diverse decine di kilo-ohm che limiterà la corrente e leggeremo uno stato logico basso. Quando il pulsante non sarà premuto l’ingresso non rimarrà volante (floating) e quindi soggetto a disturbi ma avrà una connessione a VCC e leggeremo quindi uno stato logico alto. La logica sarà quindi invertita, ricapitolando: pulsante premuto –> ingresso basso, pulsante non premuto –> ingresso alto. Il punto è proprio quello di prevenire i disturbi che generano false pressioni dovute all’ingresso floating (o detto anche in alta impedenza).
Nel codice è possibile notare come i pin sono specificati tramite dei nomi facilmente comprensibili (es. LED0_GPIO, GPIO_PUSH_BUTTON_0), questi “nomi” sono definiti nel file user_board.h:
Come è possibile vedere le definizioni avvengono tramite una funzione IOPORT_CREATE_PIN che in realtà non è una vera e propria funzione ma una funzione MACRO che viene sostituita nel codice dal preprocessore per ottenere la massima velocità.
La funzione macro converte la porta prima in un nome es. IOPORT_PORTB che ha una definizione che l’associa ad un numero (in questo caso 1 come è possibile notare dal codice sopra) che viene poi moltiplicato per 8 e viene sommato al numero del pin.
In sostanza la funzione converte ogni pin in un numero univoco che sarà utilizzato per identificare il pin senza possibilità di errori ed utilizzato dalle altre funzioni del servizio IOPORT.
Nel file sono presenti alcune definizioni legati all’oscillatore presente sulla scheda, nel nostro caso un cristallo da 12 MHz, queste informazioni saranno utilizzate col modulo System Clock Control che vedremo prossimamente.
Tornando adesso al nostro file main.c (riportato sotto per semplicità di lettura) dopo aver dilagato sugli internals delle prime due istruzioni e aver visto qualcosa sotto al cofano
Notiamo che dopo l’inizializzazione viene utilizzata una nuova funzione del servizio IOPORT che non abbiamo ancora visto:
ioport_set_pin_level: imposta un pin specificato dal primo parametro al livello logico specificato dal secondo parametro. Il livello può essere IOPORT_PIN_LEVEL_HIGH oppure IOPORT_PIN_LEVEL_LOW, il tipo del secondo parametro è un bool quindi potremmo passare equivalentemente anche true oppure false ma a mio parere l’utilizzo dell’enumerativo (es. IOPORT_PIN_LEVEL_HIGH) rende il codice di intenti più chiari.
Vengono quindi accesi tutti e tre i led della nostra scheda dopodiché notiamo un while(true) che è semplicemente un ciclo infinito dove dovremmo inserire il nostro codice che sarà ripetuto fino ad un reset o allo spegnimento del micro.
Nessun commento:
Posta un commento