Archivi tag: analogRead

Arduino – misurare tensioni superiori a 5V dc utilizzando un partitore di tensione

Nella precedente lezione abbiamo visto come misurare una tensione non superiore ai 5V dc, vedremo ora come realizzare un semplice circuito che permette mediante un partitore di tensione la misurazione di tensioni fino a 9 Volt. Dimensionando opportunamente le resistenze di partizione potremo effettuare misure per tensioni elettriche superiori.

Precisazione importante

Gli esempi riportati in questa e nella precedente lezione ed inoltre la gran parte degli esempio classici che trovate online, sono pensati per far comprendere il funzionamento del convertitore A/D, ma è opportuno fare alcune considerazioni sulla precisione di lettura, ovvero degli errori commessi dal convertitore A/D e sull’imprecisione delle tensioni di riferimento usate dal microcontrollore per fornirvi la misura. Questo sarà argomento di una prossima lezione e vedremo come ridurre l’errore di misura.

Per rendere semplice la realizzazione utilizzeremo la batteria da 9V, ma se intendete avere dei limiti di misura diversi e superiori a 9V dovrete apportare modifiche ai valori dei componenti, ma le formule esposte restano le medesime.

Prima di procedere con la realizzazione pratica è essenziale comprendere come dimensionare le resistenze del partitore, inoltre è essenziale che la tensione sul pin analogico A0 non superi il valore di 5V. Per effettuare il dimensionamento del circuito fissiamo la massima tensione misurabile Vmis_max  a 9V e imponiamo il valore di uno dei due resistori, ad esempio R1 in modo da poter ricavare il valore di R2.

Vi ricordo inoltre che sarebbe opportuno, una volta fissate le resistenze, fare qualche considerazione sulla corrente massima entrante in A0 in modo che non venga superato il valore di 40 mA corrente massima di I/O sui pin analogici e digitali di Arduino Uno R3, ma come le resistenze che sono state scelte non correremo alcun rischio, però esporrò ugualmente il calcolo.

Nello schema che segue Vmis rappresenta la tensione da misurare, Vadc la tensione sul pin A0. I è la corrente totale che circola nel circuito.

Sappiamo che la tensione Vadc ai capi di R2 non dovrà superare i 5V. Le tensioni su R1 ed R2 saranno:

(a) VR1 = R1*I
(b) VR2 = R2*I

Pertanto la tensione Vmis sarà

(c) Vmis = VR1 + VR2 = R1*I+R2*I = (R1+R2)*I

da cui ricaviamo:

(d) I = Vmis /(R1+R2)

Sostituendo I in (a) e (b) avremo:

(e) VR1 = R1*I = R1 * Vmis /(R1+R2)
(f) VR2 = R2*I = R2 * Vmis /(R1+R2)

Per il calcolo di R2 consideriamo la formula (f) sostituendo i valori fissati, Vmis_max e R1, ricordando che VR2 è la tensioni in A0, cioè Vadc:

⇒ VR2 =  R2 * Vmis /(R1+R2)

⇒ R2 /(R1+R2)  = VR2/Vmis_max

⇒ R2 /(R1+R2)  = 5/9

⇒ R2 /(R1+R2)  = 0,56

⇒ R2  = 0,56*R1 + 0,56*R2

⇒ R2*(1-0,56) = 0,56*R1

⇒ R2 = 0,56 *R1/0,44

⇒ R2 = 0,56 * 27 * 103/0,44 = 34,363 * 103 = 34,363 Kohm

Scelgo come valore commerciale prossimo (e che dispongo nel mie scorte) il valore di 33 Kohm, quindi:

  • R1 = 27 Kohm
  • R2 = 33 Kohm

Per quanto riguarda la corrente entrante in A0, utilizziamo la formula (b):

VR2 = R2*I

I = VR2/R2

I = 5V/33000 Ω = 0,00015 A = 0,15 mA

ben al di sotto del valore massimo del valore accettabile su un pin I/O di Arduino che è di 40mA.

Schema di collegamento

Programmazione

Sviluppiamo il codice necessario per la lettura della tensione e partendo dal primo sketch della lezione precedente modifichiamone alcune parti, nei commenti la spiegazione delle varie parti.

Nel codice bisognerà tenere in conto che la tensione su A0 è data dal calcolo della partizione di tensione, pertanto sapendo che Vmis = Vadc, dalla forma (f) abbiamo:

⇒ VR2 = R2*I = R2 * Vmis /(R1+R2)

⇒ VR2 = Vadc = R2 * Vmis /(R1+R2)

⇒ Vmis = Vadc * (R1+R2)/R2

Che sarà la formula che ci consentirà di rilevare la misura.

// Prof. Maffucci Michele
// Esempio 01: Misura una tensione di 9V con Arduino
// utilizzando variabili di tipo float
// Data: 03.10.2021

// tensione di riferimento massima misurabile
const float tensioneDiRiferimento = 5.0;

float R1 = 27000.0; // 27 Kohm
float R2 = 33000.0; // 33 Kohm

float volt_adc = 0.0;
float volt_mis = 0.0;

void setup() {
  Serial.begin(9600);
  //analogReference(DEFAULT);
}
void loop() {
  // legge il valore su A0 (su R2), cioè la tensione Vadc e lo trasforma
  // in un valore numerico tra 0 e 1023
  
  int valoreLetto = analogRead(A0);

  // Tensione in ingresso ad A0, cioè la tensione Vadc
  // calcolo della proporzione
  // volt:tensioneDiRiferimento = valoreLetto:1023.0
  // da cui si ricava la formula che segue
  
  volt_adc = (valoreLetto/1023.0) * tensioneDiRiferimento;

  //Stampa del valore letto dall'ADC
  Serial.print("Valore ADC = ");
  Serial.println(valoreLetto);
  
  // calcolo della tensione di ingresso Vmis

  volt_mis = volt_adc*(R1+R2)/R2;

  // stampa sulla Serial Monitor la tensione misurata
  Serial.print("Tensione di ingresso = ");
  Serial.println(volt_mis);
  Serial.println(" ");

  delay(1000);
}

Esercizi per i miei studenti

Esercizio 1
Dimensionare il Circuito per misurare una tensione massima di 12V

Esercizio 2
Realizzare uno sketch Arduino che permette di dimensionare il circuito prendendo in  input, attraverso la Serial Monitor il valore massimo misurabile ed il valore di R1 e restituisce il valore di R2 calcolato.

Esercizio 3
Realizzare le medesime funzionalità dell’esercizio 2, ma il valore restituito di R2 deve essere sia quello calcolato che quello commerciale immediatamente superiore o inferiore al valore calcolato.

Buon Coding a tutti 🙂

Arduino – misurare tensioni continue fino a 5V

La misurazione di una tensione con Arduino è un esercizio standard utilizzato per spiegare come funziona il convertitore Analogico Digitale sulla scheda. Nell’esempio che segue verrà mostrato come visualizzare sulla Serial Monitor la tensione di una batterie da 1,5V ma in generale di una tensione non superiore ai 5V, seguono poi una serie di esercizi per i miei studenti.
Nella prossima lezione mostreremo come misurare una tensione superiore ai 5V.

ATTENZIONE
E’ essenziale ricordare che non bisogna in alcun modo inserire tensioni superiori a 5V sui pin di Arduino, in quanto potreste distruggere irrimediabilmente la scheda.

Per la rilevazione di una tensione elettrica su un pin analogico viene utilizzata la funzione analogRead, che come più volte indicato su questo sito, è in grado di convertire una tensione tra 0V e 5V continui in un valore numerico intero con risoluzione di 10 bit tra 0 e 1023, operazione svolta dal convertitore A/D.

Ricordo che l’analogRead(pin) legge il valore di tensione (compreso tra 0 e 5V) applicato sul piedino analogico ‘pin’ con una risoluzione di 10 bit e la converte in un valore numerico compreso tra 0 e 1023, corrispondente quindi ad un intervallo di 1024 valori, pertanto il valore unitario corrisponde a:

Vu = 5V/1023 = 4,89 mV

Per conoscere il valore di tensione rilevato sarà sufficiente moltiplicare la tensione unitaria Vu per il valore restituito dalla funzione analogRead(pin), quello che chiamiamo valore quantizzato Vq compreso tra 0 e 1024, il valore misurato Vm sarà:

Vm = Vu x Vq

e sapendo che Vu corrisponde a 4,89 mV possiamo scrivere:

Vm = 4,89 x Vq

Nota per i miei allievi: riprenderemo questo semplice calcolo qundo utilizzeremo ad esempio i sensori di temperatura.

Il semplice schema di collegamento è riportato nell’immagine che segue:

Per stampare sulla Serial Monitor la tensione ai capi della batteria, useremo valori di tipo float (in virgola mobile), che come indicato nel mio post: “Arduino: tipi di dati – ripasso” possiamo esprime valori compresi tra –3.4028235E+38 e 3.4028235E+38.
La stampa di numeri in virgola mobile sula Serial Monitor verrà rappresentata con numeri che hanno al massimo con due cifre decimali, riprenderemo questo aspetto nel secondo esempio di questa lezione.

// Prof. Maffucci Michele
// Esempio 01: Misura di tensioni continue non superiori a 5V
// utilizzando variabili di tipo float
// Data: 01.10.2021

// tensione di riferimento predefinita sulla scheda
const float tensioneDiRiferimento = 5.0;

// batteria connessa al pin analogico 0
const byte pinBatteria = A0;

void setup() {
  // inizializzazione della porta seriale
  Serial.begin(9600);
}

void loop() {
  // legge il valore della batteria e lo trasforma
  // in un valore numerico tra 0 e 1023
  int valoreLetto = analogRead(pinBatteria);

  // calcolo della proporzione
  // volt:tensioneDiRiferimento = valoreLetto:1023.0
  // da cui si ricava la formula che segue
  float volt = (valoreLetto/1023.0) * tensioneDiRiferimento;

  // stampa sulla Serial Monitor la tensione misurata
  Serial.println(volt);
}

Per evitare spreco di memoria dovuto ai calcoli che utilizzano i tipi di dati float che occupano maggiore memoria, è possibile utilizzare al posto del tipo float il tipo long, ovvero un int lungo rappresentato da 4 byte in grado di rappresentare numeri interi tra –2147483648 a 2147483647.

Vediamo come modificare lo sketch precedente per rilevare tensioni espresse in millivolt in cui però si utilizzano variabili intere di tipo long:

// Prof. Maffucci Michele
// Esempio 02: Misura di tensioni continue non superiori a 5V
// utilizzando variabili di tipo float
// Data: 01.10.2021

// batteria connessa al pin analogico 0
const byte pinBatteria = A0;

void setup() {
  // inizializzazione della porta seriale
  Serial.begin(9600);
}

void loop() {
  // legge il valore della batteria e lo trasforma
  // in un valore numerico tra 0 e 1023
  // valoreLetto è di tipo long
  long valoreLetto = analogRead(pinBatteria);

  // stampa sulla Serial Monitor la tensione misurata
  // in millivolt
  
  Serial.println((valoreLetto*(500000/1023L))/100);
}

Quindi per evitare di effettuare calcoli con numeri di tipo float (in virgola mobile) senza perdere precisione, il trucco consiste nell’operare sui valori in millivolt invece che  sui valori in volt. Ricordo che 1 volt corrisponde a 1000 millivolt.

Come detto all’inizio di questa lezione sappiamo che un valore numerico di 1023 restituito dall’analogRead, corrisponde al valore massimo di 5000 millivolt, allora ogni unità rappresenta 5000/1023 millivolt, che corrisponde a 4,89 millivolt. Come detto nell’esempio precedente, la stampa su Serial Monitor di un numero in virgola mobile mostrerà al massimo due decimali, pertanto l’eliminazione dei decimali nel secondo esempio possiamo farlo moltiplicando per 100, nel codice: 5000×100=500000, questo valore verrà poi moltiplicato per il rapporto tra il valore letto e 1023 ed il tutto ancora diviso per 100, così facendo otterremo il valore in millivolt. Questo calcolo permette di far effettuare al compilatore solamente calcoli tra interi e non tra float, rendendo quindi la computazione più veloce e riducendo la quantità di memoria utilizzata.

Si noti che al fondo del numero 1023 è stata aggiuta una L, cioè 1023L, che indicare al compilatore che il numero rappresentato è di tipo long (4 byte).

Esercizi per i miei studenti

Esercizio 1
Utilizzare un Trimmer per regolare la tensione in ingresso ad A0 tra 0 e 5V, in questo caso si prenda la tensione di 5V dal pin di Arduino.

Esercizio 2
Nel primo sketch proposto utilizzare la funzione map per convertire il valore restituito dall’ analogRead in un valore di tensione. In questo caso nascono dei problemi sulla precisione della misura, sapresti indicarmi quali?

Esercizio 3
Visualizzare il valore di tensione regolato dal Trimmer sul Plotter Seriale.

Esercizio 4
Utilizzando uno qualsiasi dei due sketch indicati sopra e visualizzare la tensione misurate sul un display 16×2

Esercizio 5
Aggiungere all’esercizio precedente l’indicazione di carica data da un grafico costituito da 5 quadrati che ne indicano il livello di carica, non appena il livello di carica raggiunge 1 volt il quadrettino inizia a lampeggiare.

Buon Making a tutti 🙂

Arduino – Approfondimenti sulla modulazione di larghezza di impulso (PWM)

Scrivo questo post ad integrazione della lezione: Arduino – lezione 06: modulazione di larghezza di impulso (PWM) che sto utilizzando con i miei studenti di 4′ informatica per illustrare le modulazioni di tipo digitali. L’obiettivo è quello di mostrare sull’oscilloscopio come varia il  Duty Cycle di un’onda quadra su un pin di tipo PWM di Arduino utilizzato per impostare l’intensità luminosa di un LED mediante una regolazione applicata attraverso un trimmer connesso al pin A0 di Arduino.

Oltre alla visualizzazione sull’oscilloscopio si desidera, come riscontro, la stampa sulla Serial Monitor dei seguenti valori:

  • Tensione in input sul pin A0
  • Valore restituito dalla funzione analogRead() – (tra 0 e 1023)
  • Valore restituito dall’analogWrite – (tra 0 e 254)
  • Valore percentuale del Duty Cycle  (tra 0% e 100%)

Il circuito da realizzare con l’indicazione delle connessioni all’oscilloscopio è il seguente:

Sul canale X verrà visualizzata l’onda quadra in uscita dal pin 11 il cui Duty Cycle sarà regolato agendo sul trimmer.

Sul canale Y verrà visualizzata la tensione continua in input sul pin A0, che sarà convertita dal convertitore Analogico Digitale di Arduino in un valore compreso tra 0 e 1023  (risoluzione di 10 bit). Ricordo che tale conversione sarà fatta con l’istruzione analogRead(pin).

Poiché uno degli obiettivi è quello di visualizzare la tensione rilevata sul pin A0, ricordo che tale misurazione viene fatta utilizzando la funzione analogRead(pin) che legge il valore di tensione (compreso tra 0 e 5V) applicato sul piedino analogico ‘pin’ con una risoluzione di 10 bit e la converte in un valore numerico compreso tra 0 e 1023, corrispondente quindi ad un intervallo di 1024 valori, pertanto ogni intervallo corrisponde ad un valore di tensione Vu di:

Per sapere quindi il valore di tensione rilevato (nell’intervallo tra 0V e 5V) sarà sufficiente moltiplicare la tensione unitaria Vu per il valore restituito dalla funzione analogRead(pin), valore quantizzato indicato con Vq compreso tra 0 e 1023:

Sapendo che Vu corrisponde a 4,88 mV

possiamo anche scrivere che:

Questa formula sarà inserita all’interno dello sketch.

Di seguito la schermata dell’oscilloscopio che visualizza la situazione indicata dai dati stampati sulla Serial Monitor:

  • Vmax(2) indica la tensione in ingresso ad A0 (la piccola discrepanza tra valore indicato sull’oscilloscopio e la stampa sulla Serial Monitor dipende dalle approssimazioni di calcolo).
  • Vmax(1) indica il valore di picco della tensione sul pin 11.

La spiegazione del funzionamento dello sketch sono dettagliate nei commenti:

/* Prof. Michele Maffucci
   03.06.2019
 
   Regolazione luminosità LED mediante
   trimmer, si utilizza la funzione map

   Stampa sulla seriale:
   - del valore di tensione sul pin A0
   - del valore restituito dall'analogRead
   - del valore restituito dall'analogWrite
   - del valore del Duty Cycle %
 
   Questo codice è di dominio pubblico 
*/

// pin analogico su cui inviare la tensione analogica (pin A0)
int misura = 0;

// pin a cui è connesso il LED
int pinLed = 11;

// variabile in cui conservare il valore inserito su A0
long val = 0;

// variabile in cui memorizzare il Duty Cycle
int inputVal = 0;

const long VoltRiferimento = 5.0; // valore di riferimento


void setup(){
  Serial.begin(9600);      // inizializzazione della comunicazione seriale
  pinMode(pinLed, OUTPUT); // definizione di ledPin come output
}

void loop(){
  // analogRead leggerà il valore su A0 restituendo un valore tra 0 e 1023
  // per approfondimenti si consulti il link: http://wp.me/p4kwmk-1Qd
  val = analogRead(misura);

  // analogWrite() accetta come secondo parametro (PWM) valori tra 0 e 254
  // pertanto "rimappiamo" i valori letti da analogRead() nell'intervallo
  // tra 0 e 254 usando la funzione map
  // per approfondimenti si consulti il link: http://wp.me/p4kwmk-1Tu
  inputVal = map(val, 0, 1023, 0, 254);
  
  // accendiamo il LED con un valore del Duty Cycle pari a val
  analogWrite(pinLed,inputVal);

  // Tensione inviata sul pin analogico A0.
  // Valore in virgola mobile.

  float volt = (VoltRiferimento/1024.0)*val;

  // visualizzazione il valore della tensione su A0,
  // del valore restituito dalla analogRead,
  // del valore restituito dall'analogWrite
  // e del Duty Cycle %

  // per approfondimenti sull'uso di String si consulti il link: https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
  
  Serial.println(String("Tensione su A0: ") + volt + "V" + String(";  ") + "analogRead: " + val + String(";  ") + String("Valore analogWrite: ") + inputVal + String("; ") + String("Duty Cycle %: ") + (inputVal/255.0)*100 + String("%;"));
  delay(500); // stampa una strina di valori ogni mezzo secondo
}

Buon Coding a tutti 🙂