Lezione 4 – Corso di Elettronica Creativa con Arduino Sensor Kit

Il potenziometro

I potenziometri sono tra i resistori variabili più diffusi la cui legge di variazione della resistenza dipende da una grandezza meccanica (generalmente la rotazione di un albero, in qualche caso lo spostamento rettilineo di un cursore).

I resistori variabili sono schematicamente indicati con uno dei due simboli riportati di seguito:

Un resistore variabile è caratterizzato dal suo valore ohmico esistente tra i due terminali fissi; esso può essere utilizzato all’interno di un circuito in due modi come reostato, utilizzato come regolatore di corrente o come potenziometro utilizzato come regolatore di tensione, in questa lezione ne vedremo l’utilizzo come potenziometro.

Non tutti i potenziometri sono uguali, nei potenziometri “logaritmici” (usati negli amplificatori audio) la variazione di resistenza segue una curva esponenziale per meglio adattarsi alla percezione umana del volume.

Obiettivi di questa lezione

  1. Comprendere il funzionamento del potenziometro come partitore di tensione variabile.
  2. Collegare correttamente il modulo Potentiometer Grove allo shield Arduino Sensor Kit.
  3. Misurare la posizione del cursore con analogRead() e convertire in un valore all’interno di un range fissato.
  4. Utilizzare l’istruzione di controllo di flusso IF-THEN-ELSE.

Teoria di base

  • Il microcontrollore ATmega328 è dotato si 6 ADC (Analog to Digital Converter – Convertitori Analogici Digitali)
  • Gli ingressi analogici leggono valori compresi tra 0 e 5 volt
  • La risoluzione dei valori convertiti in digitale è di 10 bit (1024 valori)
  • Ogni bit equivale a valori di tensione pari a 5/1024 = 4,8 mV che è la più piccola misura di tensione che si può rilevare

Le grandezze fisiche del mondo reale sono di tipo analogico ed Arduino dispone di una serie di ingressi adibiti alla lettura di grandezze di tipo analogico, che come dettagliato nella lezione 1, vengono poi convertire dal microcontrollore in grandezze di tipo digitale.

Le variazioni di grandezze di tipo analogico vengono lette da Arduino come variazioni di tensione sugli ingressi analogici.

Un sensore generico quindi, connesso sui pin analogici fornirà una tensione che sarà funzione della grandezza fisica misurata.

Per poter simulare la variazione di tensione e quindi studiare il comportamento di un generico sensore e capire come leggere valori analogici, utilizzeremo in questa fase un potenziometro o un trimmer, componente elettronico che consente di variare la tensione presente ai suoi capi.

Il Grove Rotary Potentiometer

Il Grove Rotary Potentiometer non è altro che un trimmer o potenziometro, funziona come una resistenza variabile il cui range di rotazione è di circa 300 gradi. Collegandolo a un ingresso analogico di Arduino, il valore letto oscilla tra 0 e 1023 in base alla posizione del cursore. L’estremo superiore della scala dipende dalla tensione di alimentazione: per ottenere letture corrette, imposta la scheda su 5 V.

  • Ruotando la vite in senso antiorario fine a fine corsa la tensione presente sul piedino centrale sarà 0V.
  • Ruotando la vite in senso orario in posizione centrale si avrà una tensione di 2,5 V.
  • Ruotando la vite in senso orario fine a fine corsa si avrà una tensione di 5 V.

Il cursore del trimmer, rappresentato dalla freccia nel simbolo elettronico, o dalla vite nell’immagine prima esposta, può passare da un estremo all’altro dove è collegata direttamente a massa (0 V) oppure all’alimentazione alla Vin nel nostro caso 5 V, passando attraverso tutte le posizioni intermedie, si potrà quindi dosare la tensione sul piedino centrale (V out) come frazione della tensione di alimentazione:

  • Varaindo l’angolo di rotazione varieranno i valori di R1 ed R2.
  • Il valore della tensione di uscita sarà quella del partitore di tensione tra R1 e R2.

Per la legge di Ohm avremo che la differenza di potenziale ai capi di ogni resistore e la tensione totale Vin sarà:

Si ricava la I dall’equazione alla magli Vin e si sotituisce all’interno della VR1 e VR2:

Da cui le due formule del partitore per ottenere la VR1 e VR2:

Per quanto riguarda il modulo potenziometro sull’Arduino Sensor Kit, il suo valore nominale è di 10 kΩ e la sua risposta è lineare sull’intero arco di 300°, il modulo risulta utile sia per accendere e spegnere un carico (ad esempio un LED) sia per regolare la frequenza di lampeggio o altre grandezze analogiche in un circuito di prova.

Collegate il modulo Grove Rotary Angle Sensor al pin analogico contrassegnato A0 sul tuo Grove Base Shield. Inserisci poi lo shield sulla tua Arduino UNO R3 e collegala al computer.

Proviamo il codice

  1. Incollate lo sketch (Esempio 1) che segue nell’IDE Arduino.
  2. Dal menu Strumenti seleziona la vostra scheda e la porta COM corretta, quindi premete Upload.

Esempio 1: lettura del valore restituito da analogRead()

1/*
2   Prof. Maffucci Michele
3   Lettura potenziometro e mappatura 0‑100
4   Visualizza il valore restituito da analogRead()
5   sul Serial Monitor
6*/
7const int pinPot = A0; // pin collegato all'uscita V0 del potenziometro
8 
9void setup() {
10  Serial.begin(9600);           // avvia la comunicazione seriale
11  pinMode(pinPot, INPUT);       // imposta il pin come ingresso analogico
12}
13 
14void loop() {
15  int lettura = analogRead(pinPot);                   // acquisisci il valore grezzo (0‑1023)
16  int valore = map(lettura, 0, 1023, 0, 100);         // converte la lettura nell'intervallo 0 - 100
17  Serial.print("Valore restituito da analogRead(): ");
18  Serial.println(lettura);                            // stampa il valore grezzo
19  Serial.print("Valore potenziometro: ");
20  Serial.println(valore);                             // stampa il valore dell'analogRead()
21  delay(500);                                         // aggiorna ogni mezzo secondo
22}

Quando l’upload è terminato, aspettate un paio di secondi e aprite la Serial Monitor. Vedrete comparire a schermo la lettura del potenziometro ogni 500 ms, i valori si riferiscono sia al valore grezzo restituito dall’analogRead() e sia quello rimappato nell’intervallo 0-100. Se riducete l’intervallo di delay() potrete aumentare la frequenza di aggiornamento e seguire con maggiore dettaglio la variazione dei valori mentre ruotate la manopola.

Ora potete visualizzare direttamente il valore del potenziometro nel Serial Monitor. Per modificare il valore, vi basta ruotare la manopola.

Nota: ricordate di impostare l’interruttore di alimentazione del Grove Base Shield su 5 V, altrimenti il valore massimo letto dal potenziometro sarà intorno a 675.

Come funziona lo sketch dell’Esempio 1

Il potenziometro restituisce un valore compreso tra 0 e 1023. Per ottenere variazioni più precise – e un numero più intuitivo se decideremo di usarlo in seguito – rimappiamo questi valori nel range 0-100.

Questo si realizza con la funzione map(), che nel codice appare così:

1int valore = map(lettura, 0, 1023, 0, 100);

Perché map() funzioni correttamente occorre:

  1. Indicare la variabile di origine, in questo caso lettura, dove memorizziamo la lettura del potenziometro.
  2. Definire l’intervallo originale (0–1023), tipico di un ingresso analogico.
  3. Stabilire l’intervallo desiderato per l’output, qui 0–100.

In questo modo il valore letto sarà più facile da interpretare e potrà essere usato direttamente, ad esempio, come percentuale.

Precisazioni sull’uso di: analogRead(pin) e map()

analogRead(pin): legge un valore di tensione applicato al piedino analogico ‘pin’ con una risoluzione di 10 bit. La funzione restituisce un valore compreso tra 0 e 1023. I pin analogici a differenza di quelli digitali non hanno bisogno di essere dichiarati come pin di INPUT o OUTPUT.

map(): converte (rimappa) un numero da un intervallo a un altro, mantenendo la proporzione. Molto utile, ad esempio, per trasformare una lettura di un sensore (0-1023) in una percentuale (0-100) o in un valore PWM (0-255).

sintassi:

map(valore, daMin, daMax, aMin, aMax)

    • valore – il numero da rimappare (può essere int, long o simili).
    • daMin – limite inferiore dell’intervallo di origine.
    • daMax – limite superiore dell’intervallo di origine.
    • aMin – limite inferiore del nuovo intervallo.
    • aMax – limite superiore del nuovo intervallo

Valore restituito: Un long che rappresenta valore riscalato nel nuovo intervallo.

map() non “clampa” il risultato: se valore è fuori dall’intervallo originale, anche l’output sarà fuori dal nuovo intervallo. Per limitare il risultato, usare constrain().

Esempio 2: LED ON/OFF con potenziometro.

il LED si accende solo quando il potenziometro supera il 50 % del suo giro (circa 512 su 1023). In caso contrario rimane spento. Sulla Serial Monitor viene indicato lo stato del LED ed il valore restituito dall’analogRead().

1/*
2   Prof. Maffucci Michele
3   LED acceso quando il potenziometro supera la metà corsa
4   e segnalazione dello stato sulla Serial Monitor
5*/
6const int pinPot = A0;   // ingresso analogico
7const int ledPin = 6;    // pin digitale per il LED (non è necessario che sia un pin PWM)
8 
9void setup() {
10  Serial.begin(9600);       // avvia la comunicazione seriale
11  pinMode(ledPin, OUTPUT);  // configura il pin del LED
12}
13 
14void loop() {
15  int lettura = analogRead(pinPot); // 0–1023
16 
17if (lettura > 512) {                      // soglia 50 %
18    digitalWrite(ledPin, HIGH);             // LED ON
19    Serial.print("LED acceso - ");          // segnalazione sulla serial monitor
20    Serial.print("valore analogRead(): ");
21    Serial.println(lettura);                // valore restituito dall'analogRead()
22  } else {
23    digitalWrite(ledPin, LOW);              // LED OFF
24    Serial.print("LED spento - ");          // segnalazione sulla serial monitor
25    Serial.print("valore analogRead(): ");  // valore restituito dall'analogRead()
26    Serial.println(lettura);
27  }
28  delay(500); // piccola pausa per evitare letture inutilmente ravvicinate
29}

if…else

Come rappresentato dal diagramma di flusso che segue, la struttura if…else è composta da tre sezioni, la prima è costituita da un blocco “condizione” che controlla il verificarsi di una determinata condizione logica, se la condizione risulta “Vera” viene eseguito il blocco “istruzioni” altrimenti, se “Falso” viene eseguito il blocco “altre istruzioni”:

La condizione logica da verificare è inclusa tra parentesi tonde. Il ramo che viene eseguito nel caso di risultato “Vero” è racchiuso tra il primo gruppo di parentesi graffe, mentre il secondo gruppo di codice, incluso tra le parentesi graffe dopo l’istruzione “else“, viene eseguito se “condizione” risulta “Falso“:

1if (inputPin == HIGH)
2{
3   doThingA;
4}
5else
6{
7   doThingB;
8}

Nota: una istruzione if verifica semplicemente se la condizione all’interno delle parentesi tonde è vera o falsa. Nell’esempio, se if (inputPin == HIGH) risulta vera, cioè inputPin ha un valore HIGH (+5V) viene eseguita la porzione di codice doTingA, in caso contrario viene eseguita la porzione di codice che segue l’else: doThingB

L’else può anche precedere altre istruzioni if e test mutualmente esclusivi possono essere eseguiti nello stesso momento. Quindi potrete avere molte istruzioni if annidate.
Potete avere un numero illimitato di rami else. Ricordate che in funzione del valore logico del blocco di controllo, solo un insieme di istruzioni verrà eseguito.

1if (inputPin < 500)
2{
3   doThingA;
4}
5else if (inputPin >= 1000)
6{
7   doThingB;
8}
9else
10{
11   doThingC;
12}

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.