STEM Shield: per l’educazione STEM e la sperimentazione con Arduino

Una board di sperimentazione delle capacità delle schede Arduino, ricca di periferiche specifiche per il mondo Educational.

In questa sezione Progetti di Futuranet abbiamo più volte ospitato, da quando il progetto Arduino è nato, articoli didattici finalizzati a insegnare la programmazione e l’utilizzo dei microcontrollori Atmel, ma anche tanto hardware di supporto sotto forma di svariati shield, ovvero di schede di espansione del microcontrollore Atmel ATmega nate per interfacciarlo con il mondo esterno, allo scopo di controllare dispositivi o acquisire segnali e dati.

Molti degli shield proposti sono stati dedicati a specifiche applicazioni, ma ne esistono anche altri generici, nati per la sperimentazione e la didattica, il cui più essenziale esponente è il protoshield, costituito solamente dagli header e da piste e piazzole per montare ogni genere di componente.

Quello che vi proponiamo in questo post è, invece, uno shield nato specificamente per rientrare nell’ambito dei programmi scolastici STEM (Science, Technology, Engineering and Mathematics) quindi risponde a una serie di direttive che vedono il mondo Arduino integrato nella scuola.

Essendo un prodotto pensato per la sperimentazione, è di fatto un insieme di periferiche e dispositivi elementari che a seconda dell’esperimento da condurre possono essere inseriti o disinseriti e connessi a uno o più pin di Arduino in base alla necessità del momento; possiamo quindi dire che lo shield è un “mucchietto” …un paniere di hardware elementare che possiamo utilizzare al bisogno o anche solo per testare qualche sketch dimostrativo.

Il progetto è quindi l’ideale per imparare a programmare i microcontrollori, perché permette di verificare immediatamente il funzionamento di piccoli sketch per la gestione dell’accensione di LED, la generazione di suoni o il gioco elettronico, l’acquisizione di tensioni analogiche e la lettura di temperature, oltre a tanto altro.

Lo shield, chiamato STEM Shield in virtù del suo orientamento ai programmi didattici rientranti nel concetto omonimo, ha un form factor idoneo ad essere applicato alla scheda Arduino Uno e simili, nonché alla Arduino Mega; può quindi essere applicato alle nostre board Fishino, le quali, come ormai saprete, sono compatibili ed anche migliorate.

Non va invece bene per l’applicazione diretta sulle più piccole Arduino e Fishino, come le Micro e Nano, ma è idoneo alle schede a 32 bit, come la Fishino 32.

Schema elettrico dello STEM shield

Bene, dopo questo preambolo possiamo andare alla sostanza del progetto e analizzare l’hardware a partire dallo schema elettrico; prima, però, diamo uno sguardo al layout dello shield proposto nella Fig. 1. In esso vediamo che lo shield è composto da un corpo principale ed un’estensione composta da due parti separabili laddove non servissero o andassero dislocate lontano; l’hardware nel complesso è composto da:
• sensore di temperatura;
• display 7-segmenti;
• 6 LED simulatori di semaforo;
• 4 pulsanti;
• 1 switch a slitta;
• 1 trimmer;
• 1 cicalino;
• 1 connettore per servo;
• 1 fototransistor all’infrarosso;
• 1 LED all’infrarosso.

Fig. 1 Topografico dello shield con evidenziate le parti rilevanti e il tratteggio lungo cui si separa l’inseguitore di linea.

 

Nella sezione staccabile della scheda sono collocati il display (in una metà) e il LED e il fototransistor all’infrarosso (nell’altra) con i quali potete realizzare un sensore di prossimità o un inseguitore di linea (LINE TRACKER), molto apprezzato nelle applicazioni robotiche; non a caso questa parte è staccabile, perché così potete collocarla dove serve: ad esempio nella parte bassa di un robot su ruote. Il resto si trova sullo shield base.

Il simulatore di semaforo è formato da sei LED disposti a terne, ognuna composta da un diodo rosso, uno verde e uno giallo; i pulsanti e il deviatore a slitta servono come dispositivi di input per impartire comandi, mentre i LED possono comunque essere utilizzati disgiuntamente per fornire segnalazioni, al pari del display a LED 7-segmenti che di trova sulla parte staccabile. Il trimmer consente di testare l’ADC, ovvero di impostare soglie e valori analogici; i jumper ON/OFF servono ad abilitare/disattivare alcuni blocchi dello shield. Il sensore di temperatura è un termistore NTC montato a bordo della scheda.

Dopo questo riepilogo, guardiamo e analizziamo lo schema elettrico, che è realizzato intorno ai connettori standard per gli header Arduino.

Partiamo dai pulsanti, ognuno dei quali è del tipo normalmente aperto ed è collegato da un estremo al positivo di alimentazione terminante sulla linea 5V di Arduino e dall’altro a una linea di Arduino attraverso un jumper che permette di collegarlo e escluderlo, allo scopo di lasciare utilizzare i corrispondenti pin degli header; ciascuna linea di quelle assegnate da SW2÷SW5 è dotata di un resistore di pull-down che tiene a massa l’estremo del rispettivo pulsante.

I jumper di inserzione dei pulsanti sono quattro, siglati SH10÷SH13, ossia tanti quanto i pulsanti stessi; con i jumper chiusi ed SH10 a D2. SH11 è collegato a D11 di Arduino, SH12 a D10, SH13 a D9.
Il deviatore viene invece utilizzato come interruttore (un estremo e il centrale sono tra loro cortocircuitati) collegato con l’estremo libero al positivo 5V e il cursore (terminato a massa tramite il resistore di pull-down R18, da 100 kohm) collegato, tramite il jumper SH14, alla linea D8 dell’header Arduino.

Passiamo adesso al cicalino piezoelettrico, che è del tipo senza elettronica e può quindi essere pilotato con segnali di varia frequenza, anche PWM, per fornire semplici note acustiche o suonare brani musicali; il suo polo negativo è fisso a massa, mentre il positivo viene collegato, tramite la resistenza limitatrice della corrente, R16, al pin header D13, tramite il jumper SH9.

Il display 7-segmenti a LED è del tipo ad anodo comune e nel circuito è collegato con l’anodo al positivo 5V di Arduino e i catodi dei 7 segmenti e del punto decimale collegati, tramite jumper a due vie, alle linee A3, A4, D2, D3, D4, D5, D6, D7, cui corrispondono rispettivamente i segmenti A, B, C, D, E, F, G, DP (punto decimale o DOT); i ponticelli sono a due vie perché permettono sia di collegare/scollegare i catodi relativi ai segmenti del display, sia, in opzione, a connettere/sconnettere la linea del servo e i catodi dei 6 LED. Tale soluzione è stata voluta perché i pin di Arduino non sono abbastanza, almeno nella versione Uno, da comandare individualmente tutti i componenti a bordo dello shield; dunque, A3, A4 e D2÷D7 sono condivisi tra il display e il servo, i LED rossi, verdi, gialli, e il LED IR montato sulla sezione staccabile dello shield.

I jumper interessati sono da SH1 a SH8 per i segmenti dall’A al punto (DOT) del display; da SH1 a SH6 commutano i LED a luce visibile, SH7 commuta il LED IR ed SH8 il canale di segnale del connettore per il servocomando.

Passiamo adesso alla sezione “sensoristica” con il trimmer, che è collegato con gli estremi all’alimentazione a 5 volt proveniente da Arduino (5V/GND) e il cursore al pin A0 (analogico, giacché dev’essere letto dall’A/D converter) tramite il jumper SH15, che consente di “liberare” A0 laddove serva per altri utilizzi, senza per forza dover rimuovere lo shield, ad esempio perché potrebbe essere necessario mantenere alcune periferiche a bordo dello stesso.

La tensione che raggiunge A0 cresce portando il cursore del trimmer verso il 5V e decresce, fino ad annullarsi, ruotandolo verso GND.

Il termistore NTC che fa da sensore di temperatura è collegato a partitore con la resistenza R17 ed il partitore è alimentato con i 5 volt; il punto di unione dei due resistori si collega alla linea A1 (analogica anch’essa e quindi letta dall’ADC) tramite il ponticello SH16 (che permette di liberare il pin di Arduino); al crescere della temperatura la tensione letta diminuisce, mentre cresce al calare della temperatura. Il range è tra circa 1 e 4 volt, ma può variare in base ai valori resistivi che il termistore utilizzato assume in corrispondenza della minima e massima temperatura cui può essere sottoposto.

Chiudiamo la descrizione dello schema elettrico con il fototransistor siglato P1, che è incapsulato in un contenitore in resina trasparente tipo LED, dotato di due soli piedini che portano all’esterno il collettore e l’emettitore; la base è isolata perché poco rilevante, almeno fin quando il componente non deve trovarsi a commutare dall’interdizione alla conduzione troppo velocemente (allorché la ricombinazione delle cariche nella base rallenterebbe la commutazione).

Il fototransistor lavora nella configurazione a emitter-follower ed ha il collettore alimentato dai soliti 5 volt e l’emettitore collegato a massa tramite l’apposito resistore (R1) nonché alla linea analogica A2 di Arduino, attraverso l’immancabile jumper (in questo caso è SH17).

Il fototransistor viene impiegato in questa configurazione perché consente di ottenere un segnale analogo al livello di illuminazione ricevuta dalla base, il che è utile proprio per le applicazioni in cui serva determinare il grado di riflessione della luce del LED IR1, come ad esempio nella ricerca di una linea segnata a terra; per questo il segnale sull’emettitore viene letto da una linea di Arduino assegnabile all’ADC interno.

Piano di montaggio

Elenco componenti

RV1: Trimmer 100 kohm MO
SW1: Deviatore a slitta 90°
SW2÷SW5: Microswitch 90°
LD1, LD4: LED 3 mm rosso
LD2, LD5: LED 3 mm giallo
LD3, LD6: LED 3 mm verde
NTC1: NTC 100 kohm
SEG1: Display 7 segmenti anodo comune
IR1: LED IR 3 mm
P1: Fototransistor 3 mm
Buzzer: Buzzer

Varie:
- Strip mschio 3 vie (9 pz.)
- Strip maschio 2 vie (9 pz.)
- Jumper (17 pz.)
- Strip M/F 6 vie 
- Strip M/F 8 vie (2 pz.)
- Strip M/F 10 vie 
- Circuito stampato (87 x 54 mm)

 

Fig. 2 La parte separabile va connessa allo shield base collegando le piazzole affacciate sui bordi, anche se rimane attaccata.

Un po’ di esercizio

Bene, siccome lo shield nasce per fare esercitazioni e sperimentare come si utilizzano le periferiche, vediamo adesso qualche semplice sketch d’esempio che permette di gestire alcuni dei componenti a bordo; gli esempi che seguono sono riferiti ad Arduino Uno, tuttavia modificando la definizione dei pin potete adattarli anche ad altre board.

Il primo ci permette di accendere e spegnere in sequenza i LED LD4, LD5, LD6 (rispettivamente rosso, giallo e verde) a una velocità predefinita e ciclicamente.

Per prima cosa bisogna definire gli I/O di Arduino che userete per alimentare i LED e impostarli come uscite, quindi costruire il loop che attiva le tre porte digitali in uscita.

Lo sketch è riportato nel Listato 1, dove utilizziamo una struttura di setup e infine mettiamo la struttura che viene eseguita come programma e ripetuta all’infinito (void loop()). Nel setup definiamo le istruzioni pinMode (pin, modo), che servono, prima di utilizzare i pin digitali, a definire per ciascuno se sono nel modo INPUT o OUTPUT. Se non li definiamo con l’istruzione pinMode, questi restano in uno stato ad alta impedenza e quindi inattivi.
Il primo passaggio consiste nel definire i pin utilizzati, operazione, che comunica ad Arduino a quali contatti digitali corrispondono le variabili: stabiliamo che led1 corrisponde al piedino 3 (LD4), led2 al 4 (LD5) e led3 al 5 (LD6).

Listato 1

/*
Gestione uscite di Arduino per accendere in sequenza tre LED
*/
// definizione dei pin
int led1 = 3;
int led2 = 4;
int led3 = 5;
void setup() {
  // impostazione dei pin come uscite
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
}
void loop() {
  digitalWrite(led1, HIGH); // accendi il led
  delay(1000); // aspetta un secondo
  digitalWrite(led1, LOW); // spegni il led
  delay(1000); // aspetta un secondo
  digitalWrite(led2, HIGH); // accendi il led
  delay(1000); // aspetta un secondo
  digitalWrite(led2, LOW); // spegni il led
  delay(1000); // aspetta un secondo
  digitalWrite(led3, HIGH); // accendi il led
  delay(1000); // aspetta un secondo
  digitalWrite(led3, LOW); // spegni il led
  delay(1000); // aspetta un secondo
}

L’istruzione pinMode nel setup dev’essere impartita contenendo il nome della variabile, quindi la modalità: per esempio pinMode(led1, OUTPUT) significa che led1, assegnata in fase di definizione al contatto 11 di Arduino, diverrà un’uscita.

Segue la creazione del loop, ovvero del ciclo che vedrà l’avvicendarsi delle istruzioni di assegnazione dei livelli logici ai piedini specificati; queste istruzioni sono digitalWrite e delay: la prima assegna il livello logico al piedino di uscita digitale e la seconda stabilisce il tempo che deve trascorrere prima di passare alla successiva.

Ne deriva che essendo delay il tempo che passa dall’esecuzione di un’istruzione e la successiva e che, essendo le istruzioni in sequenza, ogni stato logico dura il tempo assegnato come parametro a delay. Nel nostro caso il ciclo sarà composto da un’istruzione digitalWrite che assegna lo stato logico alto a una linea, poi da un delay, quindi da una nuova digitalWrite che assegna lo stato basso; il tutto moltiplicato per tre, ovvero la prima volta per led1, la seconda per led2 e la terza per led3, poi il ciclo ricomincia.

Quanto alle istruzioni coinvolte, ricordiamo che la sintassi di digitalWrite è digitalWrite(pin, livello) dove al posto di pin mettete il nome assegnato nella definizione dei pin (per esempio led1) e al posto di livello scrivete se deve assumere LOW o HIGH (sono parole riservate). Ricordate che “pin” può essere una variabile. Per l’istruzione delay, la sintassi prevede invece di specificare tra parentesi il ritardo in millisecondi.
Affinché l’applicazione funzioni, sullo shield i jumper SH4, SH5 ed SH6 dovranno essere chiusi sui LED corrispondenti.

10 note e un trimmer
Passiamo a un secondo esempio dove ci proponiamo di far riprodurre al cicalino (BUZZER) 10 note acustiche la cui frequenza dipende dalla posizione del cursore del trimmer: per prima cosa dobbiamo definire i piedini di ingresso e uscita, che in questo caso sono l’ingresso analogico A0 (per questo dovete chiudere il jumper SH15 che collega ad A0 il cursore dell’RV1) e l’uscita digitale 13, che è quella assegnata al cicalino (allo scopo dovete chiudere il jumper SH9).

Per generare le note utilizziamo un output digitale che produce impulsi alla frequenza corrispondente a quella delle note. Arduino dovrà per prima cosa leggere il valore di tensione portato da esso ad A0; quest’ultimo verrà letto dall’A/D converter.

Con riferimento al Listato 2, che riporta il codice, la definizione dei pin è:
int buzzer = 13;
int trimmer = A0.

Poi definiamo le variabili:
int numNote = 10;
int note[] = {261, 277, 294, 311, 330, 349, 370, 392, 415, 440};
int valoreletto = 0;
int notascelta = 0;

Listato 2

/*
Come riprodurre tramite delle note in base al valore letto da un trimmer
*/

// definizione dei pin
int buzzer = 13;
int trimmer = A0;

// definizione variabili
int numNote = 10;
int note[] = {
  261,
  277,
  294,
  311,
  330,
  349,
  370,
  392,
  415,
  440
}; //array frequenze delle note da riprodurre
int valoreletto = 0;
int notascelta = 0;

void setup() {
  for (int i = 0; i & lt; numNote; i++) //finché la variabile i non è uguale a numNote, incrementala
  {
    tone(buzzer, note[i]); //genera sul pin buzzer una frequenza pari al contenuto 
    //della variabile note[i]
    delay(200); //aspetta 200ms
  }
  noTone(buzzer); //disabilita l’uscita
}

void loop() {
  valoreletto = analogRead(trimmer); //leggi il trimmer
  notascelta = map(valoreletto, 0, 1023, 0, 10); //scala il valore letto 
  if (notascelta == 10) { //se la nota da riprodurre è la 10 (l’array va da 0 a 9) 
    noTone(buzzer); //spegni il buzzer
  } else //altrimenti
  {
    tone(buzzer, note[notascelta]); //esegui la nota
  }
  delay(200); //aspetta 200ms
}

 

“numNote” corrisponde al numero della nota da suonare, int note[] è un array contenente la frequenza delle note da riprodurre, mentre “valoreletto” è la lettura dell’A/D converter e “notascelta” la nota da suonare.

L’array permette di alleggerire il codice e quindi risparmiare spazio nella memoria di programma del microcontrollore di Arduino, sostituendo la quantità di istruzioni che servono a suonare le note (o comunque a fare uscire da un certo pin digitale di Arduino Uno una frequenza) con una sola int note[] che contenga di volta in volta tra le parentesi quadre il numero della frequenza da riprodurre. Utilizzando l’array possiamo usare un unico ciclo di for che viene ripetuto le volte che serve, semplicemente sostituendo il parametro dell’istruzione, invece di tanti cicli di for quante sono le note.

Ogni nota viene definita dalla posizione in cui è stata specificata nell’array, quindi int note[0] significa che viene resa disponibile in output (pin12) la frequenza di 261 Hz, int note[1] che viene riprodotta la frequenza di 277 Hz e così via; int note[9] corrisponde a 440 Hz. Detto questo, andiamo alla definizione del setup: la sintassi di for che utilizziamo è:

for (int i = 0; i < numNote; i++)

indicante che la variabile “i” deve essere incrementata fino a raggiungere il valore della variabile numNote. L’apertura di una nuova parentesi graffa indica che nel ciclo for viene eseguito il comando tone(buzzer, note[i]), il quale fa generare un segnale di frequenza pari al contenuto della variabile note[i], dopodiché si aspetta un periodo di 0,2 secondi (200 ms) prima di eseguire altre istruzioni (delay(200)) e successivamente viene sospesa la generazione del segnale (istruzione noTone(buzzer)).

Nella sintassi del comando tone inseriamo la linea di Arduino sulla quale mandare la frequenza generata (in questo caso specifichiamo buzzer) e la frequenza, che nello specifico è funzione della variabile note, la quale a sua volta dipende da i.

Dopo il setup abbiamo il loop che verrà eseguito dallo sketch: dato che l’elemento da cui dipende la generazione dei suoni è la variabile (valoreletto) ricavata dalla posizione del cursore del potenziometro, per prima cosa il firmware deve acquisire la tensione su A0; ciò viene ottenuto con l’istruzione analogRead(trimmer).

Subito dopo viene eseguita l’istruzione che divide l’intera lettura dell’A/D converter in dieci passi: questo permette di dividere idealmente la corsa del potenziometro slider in dieci porzioni, ognuna delle quali corrisponde a far suonare una certa nota. Il campo dell’intera corsa è, lo ricordiamo, circa 2,5 volt, diviso in 1.024 porzioni (da 0 a 1.023) all’uscita dell’A/D onverter e a sua volta diviso in 10 dal programma. La ripartizione viene eseguita tramite la funzione map (valoreletto, 0, 1023, 0, 10); la parte tra parentesi dell’istruzione map indica che valoreletto, il cui campo è compreso tra 0 e 1.023, deve essere ricondotto a un valore tra 0 e 10 (11 valori). La funzione permette di rimappare i valori adeguando la risoluzione a 10 bit ai passi richiesti dalla nostra applicazione, sia essa una lettura o una scrittura; nel nostro caso ci permette di adattare la scala dell’ADC ai 10 passi desiderati, ma si potrebbe utilizzare, ad esempio per un’uscita PWM, per trasformare in un valore differente i 255 passi in cui è divisa la variazione 0÷100% del duty-cycle.

La sintassi generale è: map(variabile, daMin, daMAX, aMin, aMAX). Con essa, il valore della variabile viene convertito dal suo intervallo originario (0, 1.023) i cui valori minimo e massimo sono definiti con daMin e daMAX, a quello di destinazione definito con aMin e aMAX ai due estremi. Si tratta di calcoli effettuati in matematica intera e quindi si applica l’arrotondamento per troncatura dei decimali.

Andiamo oltre e vediamo che dopo la funzione, nello sketch viene eseguita una struttura if/else, per cui se la nota da riprodurre è oltre la 9 (frequenza più alta) si spegne (livello logico zero) il pin 13, altrimenti si esegue l’istruzione tone(buzzer, note[notascelta]) per suonare la nota corrispondente a valoreletto. Dopo i soliti 200 ms (delay(200)) si torna a leggere il valore della tensione fornita dal potenziometro. Notate che il delay così basso (appena 0,2 secondi) è stato voluto per fare in modo che il circuito possa rispondere molto rapidamente alle variazioni di posizione del cursore del trimmer e quindi suonare troppo velocemente.

Notate anche che abbiamo voluto dividere la corsa in un passo in più delle note da suonare per consentirvi di disinserire il tono acustico; infatti per ogni posizione del cursore il circuito suona la nota corrispondente, quindi serve una posizione di spento. Tale posizione corrisponde ad avere il cursore del potenziometro tutto verso l’estremo collegato al positivo 5V (valore 1.023).

L’ultimo esercizio che vi proponiamo coinvolge i pulsanti e consiste semplicemente nel far accendere il LED LD4 quando si preme SW2. Il codice corrispondente è nel Listato 3, dove inizialmente impostiamo il pulsante e l’uscita digitale del LED, quindi dopo la fase di setup (dove stabiliamo quali sono i pin di uscita e d’ingresso utilizzati) avviamo il loop, ossia il ciclo per gestire lo stato delle uscite sulla base di quello dei pulsanti; semplicemente, se la linea D9 di Arduino è allo stato 1 il LED viene acceso. Il delay (500) viene inserito come antiirimbalzo, per evitare false commutazioni. Rilasciando SW2 (if (digitalRead(button)==0)) il LED torna spento; a ciò provvede l’istruzione digitalWrite(led1, LOW) seguita dall’immancabile delay per l’antirimbalzo.

Listato 3

/*
Leggere gli ingressi digitali e accendere un LED.
*/

// definizione dei pin
int led1 = 3;
int button = 9;

void setup() {
  // impostazione pin come uscita
  pinMode(led1, OUTPUT);

  // impostazione pin come ingresso
  pinMode(button, INPUT);
}

void loop() {

  if (digitalRead(button) == 1) { //se il pulsante è premuto
    digitalWrite(led1, HIGH); // accende il led
  }
  delay(500); // pausa per antirimbalzo 
}
if (digitalRead(button) == 0) { //se il pulsante è rilasciato
  digitalWrite(led1, LOW); // spegne il led
}
delay(500); // pausa per antirimbalzo 
}

Conclusioni

Bene, con questo abbiamo terminato; naturalmente le esercitazioni non si limitano a quelle qui proposte e sul web ne potrete trovare tante altre che utilizzano tutte le periferiche a bordo del nostro shield.
Buona sperimentazione!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Menu