Arduino non ha bisogno di presentazioni. Si è imposto come punto d'ingresso per la sperimentazione con i microcontrollori definendosi "open source" e "scheda didattica". La prima definizione non è corretta perché la sua realizzazione, sebbene sembri alla portata di qualsiasi hobbista, in effetti non lo è. Basta dare uno sguardo alla scheda "Arduino Uno" per rendersene conto. A parte la presenza di diversi componenti SMD che potrebbero anche non presentare problemi di montaggio, uno in particolare, combinazione il più importante (il convertitore USB-seriale), è addirittura in contenitore QFN. Questi contenitori non sono affatto semplici da montare, di solito vengono montati in automatico o manualmente da persone esperte. Inoltre non è sufficiente comprare i componenti e montarli, è necessario comunque programmare in qualche modo il bootloader (più avanti spiegherò cos'è) e, nel caso dell'ultima versione, anche il convertitore. E' il classico problema dell' uovo e della gallina: ho bisogno di una gallina per avere un uovo da cui far nascere una gallina.
Rimane comunque un prodotto assai diffuso, divertente, un bel giocattolo, un passatempo intelligente e che, a mio avviso, fa e farà molti danni perché l'effetto collaterale è far credere agli utilizzatori di aver imparato qualcosa sui microcontrollori. Purtroppo non è così, ma possiamo porvi rimedio.
Lo scopo di questo articolo è la realizzazione di una scheda sperimentale basata su ATmega328P (lo stesso di Arduino Uno) che sia 100% compatibile con "Arduino Uno" ma che permetta maggiore flessibilità e che costi molto meno.
Parlerò inoltre di come passare da quello che si può definire un bel gioco, ad un approccio più didattico (veramente didattico) e utile (spendibile a livello professionale) per una vera sperimentazione con questo microcontrollore.
Indice |
Come è fatto Arduino
L'idea è questa: realizziamo un sistema di sviluppo semplice e semplificato, che aggiri in qualche modo la rigorosità di quella che è la programmazione (a costo di usare dei sotterfugi) e che permetta di scrivere qualche programma senza studiare, e che questo funzioni praticamente sempre.
Allo stesso tempo costruiamo un circuito che costi quanto un programmatore per micro (o anche meno) ma su cui si possa caricare un programma (senza programmatore) e farlo funzionare.
Come si fa a fare una cosa del genere? Si utilizza il cosiddetto bootloader. Una parte della memoria del microcontrollore (d'ora in poi lo chiameremo semplicemente "micro") contiene un programma particolare (il bootloader) che, insieme ad un software che gira sul personal computer (d'ora in poi lo chiameremo "PC") gli da modo di auto programmarsi e di far partire il programma caricato.
Il bootloader non è una novità, è una tecnica utilizzata per fare aggiornamenti del firmware sul campo, utilizzando una linea di comunicazione (di solito una seriale) senza bisogno di attrezzature particolari.
Se questa tecnica aveva molto senso anni addietro, quando i programmatori per micro costavano l'anima dei guai, oggi non ha molto senso. I programmatori hanno un costo accessibilissimo, a volte anche minimo e comprarne più di uno è una cosa normalissima, soprattutto per chi lo fa per mestiere, e se lo si rovina non è un dramma.
Lo schema a blocchi di Arduino è sostanzialmente questo
Il sistema di sviluppo, mediante la linea seriale del micro e grazie al bootloader, scarica il programma nella zona di memoria libera. Ovviamente il bootloader (un sottoinsieme del bootloader della scheda Atmel STK500) occupa dello spazio che non è disponibile per il programma utente.
Lo schema a blocchi della nostra scheda è invece il seguente
In questo caso il micro non fa proprio niente se non subire la programmazione da parte del programmatore. Tutta la memoria del micro è disponibile per il programma utente. Inoltre questo programmatore è in grado di programmare molti altri micro della famiglia megaAVR quindi, se volessimo usare un micro più potente o con più pin dovremo solo collegarlo al programmatore come scritto nel datasheet senza inventarci niente.
Una piccola precisazione
Una delle caratteristiche di Arduino che vengono sottolineate, è quella di poter fungere da programmatore per altri micro. Beh, non è niente di speciale, visto che qualsiasi microcontrollore di dimensioni opportune (in questo caso abbastanza piccolino) è in grado di trasformarsi in un programmatore. E' sufficiente caricargli il programma adatto ed il gioco è fatto.
Quindi anche noi potremmo caricare lo scketch ISP dentro il micro ma non avrebbe senso. Useremo un programmatore per programmare un micro che fa da programmatore!
Sul USbasp è montato un ATmega8A che è molto più piccolo di quello montato su Arduino!
Cos'è USBasp
E' un programmatore per micrcontrollori Atmel nato da un progetto di Thomas Fischl che potete trovare a questo link. L'idea era quella di dare la possibilità agli sperimentatori di costruirsi un programmatore con pochi soldi, e che fosse in grado di programmare i micro della Atmel.
Come potete vedere costa pochissimo, la metà di Arduino, ma non è limitato, e per programmare altri micro non bisogna fare i salti mortali.
Come idea è ottima, premette di risparmiare parecchi soldi ed è sicuramente molto flessibile perché non è limitato ad un solo micro. Tecnicamente è di sicuro preferibile ad un qualcosa come Arduino ma bisogna essere capaci a programmare.
Se prendiamo la toolchain AVR-gcc, quella open source, e la affianchiamo a questo programmatore abbiamo un vero sistema di sviluppo per i micro della Atmel. Questa è una bella notizia ma il risvolto della medaglia è che bisogna essere dei programmatori, e non alle prime armi, per poter scrivere anche un semplice programmino. Tuttavia l'oggetto in se è molto valido e vale la pena di prenderlo in considerazione, anche perché oggi sono in commercio dei cloni cinesi di ottima qualità e di bassissimo costo. Tuttavia non basta comprane uno cinese perché, il più delle volte, non funzionerà.
Ma a me le cose semplici non piacciono, quindi ne ho comprato uno cinese ed in questo articolo spiego come ho fatto per renderlo perfettamente funzionante.
Il progetto, ovvero costruiamo il nostro Arduino
Per realizzare il nostro Arduino FURBO abbiamo bisogno, oltre che del materiale per realizzare la scheda:
- Un programmatore USBasp
- Il sistema di sviluppo di Arduino
- Attrezzatura per montare il circuito
- La volontà di fare qualcosa con le proprie mani
- Pochi soldi
Il circuito è questo:
Come si può vedere è estremamente semplice, la sezione composta da D1,C1,U2,C2 fornisce l'eventuale alimentazione quando USBasp non è collegato. Il jumper J1 premette di scollegare l'alimentazione esterna quando questa non viene fornita da USBasp. J2 invece serve per prendere la tensione di alimentazione da USPasp.
Nelle prove che ho fatto ho tenuto J1 aperto e J2 collegato per comodità. Ho così sfruttato la tensione di alimentazione proveniente dal programmatore. Questa è la schedina.
Ho realizzato il prototipo velocemente e su millefori allo scopo di provare il circuito e tutto il sistema, quindi non ho dato molta importanza alla disposizione dei componenti, ma si può benissimo montare in modo da avere lo stesso pinout della scheda originale per potere usare i vari "shields" che si trovano in commercio.
Al posto dello zoccolo normale ho montato uno zoccolo ZIF (Zero Insertion Force) per poterlo usare come semplice programmatore. L'ho comprato dai cinesi su Aliexpress (non mi fido di eBay) perché si sono dimostrati affidabili e molto seri. L'ho pagato una fesseria. Poi, come mia abitudine, ci ho messo anche un LED sull'alimentazione solo per vedere quando è presente. Non è di grandissima utilità ma io lo metto sempre un LED sull'alimentazione, è un mio vezzo.
La prova pratica
Ora che abbiamo il circuito non ci resta che provarlo, e lo faremo con il solito, orrendo, schifosissimo programma di "blink" che fa lampeggiare il LED collegato a PB0. Chiedo scusa ai microcontrollisti per aver riportato un tale obbrobrio ma è utile allo scopo.
Setup dell'IDE
Prima di iniziare dobbiamo istruire l'IDE per adattarlo al nostro programmatore ed alla scheda.
Dal menu Strumenti selezioniamo la scheda Arduino Uno
Poi selezioniamo il programmatore USBasp
Il circuito di prova
Il collegamento del LED è il seguente
Mentre il sorgente per l'IDE di Arduino è questo
/* Blink Turns on an LED on for one second, then off for one second, repeatedly. This example code is in the public domain. */ // Pin 13 has an LED connected on most Arduino boards. // give it a name: int led = 8; // PB0 // the setup routine runs once when you press reset: void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); } // the loop routine runs over and over again forever: void loop() { digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW delay(1000); // wait for a second }
Una volta scritto nell' IDE lo carichiamo nell nostra scheda tramite il comando Carica tramite un programmatore del menu Sketch
A questo punto lo scketch viene compilato e caricato sulla scheda. Vedremo quindi il LED lampeggiare come ci aspettavamo.
Bene, ora c'è tutto quel che serve per gli arduinisti. Da qui in poi si può giocare.
Ora iniziamo a fare sul serio
Se chi legge ha già tutto quello che gli serve e non ambisce ad altro, lo invito a smettere di leggere e continuare con il suo giocattolo. Se per disgrazia c'è qualcuno che ha voglia di andare oltre il semplice gioco e desidera imparare qualcosa di più, qui di seguito descriverò come si inizia a fare qualcosa con questo micro in modo serio.
Abbiamo bisogno di:
- Il sistema di sviluppo ufficiale della Atmel, Atmel Studio 6. E' completamente gratuito e si scarica previa registrazione. Vale la pena averlo perché è veramente un bel sistema di sviluppo.
- La toolchain WinAVR che si può scaricare a questo link. Serve perché contiene la utility avrdude che servirà per impostare un tool esterno per la programmazione del micro tramite USBasp. E' comunque un sistema di sviluppo completo e lo si può integrare su NetBeans. Io l'ho fatto visto che uso NetBeans per Java, php, C, C++ ed altro. Mi piace avere un solo sitema di sviluppo per progetti diversi ma questa è una scelta personale.
Installazione di WinAVR
Anche l'installazione di WinAVR non presenta problemi. Si può benissimo dire di si alla richiesta della modifica delle variabili di ambiente.
Installazione di Atmel Studio 6
Non presenta nessun problema e non c'è da fare attenzione a niente di particolare. Ovviamente bisogna accettare i termini di licenza (sai che novità) e, già che ci siamo, gli facciamo caricare anche i drivers. Ora non ci servono ma un domani potranno servire quindi è preferibile installarli.
Atmel Studio 6 non supporta il programmatore USBasp ma ni possiamo creare uno strumento esterno per poterlo usare ugualmente. Vediamo come si fa.
- Appena compare la schermata di Atmel Studio andiamo nel menù Tools e selezioniamo la voce External Tools.
- Si apre la finestra di dialogo, premiamo il pulsante Add in alto a destra.
- Nel campo Title ci mettiamo il nome del nostro tool, io l'ho chiamato USBasp ATmega328P perché bisogna specificare il tipo di micro.
- Nel campo Command scriviamo la posizione del programma avrdude.exe. Nel mio caso, avendo volutamente installato il software nella cartella dei programmi x86 l' indirizzo è C:\Program Files (x86)\WinAVR\bin\avrdude.exe
- Nel campo Arguments scriviamo -V -c usbasp -p m328p -U flash:w:$(TargetName).hex. Attenzione! se un giorno volessimo programmare un micro differente dovremo cambiare l' ozione -p m328 (che sta per Atmega328) con un altra. Ad esempio se volessimo in futuro programmare un ATmega324 dovremmo scrivere -p m324. Consultare la documentazione di avrdude per la lista dei dispositivi.
- Nel campo Initial directory ci scriviamo $(TargetDir)
- Spuntiamo l'opzione Use Output window per fare in modo di vedere gli eventuali messaggi di errore nella finestra di output.
Io ho anche spuntato l'opzione Prompt for arguments ma solo per motivi di test e perché ... mi piace fare così, ma non è necessario. Che ognuno faccia come meglio crede. La finestra di dialogo apparirà come in questa foto.
Ora, nel nostro menù tools sarà presente la voce che abbiamo creato, come si vede in questa foto.
Questo è il comando che dovremo dare per caricare il programma nella scheda.
Il programma blinky
Ed ora di scrivere il programma blinky in modo normale, non come quella schifezza di sopra. I passi per scrivere questo programmino di test sono e provarlo sulla scheda sono:
- Creare un nuovo progetto (o solution come lo chiama l'IDE)
- Scrivere il file main.c
- Compilarlo correttamente
- Caricarlo sul micro
- Verificarne il buon funzionamento e gioire di questo.
Creiamo il progetto
Lanciamo Visual Studio 6. Già nella schermata principale, la Start Page troviamo a sinistra un menù dove la prima voce è New Project.... Possiamo premere su quello oppure dal menù File selezionare la voce New e poi nel sottomenù la voce Projet. Le due operazioni sono assolutamente identiche.
Ci compare questa finestra di dialogo
L'unica cosa da fare è metterci un nome significativo nel campo Name, io ho messo blinky e, visto che questo programmino di prova lo scriviamo in C selezioniamo GCC Executable Project. Premiamo il tasto OK ed andiamo avanti.
Ora compare la finestra di dialogo per la scelta del micro. Selezioniamo per comodità la famiglia megaAVR, 8-bit dal menù a tendina Device Family posto in alto. Selezioniamo poi ATmega328P come si vede nella foto.
La cosa simpatica ed utile è che nel lato destro della finestra di dialogo vengono mostrate informazioni sui programmatori ed emulatori utilizzabili con questo micro, ed il sempre onnipresente datasheet. Premiamo il tasto OK e proseguiamo.
Finalmente ci compare l'editor di testi con già uno scheletro di programma scritto.
Non ci resta ora che scrivere il programma e, già che ci siamo, cerchiamo di scriverlo bene, non ostante sia un programmino semplice semplice.
Il programma
Come dicevo prima, il programma è molto semplice e, proprio per questo motivo, lo scriveremo bene. Quale occasione migliore per illustrare le linee guida per una (a mio modesto parere) buona stesura di un programma?
Un programma per un micro (che non utilizza sistemi operativi real time) è formato sostanzialmente da due parti:
- Inizializzazione: Dove viene inizializzato tutto il sistema, e quindi pin di I/O, porte, periferiche varie e queste vengono poi fatte partire correttamente.
- Ciclo infinito di funzionamento. E' il cuore del sistema. In questo ciclo si susseguono diverse chiamate a compiti che vengono eseguiti, all'apparenza, contemporaneamente. Di solito questi compiti implementano macchine a stati perché l'esecuzione non si può fermare dentro uno di essi, un compito non può far aspettare tutti gli altri fino, ad esempio, alla pressione di un pulsante. Devono essere scritti in modo che il flusso di esecuzione li attraversi nel minor tempo possibile. Quando si scrivono individualmente si deve sempre tenere presente che verranno eseguiti di continuo e che non sono permesse fermate o attese.
Avremo quindi, all'inizio del main, la chiama ad una o più funzioni che inizializzano il sistema ed un ciclo che chiama le varie funzioni (o task) che devono essere eseguiti. Nel nostro caso ne abbiamo uno solo, quello che fa lampeggiare il LED ma, in futuro, potremmo aggiungerne altri.
Per realizzare il nostro task di lampeggio del LED non ci serviamo di ritardi fissi, come nel programma blinky per Arduino, perché questi non sono ammessi se non in casi particolarissimi. Ad essere sinceri l'introduzione di ritardi fisso ingiustificato, o giustificato dalla sola pigrizia è un crimine che dovrebbe essere duramente punito.
Per evitare ritardi fissi utilizziamo un interrupt ciclica. In pratica utilizziamo un timer (il timer 1) programmandolo in modo che generi una interrupt ogni tot di tempo, nel nostro caso 10ms. All' interno della funzione di servizio dell'interrupt implementeremo un timer software. Appare ragionevole immaginare di dover scrivere dlelle funzioni per l'inizializzazione del timer, dell'interrupt e per la lettura e scrittura del nostro timer software.
Abbiamo però anche un LED collegato a PB0 quindi è ragionevole immaginare di dover scrivere una funzione per la sua inizializzazione ed alcune funzioni per accenderlo, spegnerlo o farlo commutare. Man mano che proseguiamo le analizzeremo nel dettaglio. Diciamo ora che il nostro programma può avere una struttura del genere:
#include <avr/io.h> #include <avr/interrupt.h> //-------------------------------------------------------------------------- int main(void) { // Inizializza il LED ledInit(); // Inizializza l'interrupt ciclica cyclicIntInit(); // Abilita le interrupt sei(); // Imposta il periodo di lampeggio a 500ms setPeriodoLampeggio(50); // Fa partire l'interrupt ciclica cyclicIntStart(); // Ciclo infinito di funzionamento for(;;) { // Task di lampeggio del LED taskLampeggioLed(); // Altri eventuali task saranno scritti qui sotto // ... } }
Le prime due linee sono delle direttive per includere gli header file che contengono le definizioni degli I/O del micro e le macro e funzioni per l'uso delle interrupt.
Per il resto sembra tutto chiaro: inizializzazione, abilitazione delle interrupt, impostazione del perido di lampeggio, avvio dell'interrupt ciclica e poi il ciclo di funzionamento.
Analizziamo ora i vari "moduli" che compongono il nostro programma. Ho scritto moduli fra virgolette perché dovrebbero essere dei moduli separati, dei file a se stanti, che contengono le funzioni ma, per semplicità, ho messo tutto dentro un file.
Partiamo da quello che riguarda il LED.
//-------------------------------------------------------------------------- // Linea di I/O per il comando del LED // Inizializzazione void ledInit(void) { // Predispone il pin PB0 come uscita DDRB |= 0x01; } // Funzione per l'accensione del LED // Prerequisito: il LED deve essere stato inizializzato void ledOn(void) { PORTB |= 0x01; } // Funzione per lo spegnimento del LED // Prerequisito: il LED deve essere stato inizializzato void ledOff(void) { PORTB &= 0xFE; } // Funzione per la commutazione dello stato del LED // Se acceso si spegne e vice versa // Prerequisito: il LED deve essere stato inizializzato void ledToggle(void) { PORTB ^= 0x01; }
Questo modo di scrivere i programmi permette di implementare la cosiddetta astrazione hardware. L'idea è quella di non agire direttamente sui pin del micro ma passare attraverso delle funzioni. Il perché di questa apparente complicazione è semplice: se un domani il LED dovrà essere collegato ad un altro pin del micro ci basterà cambiare o modificare queste funzioni senza dover metter mano a tutto il programma e, credetemi, se il programma è grande è una gran comodità. Addirittura se un domani avessimo un display LCD con un LED disegnato sopra avremo sempre le stesse funzioni. Ed ecco perché questa parte di programma dovrebbe essere all'interno di un modulo, il cosiddetto HAL che vuol dire Hardware Abstraction Layer. L'utilizzo dei moduli permette di ottenere in C quello che nella programmazione ad oggetti viene chiamato incapsulamento: si lasciano visibili solo le informazioni utili per l'uso del modulo e si nasconde la sua implementazione. Ricapitolando abbiamo le seguenti funzioni:
- void ledInit(void) per inizializzare l'hardware del LED
- void ledOn(void) per accendere il LED
- void ledOff(void) per spegnerlo
- void ledToggle(void) per frgli cambiare stato
Del resto non ci dovremo più preoccupare
Ora prendiamo in considerazione il modulo per la gestione dell'interrupt ciclica e dei timer software
//-------------------------------------------------------------------------- // Interrupt ciclica e gestione dei timer software // Variabile utilizzata come timer software volatile uint16_t softTimer1; // Inizializzazione del Timer 1 per timeout 10 ms. void cyclicIntInit(void) { // Carica il registro di comparazione per ottenere 10ms OCR1A = 3125; // Abilita output compare A match TIMSK1 = (1<<OCIE1A)|(0<<TOIE1); // Predispone il prescaler 1/8 modo operativo Clear Top Count // Seleziona nessun ingresso di clock = timer fermo TCCR1B = (0<<WGM13)|(1<<WGM12); softTimer1 = 0; } // Funzione per far partire l'interrupt ciclica // Prerequisito: l'interrupt ciclica deve essere stata inizializzata void cyclicIntStart(void) { TCCR1B |= (0<<CS12)|(1<<CS11)|(1<<CS10); } // Funzione per far fermare l'interrupt ciclica void cyclicIntStop(void) { TCCR1B &= 0xF8; // CS12 = CS11 = CS10 = 0 } // Routine di servizio chiamata quando il contenuto del comparatore A // corrisponde al valore del timer. Quando raggiunge tale valore il // timer viene resettato e viene invocata questa routine. ISR(TIMER1_COMPA_vect) { if(softTimer1) softTimer1--; } // Funzione per la scrittura del timer software // val : unità da 10 ms void setTimer1(uint16_t val) { softTimer1 = val; } // Funzione per la lettura del timer software // Ritorno : contenuto del timer in unità da 10ms uint16_t getTimer1(void) { return softTimer1; }
Anche qui solito sistema che non descriverò nel dettaglio, in fondo si tratta di prendere il datasheet ed andarsi a leggere quello che riguarda il timer1 e come farlo funzionare. Una cosa degna di nota è la dichiarazione della variabile che useremo per l'implementazione del timer software, e cioè
volatile uint16_t softTimer1;
Questa variabile è visibile a tutto il programma e questa non è una bella cosa, ma se fosse stata dichiarata in questo modo all'interno di un modulo, non sarebbe visibile al di fuori di esso. E' a tutti gli effetti una sorta di contatore all'indietro ma noi vi vi accediamo direttamente (anche se verrebbe la tentazione di farlo) ma attraverso due semplici funzioni (che potremmo anche dichiararle inline) e che sono:
- void setTimer1(uint16_t val) per impostare un valore nel timer
- uint16_t getTimer1(void) per leggerne il valore
Il perché di questa scelta è lo stesso di quello che valeva per i LED. Oggi il nostro timer software è una semplice variabile ma, un domani, potrebbe essere un circuito esterno collegato al micro che non conosciamo ancora. In tal caso basterà riscrivere solo queste due funzioni senza toccare il resto del programma.
Abbiamo poi le funzioni per la gestione dell'interupt ciclica
- void cyclicIntInit(void) Per inizializzare tutto l'ambaradan
- void cyclicIntStart(void) Per farla partire
- void cyclicIntStop(void) Per fermarla qualora ce ne fosse bisogno
La funzione di servizio dell'interrupt è quella che fa il vero e proprio lavoro: viene chiamata ogni 10ms e, se la variabile timer non è a 0 la decrementa.
Passiamo ora a vedere le funzioni che realizzano il task del lampeggio del LED
//-------------------------------------------------------------------------- // Task per far lampeggiare il LED uint16_t periodoLampeggio; void taskLampeggioLed(void) { if (!getTimer1()) { // Commuta lo stato del LED ledToggle(); // Carica il timer software per intervallo 500ms. setTimer1(periodoLampeggio); } } // Funzione per impostare il periodo del lampeggio in unità di 10ms void setPeriodoLampeggio(uint16_t tempo) { periodoLampeggio = tempo; }
Beh, c'è poco da dire. Per rendere il programma più flessibile ho scritto la funzione setPeriodoLampeggio per impostare il periodo del lampeggio. In questo modo la funzione che esegue il task non è da toccare nel caso decidessi di far lampeggiare il LED ad una velocità diversa.
Una certa attenzione va data invece alla funzione taskLampeggioLed. Questa viene chiamata ripetutamente nel ciclo infinito di funzionamento. Notare bene che non aspetta lo scadere del tempo, semplicemente fa qualcosa solo quando il tempo è scaduto, altrimenti esce subito e permette l'esecuzione di altri task. Che ovviamente faranno lo stesso, interverranno solo se è il caso di farlo.
Ma tutto questo casino solo per far lampeggiare un LED? Ovviamente no, per far solo lampeggiare un LED non serve tutto questo ambaradan, ma un programma scritto in questo modo è un programma decente. E' palese che ho abbondato di commenti ed ho scritto tutto molto modulare, perché questo è un modo accettabile per scrivere buoni programmi per microcontrollori.
E iniziare subito con il piede giusto potrebbe essere una buona cosa.
A questo link è possibile scaricare il file blinky.c
La compilazione e la verifica
La compilazione non è un qualcosa che dà molta soddisfazione. Si preme il tasto F7, si aspetta un po' di tempo che il compilatore compili il progetto fino alla comparsa della fatidica scritta
Build succeeded. ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
Per poi scaricarlo nella scheda è sufficiente selezionare USBasp ATmega328P nel menù Tools ed in un batter d'occhio vedremo il nostro LED lampeggiare.
Conclusioni
Beh, prima o poi avrei dovuto affrontare l'argomento Arduino. Ho voluto farlo a modo mio analizzando l'oggetto e cercando alternative più interessanti ed economiche.
Allo stesso tempo spero di aver stimolato qualche arduinista a fare "il salto" per passare ad usare i microcntrollori nel modo canonico, in un modo sicuramente più complicato ma più evoluto, ma non mi faccio illusioni.
Quello che invece mi interessa è aver dato un po' di informazioni in grado di stimolare la creatività di molti che non vedono l'ora di trafficare con l'elettronica. In questo articolo ed in quelli collegati si possono trovare spunti di ricerca e sperimentazione.
Quindi che dire se non BUONA SPERIMENTAZIONE!