Questa sezione descrive i progetti che realizzeremo con Arduino. Per ognuno troveremo una scheda con lo scopo del progetto e il materiale necessario, il circuito e lo sketch.
Per realizzare i circuiti useremo le baseboard in dotazione al laboratorio 12 collegando la scheda arduino con l'apposito plug. Con questa soluzione i pin della scheda Arduino non sono più accessibili ma vengono replicati sulla baseboard secondo questo schema.
Scopo | fare lampeggiare il LED collegato al pin 13 presente sulla scheda Arduino |
---|---|
Componenti | in questo progetto non servono breadboard e componenti |
/* * Progetto 1 * Accende e spegne il LED ogni secondo * Nome Studente: * Creato il: data */ // Il pin collegato al LED int led = 13; // impostiamo la scheda void setup() { // impostiamo il pin come OUTPUT pinMode(led, OUTPUT); } // il programma vero e proprio che viene ripetuto ciclicamente void loop() { digitalWrite(led, HIGH); // accende il LED (HIGH -> 5 Volt sul pin) delay(1000); // attende un secondo (1000 millisecondi) digitalWrite(led, LOW); // spegne il LED (LOW -> 0 Volt sul pin) delay(1000); // attende un secondo (1000 millisecondi) }
setup()
e la funzione loop()
Scopo | fare lampeggiare un LED |
---|---|
Componenti | LED, resistore da 220Ω |
Il LED (light emitting diode) è un particolare tipo di diodo che emette luce quando attraversato da corrente. Il suo comportamento nei circuiti elettrici non è da confondere con quello di una lampadina, infatti:
Lo sketch è uguale al precedente ma possiamo scegliere uno qualunque dei pin digitali (nello schema elettrico è utilizzato il pin 9).
Scopo | accendere un LED con la pressione di un pulsante |
---|---|
Componenti | LED, resistori da 100Ω 220Ω e 10kΩ, pulsante NO |
Il pulsante è in grado di aprire e chiudere un circuito come un interruttore ma presenta una sola posizione stabile:
L'apertura o chiusura automatica avviene grazie a un meccanismo a molla che riporta i contatti nella posizione predefinita. Questa soluzione meccanica può causare dei problemi perché la molla tende a far rimbalzare i contatti e il passaggio da aperto a chiuso e viceversa può non essere netto. Lo stesso tipo di problema si presenta anche negli interruttori e viene risolto con i circuiti antirimbalzo (ce ne occuperemo l'anno prossimo).
/* * Progetto 3: * Accende un LED con la pressione di un pulsante * Nome studente: * Creato il: data */ // pin utilizzati per accendere il LED e leggere lo stato del pulsante int led = 9; int pulsante = 3; // impostiamo i due pin digitali come output e input void setup() { pinMode(led, OUTPUT); pinMode(pulsante, INPUT); } void loop() { if(digitalRead(pulsante) == HIGH) { // se è premuto il pulsante digitalWrite(led, HIGH); // accende il LED } else { digitalWrite(led, LOW); // altrimenti spegne il LED } }
HIGH
) dell'alimentazione, quando non è premuto è collegato a massa attraverso la resistenza (LOW
) come mostrato in figuraE' possibile accendere e spegnere alternativamente il LED ad ogni pressione del tasto. Per far questo occorre modificare lo sketch in questo modo:
statoPulsante
e utlimoStatoPulsante
per memorizzare lo stato del pulsante e lo stato immediatamente precedente; se i due valori sono diversi significa che il bottone è stato premuto o rilasciatostatoLed
per tenere conto dello stato del LED (0
corrisponde a spento e 1
ad acceso); quando viene premuto il pulsante modifichiamo il valore di questa variabilestatoLed
di conseguenzastatoLed
di conseguenzaultimoStatoPulsante
NB questa modifica metterà in evidenza il problema del rimbalzo dei contatti.
/* * Progetto 3 - variante * Commutare un LED tra acceso e spento con la pressione di pulsante * Nome studente: * Creato il: data */ // pin collegati al LED e al pulsante int led = 9; int pulsante = 3; // valore attuale e precedente sul pin collegato al pulsante int statoPulsante; int ultimoStatoPulsante; // stato del LED (0 = spento, 1 = acceso) int statoLed = 0; void setup() { // impostiamo il pin del LED come uscita pinMode(led, OUTPUT); // impostiamo il pin del pulsante come ingresso pinMode(pulsante, INPUT); // valore iniziale sul pin del pulsante ultimoStatoPulsante = digitalRead(pulsante); } void loop() { // leggo il valore sul pin del pulsante statoPulsante = digitalRead(pulsante); // se il valore è cambiato rispetto al precedente vuol dire // che il pulsante è stato premuto o rilasciato if(statoPulsante != ultimoStatoPulsante) { // se il pulsante è stato premuto commuta tra acceso e spento // (se è stato rilasciato non succede niente) if(statoPulsante == HIGH) { // se il LED era spento lo accende if (statoLed == 0) { digitalWrite(led, HIGH); statoLed = 1; } // se il LED era acceso lo spenge else { digitalWrite(led, LOW); statoLed = 0; } } } // aggiorna ultimoStatoPulsante ultimoStatoPulsante = statoPulsante; }
Scopo | leggere un valore da un pin analogico e trasmetterlo al PC tramite seriale |
---|---|
Componenti | potenziometro da 10kΩ |
Il potenziometro è un componente a tre morsetti costituito da un resistore con una presa centrale mobile comandata da una manopola (o una vite o un cursore). Tra il morsetto centrale e gli altri due è possibile ottenere un valore di resistenza a piacere compreso tra zero e il valore del resistore. Solitamente i potenziometri sono usati per regolare la tensione come nell'esempio in figura:
La tensione applicata tra i morsetti 1 e 3 viene suddivisa in base alla posizione del contatto mobile 2 e il tratto compreso tra il contatto mobile 2 e il morsetto 3 sarà sottoposto a una tensione proporzionale alla sua resistenza. Spostando il contatto 2 è possibile variare la resistenza e di conseguenza regolare la tensione tra 0 e 5 Volt.
/* * Progetto 4: * Legge un valore di tensione su un pin analogico e lo trasmette * al PC con una comunicazione seriale attraverso la porta USB * Nome studente: * Creato il: data */ // pin analogico utilizzato int potenziometro = 0; // valore analogico (da 0 a 1023) int valore = 0; // stabiliamo una comunicazione seriale con velocità 9600 baud void setup() { Serial.begin(9600); } void loop() { // leggiamo il valore analogico valore = analogRead(potenziometro); // inviamo il valore al PC Serial.print("La tensione sul pin analogico è "); Serial.print(valore); Serial.println(" milliVolt"); // piccola pausa delay(200); }
TX
(trasmissione) e RX
(ricezione)Serial.print(valore);
trasmette un valore sulla seriale senza andare a capo al termine; Serial.println(valore);
fa la stessa cosa ma andando a capo ogni volta (per approfondire vedi la pagina nella guida di riferimentoScopo | accendere in sequenza un gruppo di LED creando un effetto “rimbalzo” |
---|---|
Componenti | 5 LED, resistori da 180Ω |
Un array è un insieme di variabili dello stesso tipo a cui diamo un unico nome. Per accedere ai vari valori si usa un indice che identifica la variabile corrisondente. In definitiva possiamo pensare agli array come a dei contenitori (un solo nome) con tanti elementi a cui possiamo accedere usando un indice.
Un array può essere dichiarato (e inizializzato) in questi modi:
int contenitore[5]; // specificando la dimensione (array di 5 elementi) int pin[] = {2, 4, 8, 3, 6}; // senza dimensione ma indicando i singoli elementi int voti[6] = {2, 4, 8, 5, 7}; // indicando dimensione e inizializzando alcuni elementi
Per accedere a un elemento di un array si usa un indice - che parte sempre da zero - tra parentesi quadre:
contenitore[0] = 2; // assegna il valore 2 al primo elemento dell'array digitalWrite(pin[2], HIGH); // imposta alto il *terzo* elemento dell'array voti[6] = 10; // è un errore!!! se l'array contiene 6 elementi l'ultimo è voti[5]
L'errore nell'esempio precedente è piuttosto comune e difficile da individuare; va evitato assolutamente perché così facendo si scrive un valore in una parte della memoria che non appartiene all'array causando il malfunzionamento del programma.
Solitamente per accedere in sequenza agli elementi di un array si usa un ciclo for:
int pin[5] = {2, 3, 4, 5, 6}; // array di cinque elementi for(int indice = 0; indice < 5; indice++) { digitalWrite(pin[indice], HIGH); // imposto tutti i pin alti }
/* * Progetto 5: * accende in sequenza 5 LED creando un effetto rimbalzo (alla supercar) * Nome studente: * Creato il: data */ // array con i pin collegati ai 5 LED int pinLed[] = { 1, 2, 3, 4, 5}; // direzione (1 -> dal pin 1 al pin 5, -1 -> dal pin 5 al pin 1) int direzione = 1; // indice dell'array che indica su quale LED operare int ledCorrente = 0; void setup() { // imposto tutti i pin digitali come uscite for (int x = 0; x < 5; x++) { pinMode(pinLed[x], OUTPUT); } } void loop() { // spengo tutti i LED for (int x = 0; x < 5; x++) { digitalWrite(pinLed[x], LOW); } // accendo il LED corrente digitalWrite(pinLed[ledCorrente], HIGH); // aggiorno ledCorrente in base alla variabile direzione (ad es. se il LED // corrente è il secondo dell'array e la direzione è 1 il prossimo è il terzo ledCorrente = ledCorrente + direzione; // cambio direzione se siamo agli estremi (0 -> primo elemento, 4 -> ultimo) if (ledCorrente == 4) { direzione = -1; } if (ledCorrente == 0) { direzione = 1; } // piccola pausa delay(100); }
delay(analogRead(0));
ledCorrente
è l'indice usato per accedere agli elementi dell'array; il suo valore viene aumentato o diminuito ad ogni ciclo a seconda della variabile direzione
ledCorrente = ledCorrente + direzione;
si poteva usare la notazione più sintentica ledCorrente += direzione;
Scopo | visualizziamo l'intesità luminosa misurata da un fotoresistore con dei LED |
---|---|
Componenti | 5 LED, 5 resistori da 180Ω, resistore da 10KΩ, fotoresistore |
Una fotocellula (o fotorivelatore) è un dispositivo che misura l'intensità luminosa e la trasforma in un segnale elettrico. Il fotoresistore è il tipo più semplice di fotocellula ed è un componente la cui resistenza è inversamente proporzionale alla quantità di luce a cui è esposto.
La resistenza del fotoresistore usato in questa prova è maggiore di 20kΩ in condizioni di totale oscurità e scende sotto i 100Ω quando esposto direttamente alla luce di una lampada.
Comportandosi come una resistenza variabile è possibile usare il fotoresistore come un potenziometro comandato dalla luce invce che da una manopola. Se collegato in serie ad un resistore di valore costante, come nello schema in figura, la tensione ai suoi capi sarà:
`V_(FR) = (R_(FR))/(R_(FR) + R)*V`
dove V è la tensione totale, R la resistenza del resistore e RFR la resistenza variabile del fotoresistore.
/* * Progetto 6: * indica l'intensità luminosa rilevata da un fotoresistore * accendendo una serie di 5 LED * Nome studente: * Creato il: data */ // array con i pin collegati ai 5 LED int pinLed[] = { 2, 3, 4, 5, 6}; // valore della tensione ai capi del fotoresistore // completa oscurità -> circa 800 // esposizione diretta a una lampada -> circa 20 int valoreFR; void setup() { // imposto tutti i pin digitali come uscite for (int x = 0; x < 5; x++) { pinMode(pinLed[x], OUTPUT); } Serial.begin(9600); } void loop() { // leggo la tensione ai capi del LED valoreFR = analogRead(0); Serial.println(valoreFR); // spengo tutti i LED for (int x = 0; x < 5; x++) { digitalWrite(pinLed[x], LOW); } // accendo un certo numero di LED in base alla luce che investe il fotoresistore if (valoreFR < 500) { digitalWrite(pinLed[0], HIGH); } if (valoreFR < 400) { digitalWrite(pinLed[1], HIGH); } if (valoreFR < 300) { digitalWrite(pinLed[2], HIGH); } if (valoreFR < 150) { digitalWrite(pinLed[3], HIGH); } if (valoreFR < 50) { digitalWrite(pinLed[4], HIGH); } // piccola pausa delay(500); }
valoreFR
è minore di 1023Scopo | suonare una melodia con un cicalino piezoelettrico |
---|---|
Componenti | cicalino piezoelettrico |
I materiali piezoelettrici esibiscono questo comportamento:
All'interno del cicalino è presente un elemento piezoelettrico che emette un click ogni volta che viene sottoposto a una tensione a causa della deformazione provocata dall'effetto piezoelettrico. Se viene applicata alternativamente una tensione il cicalino emetterà un suono la cui tonalità dipende dalla frequenza con cui la tensione passa dal valore alto a quello basso.
/* * Progetto 7 * Suonare una melodia con il cicalino piezoelettrico * Nome Studente: * Creato il: data */ // pin collegato al cicalino int pinCicalino = 10; // note della melodia (frequenza come da tabella) int melodia[] = {262, 262, 392, 392, 440, 440, 392, 349, 349, 330, 330, 294, 294, 262}; // durata delle note in millisecondi int durataNota[] = {500, 500, 500, 500, 500, 500, 1000, 500, 500, 500, 500, 500, 500, 1000}; void setup() { } void loop() { // suona in sequenza le note della melodia (14 note in tutto) for (int nota = 0; nota < 14; nota++) { tone(pinCicalino, melodia[nota],durataNota[nota]); // pausa lunga quanto la durata della nota delay(durataNota[nota]); // interrome il suono prima di emettere la prossima nota noTone(pinCicalino); } }
tone(pin, frequenza, durata)
genera un onda quadra (alterna il valore alto e basso di tensione) su un pin digitale; questo segnale è in grado di pilotare un cicalino facendogli emettere un suononoTone(pin)
tone()
come uscitanota | frequenza |
---|---|
do | 262 |
do# | 277 |
re | 294 |
re# | 311 |
mi | 330 |
fa | 349 |
fa# | 370 |
sol | 392 |
sol# | 415 |
la | 440 |
la# | 466 |
si | 494 |
Scopo | rilevare la distanza con un sensore a ultrasuoni |
---|---|
Componenti | sensore a ultrasuoni HC-SR04 |
I sensori ad ultrasuoni servono a misurare la distanza di un oggetto e funzionano secondo il principio del sonar:
Il sensore utilizzato in questo progetto è il modello HC-SR04. E' un sensore economico e facile da utilizzare che è in grado di misurare distanze comprese tra 2 centimetri e 4 metri.
Il sensore contiene al suo interno un piccolo microcontrollore che si occupa della misura e dispone di due pin per l'alimentazione (Vcc
e GND
) e due pin digitali per la misura (Trig
e Echo
). Quando si invia un impulso di 10 microsecondo al pin trigger il sensore genera un'onda a ultrasuoni, misura il tempo che impiega a tornare dopo aver colpito un ostacolo e invia un impulso sul pin echo di durata proporzionale alla distanza. La distanza in centimetri si calcola dividendo la durata dell'impulso in microsecondi per 58.
/* * Progetto 8 * Rilevare la distanza con un sensore a ultrasuoni * Nome Studente: * Creato il: data */ // pin collegato al trigger del sensore // un impulso di almeno 10 microsecondi fa partire l'onda a ultrasuoni int trigPin = 9; // pin collegato al pin echo del sensore // l'impulso inviato dal sensore ha una durata proporzionale alla distanza int echoPin = 8; // durata dell'impuslo sul pin echo (in microsecondi) unsigned long durata = 0; // distanza rilevata dal sensore (in centimetri) int distanzaCm = 0; void setup(){ pinMode(echoPin, INPUT); pinMode(trigPin, OUTPUT); Serial.begin(9600); } void loop(){ // invio un impulso di 10 microsecondi dalla scheda al pin trigger digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // calcolo la durata dell'impulso di ritorno inviato dal sensore durata = pulseIn(echoPin, HIGH); // converto la durata dell'impulso in una distanza in centimetri distanzaCm = durata / 58; // invio il dato alla seriale Serial.print("distanza rilevata dal sensore: "); Serial.print(distanzaCm); Serial.println(" centimetri"); delay(500); }
delayMicroseconds()
è l'equivalente di delay()
ma il ritardo è espresso in microsecondi invece che in millisecondipulseIn(pin, valore, timeout)
, dove pin è il pin digitale di ingresso che riceve l'impulso, valore è la costante HIGH
o LOW
a seconda che si voglia misurare il tempo in cui l'impulso assume il valore alto o basso di tensione e il parametro opzionale timeout è il limite di tempo oltre il quale la funzione restituisce il valore zero quando non viene rilevato nessun impulsopulseIn()
restituisce il valore zero dopo un timeout di un secondo; sarebbe opportuno tenerne conto:pulseIn()
per non rallentare le misureint
(32767); per la variabile durata
si usa allora il tipo unsigned long
che può assumere valori da 0 a 4 miliardiScopo | rilevare la presenza di un ostacolo con un sensore a infrarosso |
---|---|
Componenti | sensore a infrarosso TCRT5000 |
I sensori a infrarosso (IR) vengono usati per:
In questa prova useremo una scheda con sensore IR fatta per rilevare ostacoli (o linee scure). Il sensore vero e proprio (TCRT5000) è composto di due parti:
Le due immagini sotto mostrano il lato inferiore e quello superiore della scheda con sensore IR:
Si riconoscono:
Il principio di funzionamento del sensore è molto semplice:
L'uscita analogica fornisce un'indicazione, con una tensione tra 0 e 5 Volt, di quanto è vicino l'ostacolo. L'uscita digitale (0 o 5 Volt) indica la presenza o meno di un ostacolo entro una distanza che è possibile impostare con il trimmer.
Questo tipo di sensori costituiscono un'alternativa a quelli (più complicati e costosi) a ultrasuoni ma funzionano peggio perché la luce ambientale può falsare la misura e gli oggetti possono riflettere la luce in maniera molto diversa (ad esempio uno specchio o a una superficie nera e opaca).
/* * Progetto 9 * Rilevare la distanza con un sensore a infrarosso * Nome Studente: * Creato il: data */ // pin collegato all'uscita digitale del sensore IR // LOW -> ostacolo rilevato; HIGH -> nessun ostacolo int ostacolo = 13; // valore analogico di tensione presente nell'uscita AO del sensore IR // valori bassi -> ostacolo vicino; valori alti -> ostacolo lontano int tensioneIR; void setup(){ pinMode(ostacolo, INPUT); Serial.begin(9600); } void loop(){ // rilevo la presenza dell'ostacolo if(digitalRead(ostacolo) == LOW){ Serial.println("Rilevato ostacolo"); } else { Serial.println("Nessun ostacolo rilevato"); } // valore analogico che dipende dalla distanza tensioneIR = analogRead(0); Serial.print("Valore analogico generato dal sensore IR: "); Serial.println(tensioneIR); delay(500); }
Torna all'indice.