arduino - Edizioni del Faro

20.3 Uso del watchdog mediante la libreria “wdt.h”. 284. 20.4 Uso del watchdog mediante i registri. 287. Progetti stand-alone. 291. 21.1 Arduino stand...

6 downloads 741 Views 780KB Size
ARDUINO La Guida Essenziale Leonardo Miliani

Leonardo Miliani, Arduino – La Guida Essenziale 2016 Edizioni del Faro Gruppo Editoriale Tangram Srl Via Verdi, 9/A – 38122 Trento www.edizionidelfaro.it – [email protected] Prima edizione: aprile 2016 – Printed in EU ISBN 978-88-6537-483-2

Nonostante la cura posta nel realizzare quest’opera, non è garantito che essa sia priva di errori. L’autore e l’editore declinano, quindi, qualunque responsabilità derivante dall’uso del materiale in essa contenuto.

Le foto delle schede Arduino dei capitoli 1 e 2 appartengono a Arduino S.A. (www.arduinoc.cc) e sono distribuite sotto licenza Creative Commons Attribution ShareAlike 3.0. Gli schemi di montaggio sono stati realizzati con il software Frizting (fritzing.org).

Questo libro è dedicato alle persone che hanno creato Arduino: grazie alla loro scheda di prototipazione, come tante altre persone mi sono potuto avvicinare all’elettronica ed alla programmazione dei microcontrollori. Ringrazio anche tutti coloro che hanno creduto nell’open source mettendo il loro lavoro a disposizione completa degli altri: questo è il modo migliore per trasmettere la conoscenza.

!3

Indice Introduzione 1.1 1.2 1.3 1.4

15

Un po’ di storia Le vecchie schede La filosofia “o n” Arduino o Genuino?

15 17 21 21

L’hardware

22

2.1 La scheda Arduino UNO 2.1.1 Avvertenze sull’uso della scheda 2.2 Il microcontrollore ATmega328P 2.3 Le schede Arduino MEGA2560, 101, DUE, Yún 2.4 Gli shield ufficial 2.5 Altre schede Arduino

Il software

22 25 26 29 33 35

38

3.1 Installazione dell’IDE e dei driver 3.1.1 Piattaforma Windows 3.1.2 Piattaforma OS X 3.1.3 Piattaforma Linux 3.2 Primi approcci con l’IDE 3.3 Programmiamo l’Arduino

38 39 43 44 46 49

Introduzione al linguaggio di Arduino 4.1 Che cos’è un linguaggio di programmazione 4.2 Il linguaggio C 4.3 Il linguaggio di Arduino

Basi del linguaggio di Arduino

54 54 56 57

59

5.1 Struttura di un programma in Arduino 5.2 Basi del linguaggio 5.3 Variabili 5.3.1 Visibilità: variabili locali e globali 5.3.2 Variabili di tipo static e auto 5.3.3 Variabili di tipo register e volatile 5.4 I tipi di dato 5.4.1 Costanti e letterali 5.4.2 I numeri binari !5

59 61 63 65 67 68 69 72 74

5.4.3 I numeri ottali e esadecimali 5.5 Gli operatori 5.5.1 Operatori aritmetici 5.5.2 Operatori relazionali 5.5.3 Operatori logici e algebra di Boole 5.5.4 Operatori di incremento e decremento 5.5.5 Operatori per la manipolazione dei bit 5.5.6 Operatori di assegnamento 5.5.7 Operatori vari 5.5.8 Precedenza degli operatori

Il controllo del flusso di un programma 6.1 6.2 6.3 6.4

I blocchi di codice Il costrutto if..else Il costrutto switch..case I cicli iterativi 6.4.1 Il ciclo for 6.4.2 Il ciclo while 6.4.3 Il ciclo do..while 6.4.4 Br eak e continue 6.4.5 I salt i: goto ed etichette

93 93 94 96 97 97 99 99 100 101

Funzioni e vettori

103

7.1 - Definizion di funzione 7.1.1 Prototipi di funzione 7.1.2 Argomenti in ingresso e dati in uscita 7.1.2 Argomenti per valore e per riferimento 7.1.4 Argomenti predefini i 7.1.5 Funzioni ricor sive 7.2 Vettori 7.2.1 Vettori multidimensionali

I puntatori 8.1 8.2 8.3 8.4 8.5 8.6

76 77 77 78 79 82 84 89 90 91

103 103 104 106 107 107 108 111

113

I puntatori Puntatori e vettori Aritmetica dei puntatori Puntatori e costanti Puntatori a funzioni Puntatori a puntatori e vettori di puntatori !6

113 115 116 118 119 120

Stringhe, strutture di dati e tipi personalizzati 9.1 Le stringhe 9.2 Le stringhe in stile C 9.2.1 Vettori di stringhe 9.2.2 Funzioni principali 9.3 Le Stringhe in Arduino: la classe String 9.3.1 I metodi della classe String 9.3.2 Operatori per le stringhe 9.4 Strutture di dati 9.5 Tipi personalizzati 9.6 Enumerazioni 9.7 Unioni 9.8 Campi di bit

Le funzioni di I/O di Arduino

122 122 122 126 126 127 128 134 135 137 138 139 140

142

10.1 - Input/Out put digitale 10.1.1 Avvertenze sull’uso dei pin 10.2 Input analogico 10.3 I segnali PWM (simulare l’output analogico) 10.4 Funzioni t emporali

Numeri casuali, bit e byte e funzioni matematiche 11.1 - Numeri casuali 11.2 Bit e byte 11.3 Funzioni ma tematiche

142 146 146 149 152

157 157 160 161

La comunicazione seriale

163

12.1 La classe Serial 12.1.1 Il metodo write() 12.1.2 I metodi print() e println() 12.2 Lettura di dati dalla seriale 12.3 Convertire i dati letti sulla seriale 12.4 Gestione del buffer seriale

163 166 166 168 169 170

Le librerie

173

13.1 - Usare una libreria di Arduino 13.2 Inst allazione di una libreria da un archivio 13.3 Inst allazione tramite gestore delle librerie 13.4 Le librerie standard

Principi di Elettronica, componenti elettronici di base !7

173 175 178 179

182

14.1 Che cos’è l’elettricità 14.2 Corrente continua e corrente alternata 14.3 La legge di Ohm 14.4 Il resistore 14.5 Il condensatore 14.6 Il diodo 14.7 I LED 14.8 Il transistor BJT 14.9 Il pulsante 14.10 La basetta di prototipazione

I primi progetti 15.1 15.2 15.3 15.4

182 183 185 187 189 191 194 197 202 204

206

Progetto 1: Accensione di un LED mediante un pulsante Progetto 2: Accensione temporizzata di un LED Progetto 3: Esecuzione di 2 compiti temporizzati Progetto 4: Scambio di dati sulla seriale

Interazione con l’utente

206 209 210 212

218

16.1 Schermi a cristalli liquidi (LCD) 16.2 La libreria LiquidCr ystal 16.2.1 Ge stione dello schermo 16.3 Progetto 5: Uso di LiquidCrystal 16.4 Tastiere alfanumeriche 16.4.1 P rogetto 6: Lettura di una tastiera 16.5 Progetto 7: Scrittura e lettura

Le porte logiche

218 221 221 226 229 230 234

239

17.1 Le porte logiche del microcontrollore 17.2 Gestione digitale delle porte 17.3 Le porte analogiche 17.3.1 Il r egistro ADMUX 17.3.2 Il r egistro ADCSRA 17.3.3 I r egistri ADCSRB e DIDR0 17.3.4 I r egistri ADCL/H 17.3.5 Ese mpi di utilizzo

I timer/counter

239 239 242 244 246 247 248 249

251

18.1 I timer/count er 18.2 Registri dei timer/count er 18.3 Modalit à dei timer/count er

251 253 256 !8

18.3.1 Modalit à Normal 18.3.2 Modalit à CTC 18.3.3 Modalit à Fast PWM 18.3.4 Modalit à Phase Correct PWM 18.3.5 Fast PWM con massimo variabile 18.3.6 P hase Correct PWM con massimo variabile 18.4 Ot tenere una certa frequenza

Gli interrupt

269

19.1 Gestione degli interrupt 19.2 Int errupt esterni 19.2.1 Ge stione degli interrupt INT 19.2.2 Gli int errupt INT tramite registri 19.2.3 Gli int errupt PCINT 19.2.4 P rogetto 8: Gestione di più interrupt PCINT

Il Watchdog 20.1 20.2 20.3 20.4

258 258 261 262 263 264 265 269 273 275 276 278 280

283

Il Cane da Guardia Cara tteristiche del watchdog Uso del watchdog mediante la libreria “wdt.h” Uso del watchdog mediante i registri

Progetti stand-alone

283 283 284 287

291

21.1 Arduino stand- alone 21.2 Diverse impostazioni per l’ATmega328P

Risparmio energetico

291 296

299

22.1 Consumi e Risparmio energetico 22.2 Il “sonno” dei microcontrollori 22.2.1 Le modalità di sleep 22.2.2 Il r egistro SMCR 22.2.3 La libr eria “sleep.h” 22.3 Riduzione del consumo energetico 22.3.1 Il r egistro PRR 22.3.2 La libr eria “power.h” 22.3.3 Come ridurre i consumi 22.5 Esempio pratico

Il preprocessore

299 300 302 303 303 305 305 306 307 309

312

23.1 Dir ettive per il preprocessore 23.2 Definizioni macro

312 312 !9

23.3 23.4 23.5 23.6

Inclusioni condizionali Gestione degli errori Inclusione di fil Macr o predefini e

315 318 318 319

!10

Prefazione Questa guida nasce come uno strumento utile a tutti coloro che si avvicinano per la prima volta al mondo della prototipazione elettronica. Anni fa, leggendo una rivista vidi un articolo che trattata di Arduino e della sua facilità di programmazione. Da programmatore fui tentato molto da quell’articolo, ed alla fine cedetti ed acquistai la mia prima scheda. Venivo da oltre 20 anni in cui mi ero dilettato, per passione e non per lavoro, con la programmazione spaziando tra un’infinità di linguaggi: dal BASIC dei computer Commodore all’assembly 65xx, dal GW-BASIC dell’era MS-DOS all’assembly x86, dal Turbo Pascal al COBOL, dal Visual Basic di Windows alla sua controparte linuxiana Gambas per finire al linguaggio multipiattaforma LiveCode ma mai avevo avuto a che fare col C, reputandolo un linguaggio “particolare”: all’epoca in cui avevo mosso i miei passi informatici era considerato un linguaggio per “scrivere sistemi operativi”, più che altro. Eppure la sua semplicità ha fatto la sua fortuna dato che nell’era dei sistemi embedded ha conosciuto una seconda giovinezza: per le sue doti di velocità e compattezza il C è la scelta migliore sui piccoli microcontrollori. Forte, quindi, della mia esperienza di programmazione, non ebbi grossi problemi ad apprendere l’ennesimo linguaggio. Ciò di cui ero digiuno era la parte elettronica: in ambito embedded devi conoscere entrambe, la programmazione e l’elettronica, perché una è la mente e l’altra è il braccio. Senza la prima la seconda “non si muove”, ma senza la seconda la prima “parla al vento”. Dovetti quindi procurarmi qualche manuale di elettronica e cominciare a studiarmi almeno le basi di questa materia. Col tempo la conoscenza ma, soprattutto, un po’ di esperienza, mi hanno aiutato a barcamenarmi per realizzare i miei progetti: certo, da autodidatta non si possono raggiungere i livelli di un ingegnere elettronico ma un display LCD con un port expander I2C riesco a collegarlo anch’io alla mia scheda Arduino. E questo è già un bel passo in avanti per me e per il mio ego! Perché questa guida, quindi? Questa guida l’ho scritta proprio con in mente quelle persone che mancano di una se non di entrambe le cose, le nozioni di informatica e quelle di elettronica. La guida è dedicata ai principianti, a chi “vorrebbe fare” ma non ha abbastanza conoscenze. Non è un manuale che insegna la programmazione a 360° ma si focalizza sul C/C++ in generale e sul linguaggio di Arduino nello specifico. Se cercate di portare le vostre conoscenze informatiche apprese con questo manuale su un computer vi accorgerete che non tutte le cose corrispondono fra il linguaggio che avete studiato qui e quello usato sui computer, nonostante la base sia comune. Inoltre in questa guida ho saltato alcuni concetti del C/C++ che ho ritenuto inutile approfondire: se volete studiare i linguaggi C/C++ in modo completo rivolgetevi ad uno specifico testo. Similmente, questa guida vuole anche fornire quel minimo di conoscenze di elettronica a chi non sa la differenza fra tensione e corrente oppure che non sa l’utilizzo !11 11

di un condensatore, senza dover andare nello specifico addentrandosi in argomenti che potrebbero risultare complessi da affrontare e trattare senza adeguati studi di base. Un unico libro, quindi, in cui trovare un po’ di tutto ma, soprattutto, trovare cose mirate a ciò che si ha di fronte, la scheda Arduino. Anche chi ha già una conoscenza degli argomenti trattati potrà trarre beneficio dalla lettura di questo manuale, ripassando i concetti del linguaggio e dell’elettronica e di come essi vengano adattati alle schede tipo l’Arduino. Il libro è stato diviso per argomenti. Iniziamo con una parte di storia, che ci aiuta a comprendere cos’è l’Arduino e da dove viene, per poi affrontare anche la conoscenza delle altre schede meno note della grande famiglia Arduino e degli shield, il nome con cui sono indicate le schede accessorie che ne espandono le capacità. Passiamo poi ad affrontare l’ostico tema della programmazione, con gli argomenti che vengono aggiunti uno alla volta, come gli ingredienti in una ricetta. Il passo successivo è fatto tuffandoci più in profondità, per studiare cosa offre l’Arduino per sfruttare la scheda: le librerie di sistema sono molto ricche e permettono di utilizzare quasi a pieno la scheda. Viene poi la volta dell’elettronica, anch’essa affrontata a piccoli passi, partendo dalle nozioni di base come la notissima legge di Ohm, per poi arrivare ad una vista generica sui componenti base dell’elettronica quali resistore, condensatore, diodo e transistor. Infine ci addentriamo un po’ più nello specifico, realizzando alcuni piccoli progetti che ci permettono di sperimentare e di applicare le nozioni apprese in modo più approfondito perché, secondo il mio modesto parere, non c’è modo migliore per imparare qualcosa che facendoci pratica. Si possono leggere tutti i manuali del mondo ma senza la pratica non si impara nulla di concreto. Anche il C è, sotto questo punto di vista, un ottimo linguaggio: poche parole chiave, dal significato chiaro, che però permettono di fare grandi cose se messe insieme nel modo giusto. Alla fine della guida una piccola parte è dedicata ad alcune nozioni avanzate, cose poco usate, argomenti un po' ostici, relegati in un “angolo della soffitta” perché non usate tutti i giorni. Bene, dopo tutto questo…. tocca a voi! Armatevi quindi di pazienza ed iniziate la lettura, addentrandovi nell’affascinante mondo della prototipazione per realizzare in autonomia piccoli progetti di elettronica da installare in casa ed esibire agli amici curiosi quando ricevete delle visite ;-) Buona lettura. Leonardo Miliani

!12 12

Convenzioni adottate In questa guida abbiamo utilizzato alcune convenzioni per la scrittura del testo. Le parole in lingua straniera o di una certa rilevanza ed i nomi di variabili li abbiamo scritti in corsivo.
 Le parole importanti le abbiamo evidenziate in grassetto la prima volta che le abbiamo incontrate.
 Le parole chiave del linguaggio le abbiamo scritte utilizzando un carattere a larghezza fissa. Nel caso di un blocco di codice, lo abbiamo evidenziato utilizzando un carattere diverso
 ed uno sfondo colorato

Informazioni aggiuntive sono evidenziate con un apposito riquadro a lato di un’icona riportante la lettera “i”: Prova di box informativo Avvisi di una certa rilevanza sono invece evidenziati da uno sfondo di un colore più marcato e dal segnale di attenzione: Attenzione Questo è un messaggio importante

!13 13

Sezione 1 Arduino: La Storia, L’Hardware

!14

Capitolo 1

Introduzione 1.1 Un po’ di storia Arduino nasce come un sistema per facilitare lo sviluppo di prototipi di circuiti elettronici. È stato sviluppato inizialme nte da Massimo Banzi, D av i d C u a r t i e l l e s , N i c h o l a s Zambetti e David Mellis. I primi esemplari furono realizzati nel 2005 resso l’Interaction Design Institute Ivrea (IDII), un istituto post-laurea aperto da Olivetti e Telecom Italia nella città di Figura 1: uno dei primi esemplari di Arduino Ivrea dove veniva insegnato interaction USB, la Extreme: in alto a sinistra sono indicati i design, una disciplina che st udia nomi dei membri di allora del gruppo di sviluppo. l’interazione fra l’essere umano ed i dispositivi meccanici ed informatici (l’istituto è rimasto aperto poco più di 2 anni). Tra i docenti che tenevano lezione presso l’istituto vi era Massimo Banzi, che insegnava physical computing: per facilitare gli studenti nella realizzazione dei loro progetti venivano usate schede di prototipazione normalmente reperibili in commercio quali la BasiX BX24 e le Basic Stamp di Parallax. Ma Massimo Banzi non era soddisfatto di questi prodotti, sia per la scarsa interattività degli stessi sia perché l’ambiente di sviluppo era disponibile solo per il sistema operativo Windows mentre all’istituto utilizzavano prevalentemente sistemi Mac. Egli iniziò quindi a studiare i PICmicro, programmabili con il BASIC, ed a fare esperimenti con JAL, un linguaggio simile al Pascal. Alla fin decise di progettare una propria piattaforma di prototipazione, e fu così che realizzò nel 2003 la Programma 2003 (il nome riprende la prima calcolatrice programmabile di Olivetti, la Programma 101, realizzata a metà anni Sessanta), la prima scheda realizzata presso l’IDII, pensata per essere economica, facile da usare e completamente open source.1 Come base per l’editor di codice fu scelto il JEdit, che era basato sul Java ed era quindi multi- piattaforma: da esso Massimo Banzi sviluppò l’editor per la Programma 2003, che fu poi integrato in !15 15

un sistema di compilazione dei programmi e programmazione della scheda realizzato da Nicholas Zambetti e David Mellis, all’epoca studenti dell’istituto,2 derivandolo da Processing, un linguaggio ed un ambiente di sviluppo progettato nel 2001 da Casey Reas e Benjamin Fry, due studenti del MIT Media Lab (un laboratorio della scuola di architettura e progettazione del Massachusetts Institute of Technology) che in quel periodo frequentavano i corsi dell’istituto. Osservando i progetti che gli studenti avevano realizzato con la sua scheda, Massimo Banzi stabilì i punti da rivedere per migliorare il progetto della Programma 2003. Massimo Banzi e Casey Reas lanciarono quindi un progetto di tesi per la nuova piattaforma, progetto raccolto da Hernando Barragán, il quale iniziò lo sviluppo del prototipo della nuova scheda. Fu deciso di abbandonare i PICmicro in favore dei microcontrollori Atmel, scelti su consiglio di uno dei professori di Massimo Banzi che ne faceva già uso presso l’università di Stanford dove insegnava. L’ambiente di sviluppo ed il linguaggio di programmazione furono derivati da Processing, in modo da avere una piattaforma di sviluppo compatibile con più sistemi operativi. La revisione del progetto portò alla Programma 2005, una scheda però ancora rudimentale. Mentre Barragán continuava lo sviluppo in proprio della sua scheda che aveva denominato Wiring e che era basata su un ATmega1280, Massimo Banzi procedeva parallelamente con la realizzazione di un progetto derivato, basato su un ATmega8. Inizialmente denominato Wiring Lite, ben presto divenne Arduino. Arduino fu realizzato in qualche centinaio di esemplari ed utilizzato dagli studenti per numerosi progetti. Verso la fin dello sviluppo del progetto arrivò presso l’istituto il dottor David Cuartielles, un ingegnere dell’università svedese di Malmo, per studiare la scheda Wiring. Con Cuartielles, Massimo Banzi sviluppò gli shield, ossia schede accessorie da applicare sulla scheda principale per espanderne le funzionalit à, che furono poi portati anche sull’Arduino. Fu poi scelta la forma e la struttura della scheda, che conserva tuttora, ed il colore blu del circuito stampato, per contraddistinguere Arduino dalle altre schede in commercio. L’ambiente di sviluppo fu poi reimplementato per renderlo completamente open source, sviluppando gli strumenti e mantenendo solo le API originali per compatibilità con i progetti già realizzati. Al gruppo di sviluppo si unirono anche Tom Igoe, che, grazie alle sue esperienze nell’insegnamento della programmazione, realizzò guide ed esempi facilmente comprensibili, e Gianluca Martino, che ottimizzò gli schemi elettrici dell’Arduino seguendone anche la fase realizzativa. Nicholas Zambetti lasciò successivamente il gruppo di sviluppo. !16 16

Capitolo 2

L’hardware 2.1 La scheda Arduino UNO La scheda Arduino entry-level, dedicata cioè a chi si avvicina per la prima volta al mondo della prototipazione elettronica mediante microcontrollori, è la UNO. Essa sarà la scheda di riferimento in questa guida: le informazioni date varranno per questo modello, adattamenti ad altre schede potrebbero non essere sempre possibili. La UNO è stata introdotta nel 2010 come evoluzione della precedente Duemilanove. Rispetto a quest’ultima si differenzia principalmente per l’utilizzo di un differente chip per la comunicazione con il computer a cui viene connessa la scheda: al posto del convertitore US B/se rial FT232RL di FTDI viene ora utilizzato un chip Atmel Atmega16U2 (a seconda della versione della scheda) appositamente programmato. Di questa scheda ne sono stati prodotti, al momento della stesura di questa guida, 3 versioni: • la prima, indicata semplicemente con UNO, è il modello originale; • la seconda, indicata come UNO R2, è un’evoluzione che si differenzia dalla precedente principalmente per l’adozione del chip ATmega16U2 al posto dell’ATmega8U2 (collocato anche in posizione ruotata di 45°); • l’ultima è indicata come UNO R3, e mostra il riposizionamento del convertitore nella dislocazione originale nonché l’adozione di alcuni pin addizionali e l’uso di un diverso circuito di reset. I componenti principali dell’Arduino UNO sono indicati in figura 5. Analizziamo in dettaglio la scheda ed i suoi componenti principali: Porta USB
 La porta US B serve a collegare la scheda ad un computer. Questa porta è utilizzata sia per la trasmissione dei dati da e verso la scheda sia per alimentare la scheda: è possibile infatti utilizzar e un alimentatore a 5 V con uscita US B per fornire la necessaria corrente alla UNO. !22 22

Figura 5: i componenti principali dell’Arduino UNO

Jack alimentazione esterna
 Mediante questo jack (di tipo Japan con positivo centrale e diametro 2,5/5,5 mm rispettivamente per il polo centrale ed il diametro esterno) è possibile fornire l’alimentazione alla scheda. Per evitare problemi di stabilità e surriscaldamento è consigliabile utilizzar e una tensione compresa fra 7 e 12 Volt. Circuito regolatore di tensione
 La scheda integra un circuito di regolazione della corrente e di selezione della fonte di alimentazione nel caso siano presenti contemporaneamente tensioni su entrambi i connettori US B e jack: in questo caso il circuito seleziona come fonte primaria la tensione proveniente dal jack esterno. La tensione che va fornita al jack dovrebbe essere compresa fra 7 e 12. Questi valori sono quelli consigliati affin hé il regolatore integrato possa funzionare correttamente ed in sicurezza: valori inferiori a 7 V non garant iscono in uscita la tensione operativa di 5 V per cui è stata progettata la scheda mentre valori superiori a 12 V possono portare al surriscaldamento dello stesso regolatore.
 !23 23

Convertitore USB/seriale
 Il convertitore US B/se riale è un piccolo microcontrollore Atmel che permette la comunicazione fra il computer a cui è connessa la scheda Arduino ed il microcontrollore Atmega328P. Il convertitore cambia a seconda della versione della scheda UNO utilizzata: sulla UNO R1 e in parte della seconda versione, la UNO R2, è stato utilizzato un Atmega8U2, mentre sulle UNO R2 più recenti e sulle UNO R3 è stato montato un Atmega16U2. Questo chip si occupa non solo di trasmettere i dati di transito dal canale US B (lato computer) al canale seriale (lato Atmega328P ) e viceversa ma anche di permettere l’invio di un nuovo sketch (così si chiama il programma dell’utente) dal computer al cuore della scheda (vedi sotto). Microcontrollore Atmega328P
 Il microcontrollore Atmega328P è il vero cuore della scheda. U n microcontrollore è in parole povere un computer in miniatura: esso infatti integra la memoria su cui è salvato il programma, l’unità di esecuzione capace di eseguirlo (detta CPU) e tutte le periferiche con le quali esso può comunicare con il mondo esterno (vedi il cap. 2.1.1). Nonostante il chip possa funzionare con clock fino a 20 MHz, esso è impostato per motivi storici per lavorare a 16 MHz: questo è infatti il valore della frequenza massima supportata dai microcontrollori Atmel realizzati a quel tempo ed utilizzati sulle prime schede Arduino. Solo in tempi più recenti Atmel ha aggiornato i suoi processori elevando il clock massimo da 16 a 20 MHz ma, per compatibilità con il software già scritto, si è scelto di mantenere la frequenza operativa dei vecchi chip.
 Pin digitali
 L’Arduino UNO dispone di 14 pin di input/out put (I/O) di tipo digitale: ciò vuol dire che a questi pin possono essere collegati in ingresso dei sensori oppure in uscita dei dispositivi che funzionano con la logica digitale. La logica digitale con valori TTL considera come valore “0” uno stato elettrico pari (o prossimo) a 0 V e come valore “1” uno stato elettrico pari (o prossimo) a 5 V. Valori di tensione intermedi non dovrebbero essere utilizzati con questi pin perché potrebbero essere interpretati in maniera casuale (1 oppure 0). Da notare la differente spaziatura fra i connettori della parte superiore e quelli della parte inferiore: essa è nata come un errore di progettazione che poi è stato lasciato perché impedisce agli utenti inesperti di montare sulla scheda gli shield invertendone il verso. Pin analogici
 L’Arduino UNO dispone di 6 linee di input analogico: ciò significa che a questi pin possono essere collegati dei segnali elettrici di tipo analogico, con tensione !24 24

Sezione 2 Arduino: Il Software

!37

Capitolo 3

Il software 3.1 Installazione dell’IDE e dei driver L’IDE (Integrated Development Environment, o Ambiente di Sviluppo Integrato) fornito, liberamente scaricabile dal sito di Arduino (www.arduino.cc) è derivato da quello di Processing, di cui riprende l’impostazione base. Essendo basato su Java, è un ambiente che può girare su più sistemi differenti: è infatti offerto già compilato per Microsoft Windows, Apple Mac OS X e Linux. Sono disponibili anche i sorgenti, per chi vuole compilarselo in proprio o per chi vuole espanderlo aggiungendo nuove funzionalit à. Al momento in cui scriviamo (gennaio 2016) l’IDE è disponibile in due versioni: la 1.0.6 e la 1.6.7. La prima è la versione sviluppata fino al 2015, che non supporta alcune delle schede più recenti mentre la seconda supporta tutti i modelli Arduino. A causa del fatto che il ramo 1.0 dell’IDE è in circolazione da più tempo, è la versione per la quale sono state scritte la maggior parte delle librerie di terzi. È la versione che è preferibile utilizzar e, essendo quella più collaudata. Il ramo 1.6 è stato inizialmente rilasciato per supportare specific tamente la scheda Arduino DUE, dato che il suo microcontrollore è un chip con un core ARM per cui necessita di un compilatore differente rispetto a quello utilizzato per compilare il codice scritto per i chip Atmega utilizzati sulle altre schede. In seguito è stato aggiunto il supporto alla Yún, alla Zero ed alla 101. È da poco uscita dalla beta e, rispetto al ramo 1.0, sono stati pesantemente cambiati il formato delle librerie e la versione degli strumenti di compilazione: questo significa che software scritto per l’IDE 1.0 non è detto che funzioni anche con l’IDE 1.6. La scelta dell’IDE è personale: per i nostri scopi abbiamo deciso di adottare la 1.6.7 ma quanto detto dovrebbe valere senza signific tive modifi he nel processo di installazione, scrittura dei programmi e caricamento sulle schede anche per la versione 1.0.6. Scelta la versione, per prima cosa procuriamoci l’IDE per il nostro sistema operativo. Colleghiamoci al sito www.arduino.cc e, dal menu a barra, selezioniamo la pagina “Download”. Qui, scorrendo, arriviamo ai link. Preleviamo la versione che fa al caso nostro: • Piattaforma Windows: • con installer automatico oppure come singolo ZIP; !38 38

• Piattaforma OS X: • app compressa • Piattaforma Linux: • binari per sistemi a 32 o 64 bit

3.1.1 Piattaforma Windows Il software è fornito sia con un installer che provvede in automatico a copiare tutti i fil dell’ambiente di sviluppo ed a creare i collegamenti necessari affin hé l’utente trovi l’IDE nel menu dei programmi sia tramite un archivio da decomprimere. Il sistema dell’installer è più semplice ma l’archivio compresso è da preferire se non si vogliono lasciare fil di configurazion nel sistema: per rimuovere o aggiornare l’IDE basta eliminare la cartella dove risiede, cancellando tutto con una semplice operazione. L’archivio ZIP è anche l’unica strada se non si hanno i permessi di amministratore necessari per poter installare software sulla propria postazione lavorativa. Se si opta per l’installer, dopo il download fate un doppio click sull’icona per avviare il software di installazione. Sarà richiesto se vogliamo autorizzar e il programma ad apportare modifi he al sistema: diamo conferma.

L’IDE è distribuita con licenza GNU LGPL (Lesser General Public License), per utilizzar lo dobbiamo accettarla.

!39 39

Capitolo 4

Introduzione al linguaggio di Arduino 4.1 Che cos’è un linguaggio di programmazione Tutti i giorni abbiamo a che fare con il concetto di linguaggio: quando esprimiamo un concetto, quando parliamo con gli altri, quando scriviamo, quando leggiamo, quando pensiamo. Il linguaggio è quindi la capacità che abbiamo di comunicare per mezzo di una lingua: utilizziamo un lessico, ossia un insieme di parole, con una sintassi, ossia delle regole per mettere insieme queste parole, e una semantica, ossia attribuiamo un signific to a queste parole. Grazie a ciò possiamo comporre delle frasi per chiedere a qualcuno che ore sono e capire la risposta che ci viene fornita, possiamo ordinare di fare un’azione e vedere che il nostro interlocutore ha capito cosa gli stiamo chiedendo dal fatto che stia o meno compiendo ciò che gli è stato detto. Per noi il linguaggio è una cosa semplice: parliamo con la bocca ed ascoltiamo con le orecchie, esprimiamo la nostra volontà e ascoltiamo le idee degli altri. Ma con un computer o, nel nostro caso, con un microcontrollore, come possiamo interagire? Dobbiamo utilizzar e un mezzo di comunicazione capibile da entrambi: dobbiamo usare un linguaggio di programmazione. Un linguaggio di programmazione è un linguaggio destinato a permetterci di interagire con un dispositivo informatico: come un linguaggio umano, un linguaggio di programmazione è composto da un lessico, ossia di un insieme di istruzioni, usa una sintassi, ossia delle regole per usare queste istruzioni, ed è basato su di una semantica, ossia assegna un preciso signific to d ogni istruzione. Ciò che si occupa dell’interpretazione e dell’esecuzione di queste istruzioni è la CPU, acronimo inglese che sta per Central Processing Unit, detta in italiano anche Unità di Elaborazione Centrale. La CPU è un circuito integrato composto da diversi moduli: • fetch: è il modulo che si occupa di recuperare l’istruzione dalla memoria (ed eventualmente i dati che servono ad eseguirla); • decode: questo modulo si occupa di decodifica e l’istruzione stessa, usando il “vocabolario”, il lessico di comandi che essa è in grado di capire, che è !54 54

memorizza to sotto forma di numeri detti codici macchina o opcode (da “operation code”, “codice operativo”); ogni opcode rappresenta un’azione che la CPU può compiere: ad esempio, un “salto” del programma, il caricamento di un determinato valore in un registro, un’addizione, una sottrazione, un confronto fra due valori ecc… • execute: questo è il modulo che si occupa materialmente di eseguire l’istruzione. Scrivere un programma, ossia un insieme di istruzioni per far eseguire alla CPU un determinato compito, utilizzando gli opcode è un lavoro estenuante e incline agli errori: considerate però che agli inizi dell’era informatica i computer venivano programmati proprio scrivendo programmi in codice macchina, detto anche “linguaggio macchina” anche se in realtà non si tratta di un “linguaggio” nel vero senso del termine dato che non abbiamo un insieme di parole (lessico) ma una serie di codici numeri. Il programmatore, colui che scrive un programma informatico, era perciò costretto a scrivere pagine di numeri per creare il programma che voleva realizzar e. Per facilitare il compito fu creato l’assembly: l’assembly era una rappresentazione del codice macchina fatta con codici testuali facilmente memorizzabili (detti “mnemonici”): l’opcode per il salto diveniva quindi “JMP” (da “jump”, che in inglese vuol dire appunto salto), l’opcode dell’addizione veniva sostituito da “ADD”, per quello della sottrazione si usava “SUB” e così via. La programmazione divenne sì più semplice ma il programmatore era comunque sempre legato al fatto che l’unica istruzione condizionale era il salto: questo rendeva difficil seguire la logica del programma per via del fatto che l’esecuzione passava da un punto all’altro del codice. Questo modo di scrivere i programmi è detto “spaghetti code”, perché il flusso di istruzioni si intreccia, come gli spaghetti in un piatto di pasta. Per risolvere il problema del rendere il codice facile da scrivere e da leggere, furono introdotti i linguaggi di programmazione ad alto livello, che si differenziavano da quelli a basso livello come l’assembly e quelli a bassissimo livello come il codice macchina per il fatto che erano più vicini, più “simili”, al linguaggio umano. Uno dei primi linguaggi di programmazione ad alto livello sviluppati fu il FORTRAN, nato alla fin degli anni Cinquant a del ventesimo secolo, e seguito da altri “pezzi storici” contemporanei quali l’ALGOL, il LISP ed il COBOL. A metà degli anni Sessanta nacque un linguaggio che, nel giro di poco tempo, si affermò come il più diffuso linguaggio di programmazione, restando in auge per diverse decadi, il BASIC. Istruzioni come “PRINT”, per !55 55

visualizzar e sullo schermo un risultato o un messaggio all’utente, “INPUT”, per leggere ciò che l’utente digitava sulla tastiera, “FOR..NEXT” per eseguire cicli, “GOTO” per eseguire dei salti, “DIM” per dichiarare una variabile divennero termini noti a tutti: i computer ad 8 bit degli anni Ottanta, come il Commodore 64, lo ZX Spectrum, i computer MSX ed altri ancora contribuirono all’affermazione di questo linguaggio dato che esso era preinstallato nelle memorie di quasi ogni macchina venduta a quel tempo.

4.2 Il linguaggio C Ma è un altro il linguaggio quello che ci interessa: il C. Nato per opera di Dennis Ritchie e Ken Thompson alla fin degli anni Sessanta come linguaggio di programmazione per il da poco creato sistema operativo UNIX, si impose in breve tempo per la sua semplicità e per la compattezza, l’effici nza e la velocità del codice compilato. Grazie a questi fattori fu deciso di riscrivere il kernel di UNIX in C: rispetto alla precedente versione in assembly, il C permetteva di avere un unico sorgente indipendente dall’hardware sottostante, facilitando la distribuzione del software: prima ogni macchina basata su UNIX doveva avere la propria versione del kernel perché l’assembly è intimamente legato ad una particolare CPU ed il codice scritto per un tipo di processore non gira su un altro modello perché gli opcode sono differenti. In poco tempo il C rafforzò la sua fama di linguaggio di rilievo per la scrittura dei sistemi operativi. Il C univa i vantaggi di un linguaggio a basso livello a quelli di un linguaggio ad alto livello: come un linguaggio ad alto livello, permetteva di scrivere codice usando un linguaggio facile da ricordare, semplice, con poche istruzioni native ma che permetteva all’utente di crearsi istruzioni personalizzate anche complesse; come un linguaggio a basso livello permetteva di dialogare facilmente con l’hardware di una macchina, ed il suo compilatore generava un eseguibile molto compatto e dotato di una elevata velocità di esecuzione, quasi pari a quelli di un programma scritto direttamente in codice macchina. Agli inizi degli anni Ottanta nacque il successore del C, il C++, ad opera di Bjar ne Stroustrup. Nato come “C con le Classi” e poi ridenominato C+ + , per richiamare l’operatore di incremento “+ + ” del linguaggio C, esso introduceva il supporto alla programmazione orientata agli oggetti, un nuovo modo di programmare basato sul fatto di utilizzar e “oggetti” software, ossia porzioni delimitate del codice chiamate classi che racchiudono sia le dichiarazioni dei dati usati sia i metodi, ossia le funzioni che la classe stessa è in grado svolgere. L’ereditarietà permette, una volta creata una classe principale, di creare delle classi fi lie di quella classe genitore, da cui ereditano i tipi di dati ed i metodi su !56 56

Capitolo 11

Numeri casuali, bit e byte e funzioni matematiche 11.1 - Numeri casuali L’Arduino può generare dei numeri pseudo-casuali. Sono detti “pseudocausali” perché non provengono da un vero generatore casuale ma sono creati da un algoritmo matematico e non hanno quindi una vera casualità. Per ottenere un numero casuale si usa la funzione random(). La sintassi è la seguente: long numero = random([min, ] [ max]);

La funzione restituisce un numero intero di tipo long (quindi con segno). min e max sono opzionali, possono essere passati entrambi oppure solo il secondo: • random()
 restituisce un numero intero casuale compreso fra 0 e 231- 1 (2.147.483.647); • random(max)
 restituisce un numero intero casuale compreso fra 0 e max-1; • random(min, max)
 restituisce un numero intero casuale compreso fra min e max-1. Vediamo alcuni esempi:

random(); //forma base random(100); //numeri compresi fra 0 e 99 (100-1) random(-1000, 1000); //numeri compresi fra -1000 e 999 (1000-1)

Se volessimo “tirare” un dado dovremmo scrivere: byte dado = random(1, 7);

Abbiamo scelto una variabile di tipo byte per contenere il numero casuale perché un dado può dare solo valori compresi fra 1 e 6: il compilatore esegue qui l’autocasting convertendo il tipo del risultato da long a byte. La funzione random viene chiamata passando come argomenti i numeri 1 e 7 che rappresentano gli estremi min e max. !157 157

Il numero restituito cade nell’intervallo compreso fra il valore minimo passato per min, che è compreso fra i numeri che vengono generati, ed il valore fornito per max, che non è invece compreso perché il numero più grande estraibile è sempre inferiore di 1 unità rispetto al valore massimo passato. Stampiamo sul monitor seriale i valori di 10 “lanci” di un ipotetico dado usando questo sketch:

void setup() { Serial.begin(19200); delay(1000); for (byte i = 0; i < 10; i++) { Serial.println(random(1, 7)); } } void loop() { }

L’output che otteniamo è il seguente: 2 2 6 3 5 3 1 3 6 2

Adesso premiamo il pulsante di reset sulla scheda e guardiamo la nuova sequenza di “lanci”: 2 2 6 3 5 3 1 3 6 2

Essa è perfettamente identica alla precedente perché il generato di numeri casuali è in realtà un generatore di numeri pseudo-casuali! Essendo forniti da un algoritmo, ogni volta che avviamo la scheda l’algoritmo genere i medesimi valori. Esiste un modo per rendere più casuale la sequenza: fornendo un seme. Viene chiamato seme il valore che viene utilizzato per inizializzar e un algoritmo crittografico. La funzione per inizializzar e l’algoritmo di numeri pseudo-casuali dell’Arduino è randomSeed(): randomSeed(seme);

!158 158

seme è un numero intero di tipo unsigned int. Attenzione: se utilizzate un seme costante, la sequenza rimarrà anche in questo caso sempre uguale ad ogni riavvio della scheda. Ad esempio, se riprendiamo l’esempio precedente e lo modifi hiamo così: void setup() { Serial.begin(19200); delay(1000); randomSeed(999); for (byte i = 0; i < 10; i++) { Serial.println(random(1, 7)); } } void loop() { }

Ogni volta che avvieremo la scheda otterremo sempre questi numeri: 4 5 6 5 3 5 3 1 4 1

I numeri cambiano rispetto al precedente esempio in cui generavamo numeri casuali senza l’uso di un seme ma si ripetono comunque. Come fare quindi per ottenere un seme variabile e poter avere delle sequenze sempre diverse ad ogni avvio della scheda? Possiamo utilizzar e come sorgente un pin analogico non connesso a niente. Abbiamo visto in precedenza che un pin non connesso porta ad una lettura fluttuante. Se in un pin digitale la cosa si limita a due valori, un pin analogico flo tante può dare invece molti più valori. Sfruttando questa caratteristica, possiamo utilizzar e la lettura di un pin analogico lasciato libero come seme per l’algoritmo pseudo-causale dell’Arduino. Se proviamo il seguente codice possiamo vedere come ad ogni sequenza di “lanci” i valori siano sempre diversi: void setup() { Serial.begin(19200);   delay(1000);   randomSeed(analogRead(A0));    for (byte i = 0; i < 10; i++) {      Serial.println(random(1, 7));    } } void loop() { }

!159 159

Sezione 3 L’elettronica E La Sperimentazione

!181

Capitolo 14

Principi di Elettronica, componenti elettronici di base 14.1 Che cos’è l’elettricità L’Arduino non è solo programmazione. Essendo una scheda di prototipazione elettronica, essa può interagire con dispositivi elettrici ed elettronici. Conoscere le basi dell’elettronica è fondamentale per poter sfruttare al massimo le capacità offerte ed interagire con il mondo esterno. Gli appunti che leggerete qui non vogliono in alcun modo sostituirsi ai testi specifici sull’argomento né pretendere di poter offrire le nozioni che si possono apprendere nei corsi di studi appositi ma rappresentare solo un’infarina tura sui concetti base e sui componenti passivi elementari che andremo ad utilizzar e nei capitoli successivi per eseguire alcuni esercizi pratici. Il termine elettricità indica tutti quei fenomeni fisici che si manifestano grazie alla forza elettromagnetica. Un fulmine è l’esempio più evidente di una manifestazione dell’elettricità: una scarica elettrica che percorre il cielo dalle nuvole di un temporale a terra. La scarica visibile ad occhio nudo è solo il fenomeno macroscopico: a livello microscopico la scarica è data dall’interazione di alcune particelle cariche elettricamente che compongono gli atomi della materia, gli elettroni. Gli elettroni orbitano intorno al nucleo di un atomo e sono in numero pari a quello dei protoni contenuti nel nucleo stesso: i protoni sono particelle elettriche dotate di una carica arbitrariamente detta positiva. Gli elettroni sono di carica opposta, arbitrariamente detta carica negativa. La somma delle cariche positive e negative in un atomo è pari a zero: difatti un atomo è elettricamente neutro. Gli elettroni ruotano disponendosi su più livelli detti orbitali. Gli elettroni sull’orbitale più esterno possono essere influ nzati da forze esterne e spostarsi da quegli orbitali, come ad esempio per la vicinanza di un altro atomo: è il caso delle molecole, in cui due o più atomi si legano elettricamente insieme condividendo gli elettroni degli orbitali esterni. Un orbitale può contenere un certo numero di elettroni: il primo orbitale ne può !182 182

contenere 2, il secondo 8 e così via. Gli atomi sono classific ti secondo il numero di elettroni sull’orbitale più esterno, secondo la nota tavola periodica degli elementi sviluppata da Mendeleev nell’800. In tale tavola gli elementi sono disposti in 8 classi, ognuna indicante il numero di elettroni dell’ultimo orbitale: 1, 2, 3, ecc.. Un atomo tende a perdere o guadagnare elettroni per avere l’orbitale più esterno sempre completo, con 8 elettroni. Se l’atomo ha meno di 4 elettroni sull’orbitale esterno esso tenderà a perdere facilmente quegli elettroni per mostrare l’orbitale inferiore, che è completo. Se invece ha più di 4 elettroni, esso tenderà ad acquistarli per completare l’orbitale. Questa capacità di cedere o acquistare elettroni è detta elettronegatività ed è indicata da un numero: più il numero è prossimo allo zero e più l’atomo tende a perdere elettroni, più il numero è grande e più l’atomo tende ad acquistare elettroni. Lo spostamento di elettroni crea degli atomi con una carica elettrica, detti ioni: se l’atomo ha perso degli elettroni, esso acquisterà una carica positiva perché i protoni del nucleo saranno in numero maggiore rispetto agli elettroni con carica negativa rimasti, mentre se l’atomo ha acquistato degli elettroni mostrerà una carica negativa perché gli elettroni saranno in numero maggiore rispetto ai protoni del nucleo. Il movimento degli elettroni crea un flusso di cariche elettriche, ed è questo flusso il esponsabile dei fenomeni elettrici.

14.2 Corrente continua e corrente alternata Finora abbiamo parlato di corrente in senso generico. Esistono però due tipi di corrente dalle caratteristiche differenti: la corrente continua e la corrente alternata. La corrente continua è una corrente che manifesta un flusso di intensità e direzione costanti nel tempo. La corrente continua è quella erogata da una normale batteria alcalina, ad esempio le batterie stilo da 1,5 V. Se colleghiamo ai poli di una di queste batterie una lampadina ad incandescenza di pari tensione di lavoro, vedremo che essa si accende. La lampadina emetterà una luce costante perché l’intensità della corrente continua resta costante, così come la direzione in cui scorre la corrente: la corrente continua scorre sempre dal polo positivo al polo negativo. La corrente continua è abbreviata in CC, da “Corrente Continua”, oppure DC, dall’inglese “Direct Current”. Ben diversa è la corrente alternata. La corrente alternata è quella che abbiamo disponibile dalle prese elettriche di casa, che è detta tensione di rete e che ci viene fornita dal nostro gestore elettrico. Essa è caratterizza ta da un flusso che cambia periodicamente di direzione o, per meglio dire, cambia di polarità: !183 183

possiamo infatti immaginare che la corrente scorra dal primo polo al secondo per un breve lasso di tempo, poi inverta polarità e scorra dal secondo verso il primo, poi nuovamente dal primo al secondo e così via infini amente. Nel caso della tensione di rete disponibile in Italia essa cambia polarità 50 volte al secondo, vale a dire che ogni 1/50 di secondo essa scorre prima in un verso (per metà del tempo, ossia 1/100 s) e poi nel verso opposto (per l’altra metà, ossia ancora 1/100 s). La tensione di rete è infatti a 50 hertz, e l’hertz (simbolo Hz) è l’unità di misura della frequenza: prende il nome dal fisico tedesco Heinrich Hertz. La corrente alternata non cambia solo di polarità ma anche di intensità: essa scorre con un valore di intensità inizialmente pari a zero per poi aumentare fino al valore massimo e diminuire nuovamente a zero, e così via. Per facilitarci la comprensione di come varia la corrente alternata nel tempo possiamo aiutarci con un grafico:

L’onda sinusoidale rossa rappresenta la corrente alternata. È detto periodo il tempo che essa impiega a compiere due oscillazioni complete; è detta tensione di picco la tensione misurata al picco massimo (positivo o negativo),;è detta tensione picco picco la tensione misurata fra il picco massimo positivo ed il picco massimo negativo; è detto valore efficace, indicato anche come RMS (da Root Mean Square), il valore che avrebbe un segnale costante di pari potenza. Nel caso della tensione di rete italiana la tensione di picco è pari a ca. 325 V, la tensione picco picco è pari a 325 + 325 = 650 V, ed il valore efficac è pari a 230 V. Nei regimi di corrente alternata quest’ultimo valore si ottiene dividendo la tensione di picco per la radice quadrata di 2:

RMS = Vmax / √2

Spiegare come si arriva a questo valore esula dagli scopi di questa guida, per approfondire l’argomento è consigliata la consultazione di un testo di elettrotecnica. Il valore efficac serve principalmente per semplifica e i calcoli !184 184

Capitolo 15

I primi progetti 15.1 Progetto 1: Accensione di un LED mediante un pulsante Il percorso che ci ha portato sin qui è stato molto lungo: abbiamo fatto una panoramica sull’hardware, abbiamo studiato il linguaggio di programmazione ed abbiamo terminato con lo studio delle basi di elettronica e dei più semplici componenti elettronici. Adesso è tempo di mettere in pratica tutto quello che abbiamo studiato realizzando i nostri primi progetti. Questo capitolo mostrerà alcuni semplici esercizi pratici che potremo realizzare con componenti comunemente reperibili in un qualunque negozio di materiale elettronico oppure presso un fornito shop virtuale. Gli esercizi verranno corredati dell’elenco dei componenti impiegati, di uno schema di montaggio realizzato con il programma libero Fritzing (www.fritzing.org), dello schema elettrico realizzato con il CAD elettronico Eagle (nella versione freeware) e dello sketch da caricare sulla scheda Arduino UNO direttamente dall’IDE ufficial . Il primo progetto che andremo a realizzar e è il classico circuito in cui l’utente può accendere/spe gnere un LED mediante la pressione di un pulsante.

Materiale occorrente Per questo progetto avremo bisogno dei seguenti componenti: • 1 scheda Arduino UNO • 1 pulsante a montaggio superficial • 1 LED di colore rosso, verde o giallo • 1 resistore da 10 KOhm (marrone/ne ro/arancione ) • 1 resistore da 220 Ohm (rosso/r osso/mar rone) • cavetti per i collegamenti Ut ilizziamo per il LED un resistore di limitazione di corrente di 220 ohm perché questo valore va bene per l’uso con uno qualunque dei 3 LED indicati (rosso, verde e giallo), senza dover calcolare il valore specifico per il colore che intendiamo utilizzar e. !206 206

Collegamenti Effettuiamo i seguenti collegamenti (vedi figura “ rogetto 1”): • collegare il pin 5V dell’Arduino con le linee positive della basetta; •c ol l eg a r e u n o dei p i n G N D dell’Arduino con le linee di massa della basetta; • piazzar e il pulsante a cavallo del solco centrale della basetta; • collegare il piedino in alto a sinistra del pulsante del lato opposto a quello dell’ Ar dui n o a lla li n ea posi t i va dell’alimentazione mediante il resistore da 10K; • collegare il piedino in basso a sinistra del pulsante con il pin 9 dell’Arduino; • collegare il piedino in basso a destra del pulsante con la linea di massa; •piazzar e il LED sulla baset t a mantenendo i suoi terminali su una ! delle colonne principali ma prestando Progetto 1 - Collegamenti attenzione a infila li in due fil diverse; • collegare l’anodo del LED (il terminale più lungo) al pin 3 dell’Arduino; • collegare il catodo del LED alla linea di massa mediante il resistore da 220 Ohm.

Sketch Adesso dobbiamo caricare il programma sulla scheda. Apriamo l’IDE e carichiamo il seguente sketch: //Progetto 1 - Azionamento di un LED mediante un pulsante //costanti const byte LED_OUT = 3; //pin di uscita (LED) const byte SWITCH_IN = 9; //pin di ingresso (pulsante) //variabili globali byte statoLed = 0; //stato iniziale del LED: spento //configurazione dei pin void setup() { pinMode(LED_OUT, OUTPUT); //pin del LED come output pinMode(SWITCH_IN, INPUT); //pin del pulsante come input }

!207 207

//ciclo principale void loop() { //controllo se il pulsante è stato premuto if (digitalRead(SWITCH_IN) == LOW) { //LED spento o acceso? if (statoLed == 0) { //spento: lo accendo statoLed = 1; } else { //acceso: lo spengo statoLed = 0; } //imposto il nuovo stato digitalWrite(LED_OUT, statoLed); delay(250); //piccola pausa “anti-rimbalzo" } }

Funzionamento Definiamo inizialmente alcune costanti che utilizzeremo per l’indicazione dei pin: questo ci sarà utile se in un secondo momento vorremo cambiare i pin a cui abbiamo collegato il LED ed il pulsante perché basterà modifica e il numero del pin nell’assegnazione della relativa costante che andremo a cambiare questo valore in qualunque parte dello sketch in cui abbiamo utilizzato il nome della variabile al posto del numero esplicito. Segue la dichiarazione di una variabile globale relativa allo stato del LED. La variabile globale ha, oltre al fatto di essere visibile in qualunque funzione dello sketch, la particolarità di conservare il suo valore alla fin del loop(), potendo così mantenere lo stato del LED attraverso le varie ripetizioni della funzione principale del programma. Nella funzione setup() abbiamo inserito la dichiarazione relativa alla modalità di funzionamento dei pin utilizzati dallo sketch: abbiamo dichiarato il pin a cui è collegato il LED come output, mentre abbiamo dichiarato come input quello a cui è connesso il pulsante. Nella funzione loop() c’è il codice principale del programma: leggiamo continuamente lo stato del pulsante e, nel caso esso venga premuto, di cambiare lo stato del LED. Il controllo sulla lettura viene effettuato con la funzione digitalRead() a cui passiamo come parametro il numero del pin: questo valore è contenuto nella costante SWITCH_IN. La funzione digitalRead() restituisce LOW se viene letto un valore di tensione prossimo a 0 V e HIGH se la tensione è prossima a 5 V. Nell’esempio abbiamo utilizzato il valore restituito in maniera diretta, semplicemente inserendo la funzione come membro sinistro dell’operatore di uguaglianza. Il confronto lo facciamo con lo stato LOW. Nel caso il pulsante venga premuto, cambiamo lo stato del LED, accendendolo o spegnendolo, mediante l’uso della variabile globale statoLed. La piccola pausa alla fin del blocco di codice dell’if serve ad !208 208

evitare che, alla pressione del pulsante, il codice accenda/spe nga il LED ripetutamente nel caso si faccia una pressione un po’ più lunga del necessario.

15.2 Progetto 2: Accensione temporizzata di un LED Questo progetto è simile al precedente: differisce per il fatto che il pulsante serve solo ad accendere il LED. Questo si spegne in automatico dopo un certo periodo di tempo. Ogni pressione del pulsante fa ripartire il conteggio del tempo di timeout.

Materiale occorrente Il materiale occorrente è identico a quello del progetto 1.

Collegamenti I collegamenti sono identici a quelli del progetto 1.

Sketch // Progetto 2 - Accensione temporizzata di un LED //costanti const byte LED_OUT = 3; //pin di uscita (LED) const byte SWITCH_IN = 9; //pin di ingresso (pulsante) const int TIMEOUT = 5000; //timeout - 5 secondi //variabili globali byte statoLed = 0; //stato iniziale del LED: spento unsigned long attivazione; //memorizza l'istante di accensione //configurazione dei pin void setup() { pinMode(LED_OUT, OUTPUT); //pin del LED come output pinMode(SWITCH_IN, INPUT); //pin del pulsante come input } //ciclo principale void loop() { //controllo se il pulsante è stato premuto if (digitalRead(SWITCH_IN) == LOW) { //accendo il LED statoLed = 1; digitalWrite(LED_OUT, HIGH); attivazione = millis(); //salvo l'istante } if (statoLed) { //il LED è acceso? //controllo se è trascorso il tempo di timeout if (millis() - attivazione > TIMEOUT) { //sì, devo spegnere il LED digitalWrite(LED_OUT, LOW); statoLed = 0; } } }

!209 209

Capitolo 16

Interazione con l’utente 16.1 Schermi a cristalli liquidi (LCD) Finora abbiamo visto esaminato le funzionalit à base dell’Arduino: abbiamo preso dimestichezza con la lettura di un ingresso analogico, abbiamo imparato come impostare i pin in input ed in output, abbiamo provato la lettura e la scrittura di dati sulla linea seriale. In questo capitolo inizieremo a sperimentare con funzionalit à per l’interazione con l’utente: Arduino è un microcomputer e come tale può gestire forme di input/out put con un utente, in modo del tutto autonomo. Con l’uso di dispositivi semplici quali i display LCD o le tastiere in stile telefonico possiamo fornire dei dati ed ottenere informazioni dal nostro progetto basato su Arduino. Gli schermi a cristalli liquidi, detti anche display LCD, da Liquid Crystal Display, sono comunemente utilizzati come dispositivi di output per la loro semplicità d’uso e per il loro moderato consumo energetico. Sono in genere identific ti dal numero di colonne e righe che li compongono: ad esempio, un display 16x2 è un display composto da una matrice di 16 colonne per 2 righe di celle, ogni cella è composta da una matrice di pixel, generalmente 5x8 pixel.

Sono per la maggior parte basati sul controller Hitachi HD44780: grazie alla sua diffusione, questo controller ha creato uno standard de-facto nell’industria. Questi schermi comunicano con una linea parallela a 4 oppure 8 bit, e permettono di regolare il contrasto da un pin mediante il collegamento di un !218 218

potenziometro. Alcuni display sono forniti anche di retroilluminazione, pilotabile tramite un transistor, ad esempio. Grazie all’uso di controller compatibili fra loro è stato possibile realizzar e una libreria in grado di gestire la stragrande maggioranza degli schermi in circolazione: la libreria si chiama LiquidCrystal ed è inclusa in quelle disponibili con l’IDE di Arduino. Prima di pensare alla parte software, dobbiamo pensare a collegare lo schermo alla nostra scheda Arduino. Per fare ciò abbiamo bisogno dei seguenti componenti: • scheda Arduino UNO • schermo a cristalli liquidi compatibile HD44780 di una qualunque misura supportata dalla libreria (es.: 16x2, o 16x4); • potenziometro da 10 KOhm; • striscia di pin; • cavetti per i collegamenti. I display sono generalmente distribuiti già montati su una scheda, con il controller saldato sulla parte posteriore ed una fila di 16 fori per i collegamenti (standard HD44780). Consiglio di saldare una fila di pin per facilitare i collegamenti ed evitare falsi contatti: saldate i pin montando la parte più lunga sul retro della scheda, in modo da facilitare l’inserimento su una basetta di prototipazione o il montaggio su un circuito realizzato da voi (vedi figura 8).

Figura 8: i pin di collegamento saldati sulla scheda di un display LCD 16x2

I pin sono numerati dall’1 al 16 per facilitarne l’identificazion , vedi tabella 8. La tensione dell’alimentazione è generalmente a 5 V, per poter lavorare con le logiche TLL. L’alimentazione fornita tramite i pin VDD/ VSS serve l’elettronica di controllo: la retroilluminazione, se presente, è servita dai pin A/ K: controllare sulla scheda tecnica fornita dal costruttore se anche su questi pin !219 219

Pin

Nome

Note

1

VSS

Massa dell’alimentazione

2

VDD

Positivo dell’alimentazione

3

VLC

Contrasto dell’immagine

4

RS

0 per l’invio di comandi, 1 per l’invio di dati

5

R/W

0 per lettura/scrit tura, 1 per sola lettura

6

E

Pin di “Enable” per le operazioni di R/S o R/W

7

D0

Bus dati

8

D1

Bus dati

9

D2

Bus dati

10

D3

Bus dati

11

D4

Bus dati

12

D5

Bus dati

13

D6

Bus dati

14

D7

Bus dati

15

A

Positivo per retroilluminazione

16

K

Massa per retroilluminazione Tabella 8: corrispondenza fra pin e linee dei display con controller HD44780

dobbiamo dare 5 V oppure una tensione differente e se dobbiamo utilizzar e un resistore per limitare la corrente, dato che questa linea alimenta dei LED, o se il resistore è già integrato sulla scheda elettronica. Come detto, il bus dati può funzionare sia a 4 che ad 8 pin: si collegano perciò solo i pin utilizzati. Sarà cura dell’utente in fase di inizializzazione della libreria indicare la dimensione del bus stesso. Di solito si utilizzano solo 4 linee di dati per risparmiare sui collegamenti e impiegare meno pin dell’Arduino: usando 8 linee, comunque, l’invio dei dati avviene in maniera più veloce. Il pin VLC va collegato ad un potenziometro per la regolazione del contrasto. Il pin RS è pilotato dalla libreria e serve ad indicare al controller se stiamo inviando un comando o dei dati. Il pin R/W può essere collegato direttamente a massa perché in genere il display è utilizzato per visualizzar e dei dati per cui necessitiamo della possibilità di scrivere sulla memoria RAM del buffer video del controller integrato. !220 220

Sezione 4 Tecniche Avanzate

!238

Capitolo 17

Le porte logiche 17.1 Le porte logiche del microcontrollore Abbiamo visto nel capitolo 10 che Arduino ci mette a disposizione delle comode funzioni per poter operare con le linee di I/O digitale della scheda: con pinMode() possiamo dire al microcontrollore se un dato pin lo vogliamo usare come ingresso (INPUT) o come uscita (OUTP UT), con digitalWrite() possiamo impostare lo stato di un pin e con digitalRead() lo possiamo leggere. Sembra semplice. Ma se andiamo ad analizzar e il codice delle librerie base di Arduino ci accorgiamo che non lo è. È vero che la semplicità dell’IDE di Arduino permette di fare queste operazioni usando poche istruzioni ma nel “retrobottega” le operazioni che vengono eseguite sono diverse, perché Arduino deve effettuare una serie di calcoli per trasformare il numero di pin nel corrispondente piedino fisico e poi ancora controllare se quel pin è collegato ad un timer, e nel caso disattivare l’eventuale segnale PWM che ci può essere collegato. Solo allora il pin viene impostato come si vuole. Se non si ricerca una grande velocità tutti questi passaggi, che vengono eseguiti tutte le volte che invochiamo tali istruzioni, possono anche non creare problemi ma se vogliamo fare le cose in modo più rapido e diretto la soluzione è solo una: operare a livello di porte logiche del microcontrollore.

17.2 Gestione digitale delle porte Come abbiamo visto in precedenza, microcontrollore è un dispositivo elettronico complesso composto da diverse periferiche: tutto, però, è fatto a livello digitale. Non esiste un meccanismo meccanico da azionare, un interruttore che viene premuto quando vogliamo cambiare lo stato di un pin: esistono dei particolari registri mappati in memoria che contengono lo stato di ogni singola linea di input/out put (I/O) del microcontrollore. Ogni registro rappresenta lo stato di una porta logica quindi una porta logica è l’insieme dei bit collegati ad un gruppo di piedini fisici del microcontrollore. Leggendo o scrivendo in questi registri si può operare in maniera diretta sui pin. !239 239

Le porte logiche degli Atmel della serie AVR ATtiny e ATmega sono registri ad 8 bit, per cui ogni porta logica può contenere al massimo lo stato di 8 linee di I/ O, ossia di 8 pin del microcontrollore. Ogni pin è identific to da una sigla, come PD0, PC1 o PB2. Ad esempio, PB0 identifica il pin 0 della porta logica “B”. L’ATmega328P ha 23 linee di I/O raggruppate in 3 porte logiche da 8 bit l’una denominate B, C e D. Ogni porta è gestita da 3 registri, denominati DDRx, PORTx e PINx dove la “x” rappresenta la lettera identific tiva della porta. Per ogni porta possiamo agire sulla corrispondente linea di I/O mediante i bit del registro collegato. Negli schemi seguenti, la lettera “y” indica la porta (B, C, o D) e “x” il bit (può assumere un valore compreso fra 0 e 7), es.: DDRB2: • DDRx: questo registro è di lettura/scrit tura e contiene la direzione dei pin ad esso collegati. I bit sono denominati DDyx. Un bit a 0 rappresenta un pin impostato come INPUT; un bit ad 1 rappresenta un pin impostato come OUTP UT. DDy7

DDy6

DDy5

DDy4

DDy3

DDy2

DDy1

DDy0

• PORTB: questo registro è di lettura/scrit tura e contiene lo stato dei pin. I bit sono denominati PORTyx. Questo stato cambia a seconda della direzione del pin: • se il pin è impostato come INPUT, un bit ad 1 attiva il resistore interno di pull-up, mentre un bit a 0 la disattiva; • se il pin è impostato come OUTP UT, un bit ad 1 indica un segnale alto (HIGH) sul relativo pin, mentre un bit a 0 indica la presenza di un segnale basso (LOW). PORTy7

PORTy6

PORTy5

PORTy4

PORTy3

PORTy2

PORTy1

PORTy0

• PINB: questo registro è di sola lettura e contiene, nel caso di un pin impostato come INPUT, la lettura del segnale collegato al pin. I bit sono denominati PINyx. I bit valgono 1 per un segnale alto (HIGH) e 0 per un segnale basso (LOW). PINy7

PINy6

PINy5

PINy4

PINy3

PINy2

PINy1

PINy0

Da ciò si capisce subito come per impostare un pin come OUTP UT con un livello HIGH non dobbiamo far altro che impostare prima la direzione dello stesso mediante il registro DDRx e poi cambiare il livello del segnale con il registro PORTx. Tutto questo lo possiamo effettuare ricorrendo all’uso degli operatori per la manipolazione dei bit visti nel capitolo 5.5.5. Facciamo un esempio pratico. Vogliamo impostare il pin PB2 come OUTP UT con livello in uscita HIGH. Dobbiamo operare sul 3° bit (ricordatevi che il !240 240

conteggio delle posizioni parte da 0, per cui il bit n° 2 è il 3° bit) dei registri DDRB e PORTB, usando il primo per impostare la direzione del pin ed il secondo il segnale che vogliamo: DDRB |= (1<
Aiutandoci con la figura 7 del capitolo 10.1 dov’è riportata la corrispondenza fra pin dell’Arduino e piedini del microcontrollore possiamo trovare che il pin PB2 corrisponde al pin digitale 10, per cui le istruzioni viste qui sopra corrispondono alle seguenti funzioni di Arduino: pinMode(10, OUTPUT); digitalWrite(10, HIGH);

Come detto, la differenza fra i due insiemi risiede nella velocità: il primo viene sempre eseguito con una velocità maggiore. E c’è anche il vantaggio della compattezza del codice. La differenza è ancora più notevole nel caso si debba cambiare lo stato a diverse porte: manipolando direttamente le porte logiche possiamo cambiare la direzione e lo stato di più pin in un unico passaggio. Ad esempio, se volessimo impostare i pin dal PB0 e PB1, i pin digitali da 8 e 9, come output con segnale alto non dovremmo far altro che scrivere questo codice: DDRB |= ((1<
Oppure, se non ci interessa cambiare anche gli altri pin, usare istruzioni di assegnazione dirette, ancora più veloci: DDRB = 0b00000011; PORTB = 0b00000011;

Usando il linguaggio di Arduino saremmo stati costretti a scrivere qualcosa di simile: pinMode(8, OUTPUT); pinMode(9, OUTPUT); digitalWrite(8, HIGH); digitalWrite(9, HIGH);

E avremmo dovuto anche considerare il tempo occorso ad eseguire ogni singola chiamata a pinMode() ed a digitalWrite(), ricordandoci quanto detto in precedenza circa le operazioni ed i controlli che l’Arduino esegue sui pin. Eseguiamo adesso la lettura digitale di un pin e troviamo l’equivalente delle seguenti istruzioni:

pinMode(10, INPUT); byte a = digitalRead(10);

Dobbiamo impostare prima la direzione del pin PB2 (corrispondente al pin digitale 10) scrivendo 0 sul bit DDRB2 per attivare il pin come ingresso e poi !241 241

Capitolo 19

Gli interrupt 19.1 Gestione degli interrupt Il signific to del nome spiega già il loro compito: gli interrupt sono dei particolari segnali che vengono utilizzati per interrompere le normali funzioni della CPU del microcontrollore ed obbligarla ad eseguire una porzione speciale di codice detta Interrupt Service Routine (ISR), ossia una funzione di servizio di un interrupt. A cosa servono gli interrupt? Principalmente a svolgere un compito che ha una priorità maggiore di quella del codice dello sketch e che deve essere eseguito nel momento stesso in cui arriva l’ordine di farlo, ordine dato da un particolare evento che può accadere sia all’interno che all’esterno del microcontrollore. Gli interrupt esterni sono interrupt generati da segnali elettrici letti sui piedini del microcontrollore mentre gli interrupt interni sono segnali inviati dalle periferiche integrate. Abbiamo studiato in precedenza i timer: anche i timer possono essere programmati per sollevare un interrupt, ad esempio quando il registro contatore va in overfl w oppure quando il valore che contiene è identico al valore di un registro di comparazione. Il verbo usato per indicare l’arrivo di un segnale di interruzione è sollevare, che deriva dall’inglese to raise. La gestione degli interrupt avviene tramite appositi registri i cui bit vengono costantemente monitorati dalla CPU per controllare se un interrupt è stato sollevato. Il microcontrollore può essere programmato per ignorare tutti gli interrupt oppure per ignorarne solo alcuni: nel primo caso esiste un bit nel registro di stato del microcontrollore che attiva o disattiva gli interrupt a livello globale. Se questo bit è “acceso” (se cioè il bit corrispondente vale 1) il microcontrollore gestisce tutti gli interrupt in arrivo, se invece è “spento” (se il bit vale 0) allora il microcontrollore ignora tutti i segnali. Il registro in questione si chiama SREG ed il bit in questione, l’ottavo di quel registro, si chiama “I”. Possiamo modifica e quel bit in maniera diretta usando alcune istruzioni particolari oppure mediante la manipolazione dei bit. Nel primo caso il compilatore offre due istruzioni: sei() (da “set interrupts”), che attiva gli interrupt globali, impostando il bit ad 1; cli() (da “clear interrupts”), che li !269 269

disattiva ponendolo a 0. Il linguaggio di Arduino ci mette a disposizione due alias (alternative) dei suddetti comandi: interrupts() e noInterrupts(), con le stesse identiche funzioni. Se invece vogliamo manipolare direttamente quel bit possiamo utilizzar e la costante predefini a SREG_I che il compilatore ci mette a disposizione per indicare in maniera implicita la posizione del relativo bit. Per “accendere” il bit il codice sarà il seguente: SREG |= (1<
mentre per “spegnerlo” scriveremo questo: SREG &= ~(1<
Prestate attenzione al fatto che, se disattivate gli interrupt globali, tutte le funzioni temporali di Arduino cessano di funzionare perché sono tutte gestite da una funzione di servizio di un interrupt agganciata al timer 0. Se gli interrupt sono disattivati a livello globale qualsiasi segnale di interrupt verrà ignorato dal microcontrollore. Se invece sono attivi, il microcontrollore gestirà tutti i segnali in arrivo secondo le impostazioni delle periferiche a cui è arrivato il segnale. Ad esempio, un interrupt in arrivo su un piedino del microcontrollore sarà sollevato solo se è stato acceso il relativo bit di abilitazione, altrimenti verrà ignorato. Quando l’interrupt è gestito, il microcontrollore imposta ad 1 il bit relativo: questo provoca da parte della CPU l’interruzione dell’esecuzione del codice dello sketch ed il passaggio ad un blocco di codice specifico che, come abbiamo visto, si chiama Interrupt Service Routine (ISR). La chiamata alla funzione avviene mediante una “jump table”, ossia una “tavola dei salti”: in una zona di memoria posta normalmente nella prima parte della memoria Flash viene scritto un elenco di indirizzi, chiamati anche vettori di salto, che sono gli indirizzi di memoria dove la CPU può trovare ed eseguire le funzioni per gestire i singoli interrupt. In tabella 24 è possibile vedere le prime posizioni della tavola dei salti dell’ATmega328P (l’elenco completo è contenuto nella scheda tecnica del microcontrollore fornita dal produttore). Questo elenco è ordinato per priorità: un interrupt con numero di posizione x nella tavola avrà una priorità maggiore rispetto ad un interrupt il cui vettore di salto è posto in posizione x+1 e priorità inferiore rispetto ad un altro con un vettore in posizione x-1. Ad esempio, l’interrupt INT1 avrà priorità maggiore rispetto a PCINT0 ma priorità inferiore rispetto a INT0. La priorità è importante per capire l’ordine con cui vengono eseg u i t i g l i i n t er r u pt . N e l c a s o i n c u i ve n g a n o s o l l eva t i contemporaneamente 2 interrupt, la CPU eseguirà per primo quello !270 270

VETTORE

INDIRIZZO

SORGENTE

INTERRUPT

1

0x000

RES ET

2

0x001

INT0

Segnale dall’interrupt INT0

3

0x002

INT1

Segnale dall’interrupt INT1

4

0x003

PCINT0

Segnale dall'interrupt PCINT0

5

0x004

PCINT1

Segnale dall'interrupt PCINT1

6

0x005

PCINT2

Segnale dall'interrupt PCINT2

7

0x006

WDT

8

0x007

TIMER2 COMPA

Pin esterno, reset di avvio, reset di Brown- out, reset del watchdog

Segnale dal Watchdog Segnale dal Timer/Count er 2 Compare Match A

Tabella 24: estratto della tavola dei salti (“jump table”) delle ISR dell’ATmega328P

con priorità maggiore. Ogni interrupt resta registrato fino a che non viene eseguita la corrispondente ISR. All’uscita della ISR il relativo bit viene resettato (posto a 0). È anche possibile resettarlo manualmente scrivendo il valore 0 nel relativo bit: in questo caso viene cancellata la richiesta di esecuzione della ISR. E se arriva un segnale di interrupt mentre la CPU sta già eseguendo una ISR? Per impostazione predefini a le ISR sono atomiche, ossia il relativo blocco di codice non è interrompibile da altri interrupt: il compilatore inserisce automaticamente l’istruzione cli() subito all’inizio del blocco di codice e poi l’istruzione sei() subito in fondo. Questo comporta anche che le operazioni basate sugli interrupt cessano di funzionare all’interno di una ISR. Quando arriva un interrupt la CPU ferma l’esecuzione del codice principale, salva nello stack il punto del programma a cui era, arrivata rappresentato dal valore del registro Program Counter (PR) che contiene il valore della cella da cui prelevare la prossima istruzione da eseguire, salva tutti i suoi registri interni in modo da poter recuperare l’esatta situazione del lavoro interrotto quando uscirà dalla ISR e poi salta ad eseguire la funzione di gestione dell’interrupt sollevato. Al termine della ISR, la CPU recupera il valore dei registri interni ed infin quello del registro PR in modo che la successiva operazione che andrà ad eseguire sarà quella del programma principale che era stato messo in sospeso. In figura 10 possiamo vedere graficam nte qual è il flusso del programma eseguito dalla CPU prima e dopo l’arrivo del segnale di interrupt. Analizziamo ora come si scrive una ISR. L’esempio qui sotto dichiara la funzione ISR per gestire l’interrupt sollevato dall’overflow del timer 2: ISR(TIMER2_OVF_vect) { …..codice…. }

!271 271

! Figura 10: gestione di una ISR da parte della CPU

La funzione si dichiara usando la speciale parola chiave ISR facendo seguire fra parentesi il vettore dell’interrupt. Come si vede dall’esempio, il vettore dell’interrupt è il nome dell’interrupt seguito dal suffisso vect: al posto degli spazi fra le parole viene usato il carattere di sottolineatura (underscore) come separatore. Il blocco di codice della ISR segue le stesse regole di visibilità del linguaggio per cui per utilizzar e una variabile esterna essa deve essere di tipo globale. Questo da solo però non basta: serve in più l’accortezza di anteporre alla dichiarazione la parola chiave volatile per evitare che il compilatore ne ottimizzi l’uso durante la compilazione, cosa che potrebbe portare a comportamenti del programma inattesi (vedi capitolo 5.3.3):

volatile int contatore = 0; ….. ISR(TIMER2_OVF_vect) { contatore++; }

Che succede nel caso in cui si attivi un interrupt ma non si sia scritta la relativa ISR? In questo caso il comportamento predefini o è quello di resettare il microcontrollore perché il compilatore interpreta la condizione di chiamata ad una !272 272

Capitolo 21

Progetti stand-alone 21.1 Arduino stand-alone Finora abbiamo sempre parlato di scheda Arduino nella sua interezza. Per ogni progetto abbiamo previsto l’utilizzo di una UNO. Un po' dispendioso, economicament e parlando, vero? Non possiamo ogni volta includere nel progetto una scheda e acquistarla ex-novo. Dobbiamo trovare un sistema per poter risparmiare soldi e componenti. La UNO è una scheda di prototipazione per principiant i e come tale è stata ! studiata per per mettere ai Figura 12: una scheda Arduino UNO con il microcontrollore principiant i di fare ciò che gli ATmega328P estratto dallo zoccolo riesce meglio: i danni! Prima o poi chiunque commette un errore e magari collega un LED ad un pin senza usare il necessario resistore oppure mette a corto con massa un pin impostato in uscita con un segnale di livello alto sul pin stesso. Il risultato è disastroso: il microcontrollore cessa di funzionare, e se ne richiede la sostituzione. I progettisti di Arduino hanno pensato anche a questo scenario, quando hanno sviluppato la scheda, ed hanno scelto un microcontrollore in formato DIP, sigla che sta per Dual In-line Package, ossia un chip i cui piedini sono disposti su due fil ordinate ai lati del contenitore. Se abbiamo bruciato il chip e ci rivolgiamo al nostro amico smanettone oppure al nostro rivenditore, ci verrà risposto che “il chip è facilmente estraibile dal suo zoccolo per poter essere sostituito con un altro identico, basta che abbia il bootloader precaricato”. Acquistiamo il chip, estraiamo quello danneggiato, montiamo quello nuovo… et voilà, la scheda è tornata funzionant e!

!291 291

Che succederebbe, però, se noi estraessimo non un chip danneggiato ma un chip perfettamente funzionant e? Potrebbe tornare a funzionare anche montato al di fuori della scheda Arduino? La risposta è sì! Potrebbe funzionare a patto di corredarlo dei componenti minimi necessari a ricreare una scheda Arduino. Quindi avremmo trovato un modo per risparmiare una scheda, usando il solo microcontrollore. Non resterebbe altro da fare, ora, che capire quali sono i componenti minimi necessari affin hé il chip possa funzionare anche non montato sulla scheda. Studiando la scheda tecnica del microcontrollore ed i fil di progetto della scheda Arduino UNO (grazie al fatto che l’Arduino è opensource, chiunque ha accesso ai fil di progetto) possiamo vedere come l’ATmega328P sia abbastanza indipendente. Tralasciando i collegamenti tra i pin D0 e D1 con il chip convertitore US B/S eriale ATmega16U2, che servono per il dialogo con il computer, ciò di cui ha realmente bisogno per funzionare è essenzialmente un segnale di clock esterno. Sull’Arduino UNO c’è un risonatore ceramico con i relativi condensatori sulle linee del segnale ma noi possiamo sostituire quel risonatore con un più comune e altrettanto facilmente maneggiabile quarzo esterno, sostituendo i condensatori a montaggio superficial del primo con dei più normali condensatori ceramici. Infin , ci serve un semplice resistore da 10 KOhm come pull-up sul pin di reset per evitare reset indesiderati del microcontrollore stesso. Tutto qui? Sì, tutto qui! I componenti per un Arduino autonomo, o stand-alone come viene detto in inglese, sono solo questi: • microcontrollore ATmega328P • quarzo a 16 MHz (la stessa frequenza dell’Arduino UNO) • 2 condensatori ceramici da 18 pF (pico Farad) per il quarzo • 1 resistore da 10 Kohm Il microcontrollore è quello della scheda UNO: assicuratevi, al momento dell’acquisto, che la sua sigla contenga la lettera “P” final . Come detto nel capitolo 2.2, ATmega328 e ATmega328P sono due chip differenti. A noi serve il modello “con P”, che ha un core differente. Il quarzo da 16 MHz è necessario affin hé la velocità del nostro Arduino autonomo sia identica a quella della scheda UNO. In alternativa potete anche utilizzar e un risonatore ceramico di pari valore ma attenzione al fatto che un risonatore ha una minor precisione per cui se usate delle funzioni basate sullo scorrere del tempo il risonatore darà intervalli meno regolari e precisi. I condensatori ceramici servono per evitare auto-oscillazioni del quarzo stesso. Atmel nella scheda tecnica dell’ATmega328P fornisce un intervallo di valori utilizzabili compreso fra 12 e 22 pF: 18 pF è un valore abbastanza comune e medio rispetto a quelli suggeriti. Il resistore da 10 KOhm serve come pull-up sul piedino di reset del microcontrollore: senza di esso, flu tuazioni elettrostatiche intorno al chip potrebbero portare a reset !292 292

imprevisti, quindi mettetelo sempre. Tutti i componenti sono normalmente reperibili presso un negozio ben fornito di materiale elettronico: se invece acquistate in rete non avrete che l’imbarazz o della scelta dato il numero considerevole di rivenditori presenti. Ovviamente ci serve un Arduino UNO completo e funzionante, che utilizzeremo per la programmazione del microcontrollore montato in solitario. Reperito tutto il materiale, provvediamo all’assemblaggio del nostro Arduino autonomo, seguendo il seguente schema e rifacendoci alla figura 13: • prendiamo una basetta di prototipazione e colleghiamo insieme le due linee dell’alimentaz ione super ior e ed infer ior e rispettando le polarità; • montiamo l’ATmega328P al centro della basetta in modo che ogni f la di piedini sia incastrata in una metà della basetta; • colleghiamo il piedino n° 1 del chip alla linea di alimentazione rossa della basetta mediante il resistore da 10 KOhm; • montiamo il quarzo da 16 MHz in una zona libera alla destra del chip; ! • colleghiamo i due piedini Figura 13: realizziamo un Arduino stand-alone del quarzo rispettivamente ai piedini 9 e 10 del microcontrollore; • montiamo i 2 condensatori da 18 pF affin hé ognuno di essi abbia un piedino montato sulla linea in comune con uno dei piedini del quarzo e l’altro sia libero al suo esterno; non essendo polarizza ti, possono essere montati come capita; • colleghiamo i piedini liberi dei condensatori alle linee di massa della basetta; • colleghiamo i piedini 7 e 20 del microcontrollore alle linee di alimentazione rosse della basetta; !293 293