Guide · 15 min di lettura

Voltmetro con Arduino: misurare 0–25 V con LCD e calibrazione

Come costruire un voltmetro con Arduino: misurare 0–25 V col partitore, scegliere resistenze, protezione zener, calibrazione, LCD, INA219 e tester.

Un voltmetro con Arduino è uno strumento di misura che costruisci in una serata: due resistenze, un ingresso analogico e poche righe di codice bastano per misurare con precisione da 0 a 25 V e mostrare il valore su un display. Gli ingressi analogici di Arduino leggono al massimo 5 V; per misurare una tensione più alta prima la riduci con un partitore di tensione, poi nel codice la riporti al valore reale con lo stesso rapporto. Monitor di batterie, indicatori per alimentatori, logger per pannelli solari e tester di pile si basano tutti su questa idea.

In questa guida vedrai passo passo come scegliere le resistenze in base all'intervallo di misura, come un diodo zener e una resistenza in serie proteggono l'ingresso analogico dalle sovratensioni, come funziona il modulo sensore di tensione 0–25 V e come la tensione di riferimento e la calibrazione avvicinano le tue letture a quelle di un multimetro. Poi mostrerai il valore su un LCD I2C, costruirai lo stesso voltmetro con ESP32 e Raspberry Pi Pico, aggiungerai la misura di corrente con un INA219 per trasformarlo in un wattmetro e infine realizzerai un tester che misura la capacità reale di una batteria in mAh.

Voltmetro digitale
Il voltmetro che costruisci con Arduino può mostrare la tensione con due decimali, proprio come questi indicatori da pannello.

Come funziona un voltmetro con Arduino?

Arduino non conosce direttamente la tensione: il suo ADC (convertitore analogico-digitale) confronta la tensione sull'ingresso analogico con una tensione di riferimento e restituisce il risultato come numero intero. L'ADC di Arduino Uno è a 10 bit: legge 0 per 0 V e 1023 per la tensione di riferimento (5 V di default). La tensione sul pin è Vpin = lettura × Vref / 1024. Se all'ingresso c'è un partitore di tensione, la tensione che stai davvero misurando è Vin = Vpin × (R1 + R2) / R2. La precisione dell'intero voltmetro dipende quindi da tre cose: il valore reale di Vref, il rapporto tra le due resistenze e l'errore dell'ADC stesso.

SchedaADCRiferimento1 passo sul pin1 passo con partitore 0–25 V
Arduino Uno, Nano, Pro Mini10 bit (0–1023)5 V (AVcc)4,88 mV24,4 mV (30 kΩ + 7,5 kΩ)
ESP3212 bit (0–4095)Circa 3,3 V (attenuazione 11 dB)Circa 0,8 mVCirca 9 mV (100 kΩ + 10 kΩ)
Raspberry Pi Pico12 bit (0–65535 con read_u16)3,3 V (ADC_VREF)0,81 mV8,9 mV (100 kΩ + 10 kΩ)

Partitore di tensione e scelta delle resistenze per 0–25 V

La tensione da misurare entra dalla resistenza superiore R1, il punto centrale tra le due resistenze va al pin analogico e la resistenza inferiore R2 va a GND. Per sceglierle, prima stabilisci la tensione massima, poi un rapporto che a quella tensione lasci il pin un po' sotto il riferimento, per esempio circa 4,5 V su un Uno. La coppia da 30 kΩ e 7,5 kΩ dei moduli pronti divide esattamente per 5: 25 V in ingresso danno 5,00 V sul pin. Non scegliere i valori a caso: se la resistenza totale è troppo bassa il partitore spreca corrente dalla sorgente misurata, se è troppo alta il condensatore di campionamento interno dell'ADC non fa in tempo a caricarsi e la lettura deriva. Il datasheet dell'ATmega328P raccomanda che la sorgente collegata a un ingresso analogico non superi i 10 kΩ; per un partitore questa resistenza è il parallelo di R1 e R2 (6 kΩ con 30 kΩ e 7,5 kΩ). Trovi la formula in dettaglio e l'effetto del carico nell'articolo sul partitore di tensione.

IntervalloArduino Uno (5 V): R1 + R2Pin a fondo scalaESP32 / Pico (3,3 V): R1 + R2Pin a fondo scala
0–10 V12 kΩ + 10 kΩ4,55 V33 kΩ + 10 kΩ2,33 V
0–25 V30 kΩ + 7,5 kΩ (modulo pronto)5,00 V100 kΩ + 10 kΩ2,27 V
0–30 V56 kΩ + 10 kΩ4,55 V120 kΩ + 10 kΩ2,31 V
0–50 V100 kΩ + 10 kΩ4,55 V220 kΩ + 10 kΩ2,17 V
Invece di calcolare a mano il rapporto per il tuo intervallo, puoi usare il calcolatore del partitore di tensione. Nelle colonne ESP32 e Pico abbiamo tenuto apposta il pin sotto 2,5 V, perché l'ADC dell'ESP32 perde linearità nella parte alta. Preferisci resistenze a film metallico all'1%; due resistenze al 5% possono spostare il rapporto di circa il 10% nel caso peggiore.

Protezione: diodo zener, resistenza in serie e condensatore

Anche con un partitore calcolato bene, un puntale sbagliato, un picco sull'alimentatore o toccare per errore 48 V invece di 25 V possono portare il pin oltre 5 V. I pin dell'ATmega328P sopportano al massimo l'alimentazione più 0,5 V. All'interno del pin ci sono diodi di protezione verso 5 V e GND, ma reggono solo correnti piccole. La buona notizia è che la resistenza superiore del partitore limita già la corrente. Con una R1 da 30 kΩ, anche toccando 50 V nel pin entrano al massimo circa 1,5 mA. Per ridurre ancora questa corrente e assorbire in sicurezza la tensione in eccesso puoi aggiungere i seguenti livelli.

  • Resistenza in serie: metti una resistenza da 4,7–10 kΩ tra il punto centrale del partitore e il pin analogico. In caso di sovratensione la corrente verso i diodi interni del pin scende a pochi microampere.
  • Condensatore da 100 nF: collegalo tra il pin analogico e GND. Compensa la resistenza di sorgente più alta dovuta alla resistenza in serie, perché durante il campionamento l'ADC prende la carica che gli serve da questo condensatore. Inoltre filtra rumore e picchi brevi.
  • Diodo zener da 5,1 V: collega uno zener come l'1N4733A o il BZX55C5V1 con il catodo sul pin e l'anodo a GND. Quando la tensione cerca di superare 5,1 V, lo zener conduce e scarica l'eccesso verso GND.
  • Attenzione alla dispersione dello zener: uno zener inizia ad assorbire una piccola corrente già un po' sotto la tensione di breakdown, e con un partitore ad alta resistenza questa corrente abbassa la lettura. Se usi lo zener, tieni il massimo del pin intorno a 4 V, oppure usa al suo posto un diodo Schottky (BAT85) dal pin alla linea dei 5 V.
  • Polarità invertita: se colleghi i puntali al contrario, sul pin arriva una tensione negativa. La resistenza in serie limita la corrente; per maggiore sicurezza puoi aggiungere un secondo diodo Schottky con l'anodo a GND e il catodo sul pin.
Questo voltmetro è solo per la corrente continua e le basse tensioni (al massimo qualche decina di volt). Non provare mai a misurare la rete a 230 V con due resistenze: è potenzialmente letale e collega il GND di Arduino alla rete. Per la tensione di rete si usa un modulo a trasformatore con isolamento galvanico come lo ZMPT101B. Inoltre il negativo della sorgente misurata deve essere collegato al GND di Arduino; senza una massa comune la lettura non ha senso.

Il modulo sensore di tensione pronto (0–25 V)

Se non vuoi saldare, puoi usare il piccolo modulo rosso o blu venduto come "voltage sensor". Dentro non c'è nulla di magico: un partitore fatto esattamente da una resistenza da 30 kΩ e una da 7,5 kΩ, un morsetto a vite e un connettore a tre pin. Dato che il rapporto è 5, con un Arduino a 5 V misuri da 0 a 25 V, ma con una scheda a 3,3 V solo fino a 16,5 V. Su una scheda a 3,3 V, toccare 25 V porta 5 V sul pin e lo danneggia, quindi per ESP32 e Pico è più sicuro costruire il tuo partitore dalla tabella sopra. Il modulo non ha diodo di protezione, perciò valgono anche qui le precauzioni con zener o Schottky della sezione precedente.

Pin del moduloFunzioneArduino UnoESP32 (partitore tuo)Raspberry Pi Pico (partitore tuo)
VCC (morsetto)Positivo della sorgente da misurareSorgente +Estremo superiore di R1Estremo superiore di R1
GND (morsetto)Negativo della sorgente da misurareSorgente −Sorgente − e GNDSorgente − e GND
SSegnale divisoA0GPIO 34 (ADC1)GP26 (ADC0, pin 31)
+Non collegato nella maggior parte dei moduliNon collegare--
−GND del moduloGNDGNDGND (es. pin 33)

Passo passo: il tuo primo voltmetro con Arduino

  1. Collega il pin S del modulo ad A0 e il pin − a GND. Se costruisci il partitore da solo, metti la 30 kΩ dal lato della sorgente e la 7,5 kΩ dal lato GND, e porta il punto centrale ad A0.
  2. Collega Arduino alla USB, misura con il multimetro tra il pin 5V e GND e annota il valore. La tensione della USB spesso è tra 4,7 e 5,1 V.
  3. Scrivi il valore misurato nella costante VREF del codice qui sotto e caricalo.
  4. Collega la sorgente da misurare al morsetto del modulo: positivo a VCC, negativo a GND. Per la prima prova va benissimo una pila da 9 V o un alimentatore regolabile.
  5. Apri il Monitor seriale a 9600 baud. Leggi la tensione e intanto misura la sorgente con il multimetro per confrontare i due valori.
C++ (Arduino IDE)
1// Arduino voltmetre: 0-25 V gerilim sensörü modülü / Arduino voltmeter: 0-25 V voltage sensor module
2// Modül S -> A0, modül - -> GND / module S -> A0, module - -> GND
3// Ölçülen kaynak modülün VCC ve GND klemensine / measured source goes to the module's VCC and GND terminals
4const int SENSE_PIN = A0;
5const float VREF = 5.00;       // 5V pininde ölçtüğün gerilim / voltage you measured on the 5V pin
6const float R1 = 30000.0;      // üst direnç (ohm) / top resistor (ohms)
7const float R2 = 7500.0;       // alt direnç (ohm) / bottom resistor (ohms)
8const float CAL = 1.000;       // kalibrasyon: gerçek / okunan / calibration: real / measured
9const int SAMPLES = 32;        // ortalama için örnek sayısı / samples to average
10
11float readVoltage() {
12  analogRead(SENSE_PIN);                    // ilk okumayı at / discard the first reading
13  unsigned long sum = 0;
14  for (int i = 0; i < SAMPLES; i++) {
15    sum += analogRead(SENSE_PIN);
16    delayMicroseconds(500);
17  }
18  float adc = (float)sum / SAMPLES;         // 0-1023 arası ortalama / average between 0 and 1023
19  float vPin = adc * VREF / 1024.0;         // pindeki gerilim / voltage at the pin
20  return vPin * (R1 + R2) / R2 * CAL;       // bölücüden önceki gerilim / voltage before the divider
21}
22
23void setup() {
24  Serial.begin(9600);
25}
26
27void loop() {
28  float v = readVoltage();
29  if (v < 0.05) v = 0.0;                    // boşta gürültüyü sıfırla / zero the noise when idle
30  Serial.print(F("Gerilim / Voltage: "));
31  Serial.print(v, 2);
32  Serial.println(F(" V"));
33  delay(500);
34}

Il codice fa ogni volta la media di 32 letture, così l'oscillazione di ±1 passo dell'ADC sparisce quasi del tutto e l'ultima cifra si stabilizza. La prima lettura viene scartata perché il condensatore di campionamento dell'ADC conserva ancora la carica del canale precedente. Arrotondare a zero tutto ciò che è sotto 0,05 V evita valori casuali come 0,02–0,04 V quando non è collegato nulla. Ricorda che la risoluzione è di 24,4 mV: anche se vedi due decimali, l'ultima cifra cambia a passi di 0,02–0,03 V. Se ti serve una risoluzione più fine, restringi l'intervallo; con un partitore 0–10 V un passo scende a 10,7 mV.

Tensione di riferimento e calibrazione

Si dice spesso che i voltmetri con Arduino "misurano male", ma la vera fonte dell'errore di solito è il riferimento. Se nel codice c'è scritto 5,00 V e la scheda riceve 4,80 V dalla USB, ogni lettura è più alta del 4%: una batteria da 12,00 V appare come 12,50 V. Questa tensione cambia da un PC fisso a un portatile e da un cavo USB all'altro, e se alimenti la scheda con un alimentatore esterno entra in gioco il suo regolatore e il valore cambia di nuovo. Ci sono tre soluzioni: misurare il pin 5V e scriverlo nel codice, usare un riferimento interno fisso, oppure ricalcolare a ogni misura la tensione di alimentazione della scheda.

MetodoCodiceVantaggioAttenzione a
Predefinito (AVcc)analogReference(DEFAULT)Nessuna configurazione, intervallo completo 0–5 VQualsiasi variazione dell'alimentazione si ritrova nella lettura
Riferimento interno 1,1 VanalogReference(INTERNAL)Stabile e indipendente dall'alimentazioneVaria tra 1,0 e 1,2 V da scheda a scheda; il rapporto del partitore deve essere circa 23 (es. 220 kΩ + 10 kΩ)
Riferimento esterno (AREF)analogReference(EXTERNAL)Massima precisione con un riferimento come l'LM4040Questa riga deve essere eseguita prima di applicare tensione ad AREF, altrimenti va in corto con il riferimento interno
Misura dell'alimentazione (readVcc)Il codice qui sottoNessun componente in più, resta preciso anche se cambia la USB o la pilaFunziona solo sulle schede AVR (Uno, Nano, Pro Mini); calibra una volta il valore di 1,1 V
C++ (Arduino IDE)
1// Kendi besleme gerilimini ölçen voltmetre (ATmega328P: Uno, Nano, Pro Mini)
2// Voltmeter that measures its own supply (ATmega328P: Uno, Nano, Pro Mini)
3const int SENSE_PIN = A0;
4const float R1 = 30000.0;      // üst direnç / top resistor
5const float R2 = 7500.0;       // alt direnç / bottom resistor
6long bandgapMv = 1100;         // iç referans (mV), kalibrasyonla düzelt / internal reference (mV), fix by calibration
7
8long readVccMv() {
9  // Referans AVcc, ölçülen kanal iç 1,1 V / reference AVcc, measured channel is the internal 1.1 V
10  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
11  delay(2);                                  // referans otursun / let the reference settle
12  ADCSRA |= _BV(ADSC);                       // dönüşümü başlat / start a conversion
13  while (bit_is_set(ADCSRA, ADSC)) {}        // bitmesini bekle / wait until it finishes
14  unsigned int raw = ADCW;                   // 10 bit sonuç / 10-bit result
15  return bandgapMv * 1024L / raw;            // Vcc = 1,1 V x 1024 / okunan / Vcc = 1.1 V x 1024 / reading
16}
17
18float readVoltage(float vcc) {
19  analogRead(SENSE_PIN);                     // kanal değişti, ilk okumayı at / channel changed, discard first
20  unsigned long sum = 0;
21  for (int i = 0; i < 32; i++) sum += analogRead(SENSE_PIN);
22  float vPin = (sum / 32.0) * vcc / 1024.0;
23  return vPin * (R1 + R2) / R2;
24}
25
26void setup() {
27  Serial.begin(9600);
28}
29
30void loop() {
31  float vcc = readVccMv() / 1000.0;
32  float v = readVoltage(vcc);
33  Serial.print(F("Vcc: "));
34  Serial.print(vcc, 3);
35  Serial.print(F(" V   Giris / Input: "));
36  Serial.print(v, 2);
37  Serial.println(F(" V"));
38  delay(500);
39}
  1. Calibra il riferimento interno: esegui il codice readVcc e confronta il valore Vcc del Monitor seriale con quello che il multimetro misura sul pin 5V. Nuovo bandgapMv = 1100 × misurato / visualizzato. Per esempio, se la scheda mostra 5,12 V e il multimetro 4,98 V, scrivi 1100 × 4,98 / 5,12 ≈ 1070.
  2. Calibrazione a un punto: collega una tensione nota vicina al massimo dell'intervallo (es. 12 V). CAL = valore del multimetro / valore di Arduino. Questo coefficiente corregge anche l'errore di rapporto dovuto alla tolleranza delle resistenze.
  3. Calibrazione a due punti: se vedi uno scostamento fisso alle basse tensioni, misura in due punti, uno basso (es. 2 V) e uno alto (es. 20 V). Pendenza = (M2 − M1) / (A2 − A1), offset = M1 − pendenza × A1; il risultato è reale = pendenza × lettura + offset (M è il valore del multimetro, A quello di Arduino).
  4. Verifica: dopo la calibrazione controlla il risultato con una terza tensione a metà intervallo. Un voltmetro con Uno costruito con cura misura da 0 a 25 V con un errore inferiore all'1%.

Voltmetro digitale con display LCD

Display LCD 16x2 I2C
Grazie al modulo I2C sul retro, l'LCD 16x2 si collega con soli quattro fili: GND, VCC, SDA e SCL.

Per rendere il voltmetro indipendente dal computer basta scrivere il valore su un display LCD I2C. Collega GND del display a GND, VCC a 5V, SDA ad A4 e SCL ad A5. Installa dal Gestore librerie la libreria LiquidCrystal I2C (Frank de Brabander). L'indirizzo del display di solito è 0x27, su alcuni moduli 0x3F. Il codice seguente mostra la tensione istantanea sulla riga superiore e, su quella inferiore, il valore minimo e massimo dall'accensione; così cogli anche il calo di tensione di una batteria mentre gira un motore.

C++ (Arduino IDE)
1// LCD ekranlı dijital voltmetre (0-25 V, min/maks) / Digital voltmeter with LCD (0-25 V, min/max)
2// LCD: SDA -> A4, SCL -> A5, VCC -> 5V, GND -> GND; sensör S -> A0 / sensor S -> A0
3#include <Wire.h>
4#include <LiquidCrystal_I2C.h>
5
6LiquidCrystal_I2C lcd(0x27, 16, 2);   // adres 0x27 ya da 0x3F / address 0x27 or 0x3F
7
8const int SENSE_PIN = A0;
9const float VREF = 5.00;              // 5V pininde ölçülen / measured on the 5V pin
10const float RATIO = (30000.0 + 7500.0) / 7500.0;   // = 5,0
11const float CAL = 1.000;              // kalibrasyon katsayısı / calibration factor
12
13float vMin = 99.99;
14float vMax = 0.0;
15
16float readVoltage() {
17  analogRead(SENSE_PIN);
18  unsigned long sum = 0;
19  for (int i = 0; i < 32; i++) sum += analogRead(SENSE_PIN);
20  float v = (sum / 32.0) * VREF / 1024.0 * RATIO * CAL;
21  return v < 0.05 ? 0.0 : v;
22}
23
24void printField(float value) {
25  char buf[8];
26  dtostrf(value, 5, 2, buf);          // sabit genişlik: " 9.87" / fixed width: " 9.87"
27  lcd.print(buf);
28}
29
30void setup() {
31  lcd.init();
32  lcd.backlight();
33  lcd.print(F("Voltmetre 0-25V"));
34  delay(1000);
35  lcd.clear();
36}
37
38void loop() {
39  float v = readVoltage();
40  if (v > 0.5) {                      // boştayken min/maks güncelleme / don't update min/max when idle
41    if (v < vMin) vMin = v;
42    if (v > vMax) vMax = v;
43  }
44
45  lcd.setCursor(0, 0);
46  lcd.print(F("V: "));
47  printField(v);
48  lcd.print(F(" V      "));
49
50  lcd.setCursor(0, 1);
51  lcd.print(F("L"));
52  printField(vMin > 99.0 ? 0.0 : vMin);
53  lcd.print(F("  H"));
54  printField(vMax);
55  lcd.print(F("  "));
56  delay(300);
57}

Voltmetro con ESP32

L'ESP32 funziona a 3,3 V e i suoi pin non reggono più di 3,6 V, quindi per 0–25 V usa un partitore da 100 kΩ + 10 kΩ: 25 V in ingresso danno 2,27 V sul pin. Collega il partitore a uno dei pin ADC1 (GPIO 32–39); i pin ADC2 non funzionano mentre il Wi-Fi è attivo. L'ADC dell'ESP32 è a 12 bit ma non è lineare agli estremi: sotto 0,15 V non vede quasi nulla e sopra 2,5 V il suo errore cresce. La funzione analogReadMilliVolts() usa i dati di calibrazione scritti nel chip in fabbrica e restituisce un valore in millivolt molto più preciso del dato grezzo. Per eliminare lo scostamento residuo, il codice applica la calibrazione a due punti della sezione precedente con le costanti GAIN e OFFSET.

C++ (Arduino IDE)
1// ESP32 voltmetre: 100k + 10k bölücü ile 0-25 V / ESP32 voltmeter: 0-25 V with a 100k + 10k divider
2// Kaynak + -> 100k -> GPIO 34 -> 10k -> GND, kaynak - -> GND / source + -> 100k -> GPIO 34 -> 10k -> GND
3const int SENSE_PIN = 34;                 // ADC1_CH6, Wi-Fi açıkken de çalışır / works with Wi-Fi on
4const float RATIO = (100000.0 + 10000.0) / 10000.0;   // = 11,0
5const float GAIN = 1.000;                 // iki noktalı kalibrasyon: eğim / two-point calibration: slope
6const float OFFSET = 0.00;                // iki noktalı kalibrasyon: kayma (V) / two-point calibration: offset (V)
7
8float readVoltage() {
9  uint32_t mv = 0;
10  for (int i = 0; i < 64; i++) {
11    mv += analogReadMilliVolts(SENSE_PIN);   // fabrika kalibrasyonlu mV / factory-calibrated mV
12  }
13  float vPin = mv / 64.0 / 1000.0;           // pindeki gerilim (V) / voltage at the pin (V)
14  float v = vPin * RATIO * GAIN + OFFSET;
15  return v < 0.10 ? 0.0 : v;
16}
17
18void setup() {
19  Serial.begin(115200);
20  analogReadResolution(12);                  // 0-4095
21}
22
23void loop() {
24  float v = readVoltage();
25  Serial.printf("Gerilim / Voltage: %.2f V\n", v);
26  delay(500);
27}

Voltmetro con Raspberry Pi Pico (MicroPython)

Sul Raspberry Pi Pico gli ingressi analogici sono GP26, GP27 e GP28. Collega a GP26 lo stesso partitore da 100 kΩ + 10 kΩ usato con l'ESP32. In MicroPython read_u16() restituisce il risultato a 12 bit scalato su 0–65535. Il riferimento dell'ADC del Pico è filtrato dalla linea a 3,3 V; per una misura più precisa, misura tra ADC_VREF (pin 35) e GND con il multimetro e scrivi il valore in VREF. Nel codice c'è anche un bonus: sul Pico standard GP29 (ADC3) è collegato a un partitore interno che divide per 3 l'ingresso di alimentazione VSYS. Così, senza componenti aggiuntivi, leggi anche la tensione della batteria che alimenta il Pico. Su Pico W e Pico 2 W il GP29 è condiviso con il chip wireless, quindi questa riga lì non funziona direttamente.

MicroPython
1# Raspberry Pi Pico voltmetre (MicroPython) / Raspberry Pi Pico voltmeter (MicroPython)
2# Kaynak + -> 100k -> GP26 -> 10k -> GND / source + -> 100k -> GP26 -> 10k -> GND
3from machine import ADC
4import time
5
6sense = ADC(26)            # GP26 = ADC0 (pin 31)
7vsys = ADC(29)             # GP29 = VSYS / 3 (yalnız standart Pico / standard Pico only)
8VREF = 3.3                 # ADC_VREF; multimetreyle ölçüp düzelt / measure and correct with a multimeter
9RATIO = (100000 + 10000) / 10000    # = 11.0
10GAIN = 1.000               # iki noktalı kalibrasyon: eğim / two-point calibration: slope
11OFFSET = 0.00              # iki noktalı kalibrasyon: kayma (V) / two-point calibration: offset (V)
12
13
14def pin_voltage(adc, samples=64):
15    total = 0
16    for _ in range(samples):
17        total += adc.read_u16()            # 0-65535
18    return total / samples * VREF / 65535  # pindeki gerilim / voltage at the pin
19
20
21while True:
22    v_in = pin_voltage(sense) * RATIO * GAIN + OFFSET
23    if v_in < 0.05:
24        v_in = 0.0
25    v_sys = pin_voltage(vsys) * 3          # VSYS = GP29 x 3
26    print("Giris / Input: {:.2f} V   VSYS: {:.2f} V".format(v_in, v_sys))
27    time.sleep(0.5)

Aggiungere la corrente per fare un wattmetro: ACS712 o INA219

Modulo sensore di corrente ACS712
L'ACS712 misura la corrente con l'effetto Hall e isola elettricamente il circuito misurato da Arduino.

Quando aggiungi la misura di corrente a un voltmetro ottieni anche la potenza: P = V × I. Se una batteria da 12 V eroga 1,5 A, la potenza è 18 W. Sommando la potenza nel tempo ottieni l'energia: un carico da 18 W acceso per 2 ore consuma 36 Wh. Ci sono due opzioni comuni. L'ACS712 ha un'uscita analogica, misura anche la corrente alternata e offre isolamento; si aggiunge al voltmetro come secondo canale analogico. L'INA219 è un misuratore di potenza in continua che misura tensione e corrente nello stesso chip con precisione a 12 bit e comunica via I2C; da solo è già un wattmetro completo.

CaratteristicaModulo di tensione + ACS712 (5A)Modulo INA219
Intervallo di tensione0–25 V (dato dal partitore)0–26 V (all'interno del chip)
Intervallo di corrente±5 A±3,2 A (con shunt da 0,1 Ω)
Risoluzione in correnteCirca 26 mA su un Uno0,1 mA
Corrente alternataSìNo
CollegamentoDue pin analogiciI2C (SDA, SCL), indirizzo 0x40
Ideale perMotori, corrente lato rete e dove serve isolamentoPiccole potenze in continua: batterie, pannelli solari, dispositivi USB
C++ (Arduino IDE)
1// INA219 + I2C LCD ile wattmetre: V, A, W ve Wh / Wattmeter with INA219 + I2C LCD: V, A, W and Wh
2// Kaynak + -> INA219 VIN+ ; INA219 VIN- -> yük + ; yük - -> kaynak - -> Arduino GND
3// Source + -> INA219 VIN+ ; INA219 VIN- -> load + ; load - -> source - -> Arduino GND
4#include <Wire.h>
5#include <Adafruit_INA219.h>
6#include <LiquidCrystal_I2C.h>
7
8Adafruit_INA219 ina219;               // varsayılan adres 0x40 / default address 0x40
9LiquidCrystal_I2C lcd(0x27, 16, 2);
10
11float energyWh = 0.0;
12unsigned long lastMs = 0;
13
14void printField(float value, int width, int decimals) {
15  char buf[10];
16  dtostrf(value, width, decimals, buf);
17  lcd.print(buf);
18}
19
20void setup() {
21  Serial.begin(9600);
22  lcd.init();
23  lcd.backlight();
24  if (!ina219.begin()) {              // modül bulunamadı / module not found
25    lcd.print(F("INA219 yok!"));
26    while (true) delay(10);
27  }
28  // ina219.setCalibration_16V_400mA();  // küçük akımlar için daha hassas / finer for small currents
29  lastMs = millis();
30}
31
32void loop() {
33  float busV = ina219.getBusVoltage_V();           // VIN- ile GND arası / between VIN- and GND
34  float shuntMv = ina219.getShuntVoltage_mV();     // şönt üzerindeki düşüm / drop across the shunt
35  float loadV = busV + shuntMv / 1000.0;           // kaynağın gerilimi / source voltage
36  float currentA = ina219.getCurrent_mA() / 1000.0;
37  float powerW = loadV * currentA;
38
39  unsigned long now = millis();
40  energyWh += powerW * (now - lastMs) / 3600000.0; // W x saat = Wh / W x hours = Wh
41  lastMs = now;
42
43  lcd.setCursor(0, 0);
44  printField(loadV, 5, 2);  lcd.print(F("V "));
45  printField(currentA, 6, 3); lcd.print(F("A  "));
46  lcd.setCursor(0, 1);
47  printField(powerW, 6, 2); lcd.print(F("W "));
48  printField(energyWh, 6, 2); lcd.print(F("Wh"));
49
50  Serial.print(loadV, 2);    Serial.print(F(" V, "));
51  Serial.print(currentA, 3); Serial.print(F(" A, "));
52  Serial.print(powerW, 2);   Serial.print(F(" W, "));
53  Serial.print(energyWh, 3); Serial.println(F(" Wh"));
54  delay(500);
55}

L'INA219 ricava la corrente dalla piccola caduta di tensione sulla resistenza di shunt da 0,1 Ω tra VIN+ e VIN−, quindi il modulo va collegato in serie sul lato positivo della sorgente (lato alto). Dato che la tensione di bus è misurata tra VIN− e GND, il codice aggiunge la caduta sullo shunt per ottenere la tensione reale della sorgente. La calibrazione predefinita è per 32 V e 2 A; se misurerai solo qualche centinaio di milliampere, attiva la riga setCalibration_16V_400mA() per restringere l'intervallo a 400 mA e migliorare la precisione con le correnti piccole. L'energia si ottiene sommando a ogni ciclo la potenza del momento moltiplicata per il tempo trascorso; si azzera quando spegni Arduino, quindi per conservarla scrivi il valore a intervalli nella EEPROM. Il codice che fa lo stesso calcolo con l'ACS712 è nella sezione su potenza ed energia dell'articolo sull'ACS712.

Tester di batterie: un voltmetro che misura la capacità (mAh)

Batteria agli ioni di litio 18650
La capacità stampata su una cella 18650 e quella reale spesso non coincidono; il tester lo rivela.

La tensione di una batteria non dice con precisione quanta energia le resta; anche una cella carica ma usurata può segnare 4,1 V. Per conoscere la capacità reale si scarica la batteria su un carico noto e si somma la corrente nel tempo: mAh = Σ (corrente × tempo). In questo circuito un MOSFET accende e spegne il carico, e Arduino misura una volta al secondo la tensione della batteria e quella all'estremo inferiore della resistenza di carico. La differenza tra le due, divisa per la resistenza di carico, dà la corrente. Quando la batteria arriva alla tensione di cut-off, il MOSFET si spegne e viene mostrato il risultato. All'inizio il codice confronta anche la tensione a vuoto e sotto carico per calcolare la resistenza interna; più è alta, più la tensione della batteria crolla con correnti elevate.

ComponenteCollegamentoNota
Batteria +Ad A0 tramite 10 kΩ; anche all'estremo superiore della resistenza di caricoMetti 100 nF tra A0 e GND
Resistenza di carico da 4,7 ΩTra batteria + e il drain del MOSFETResistenza a cemento da almeno 5 W (meglio 10 W); con una 18650 passano circa 0,9 A e scalda
Drain del MOSFETEstremo inferiore della resistenza di carico; ad A1 tramite 10 kΩMetti 100 nF anche tra A1 e GND
Source del MOSFETGNDQui va anche il negativo della batteria
Gate del MOSFETA D9 tramite 220 Ω; a GND con 100 kΩUsa un MOSFET logic-level come l'IRLZ44N
C++ (Arduino IDE)
1// Pil kapasite test cihazı: mAh, Wh ve iç direnç / Battery capacity tester: mAh, Wh and internal resistance
2// Pil + -> 10k -> A0 ; pil + -> 4,7 ohm yük -> MOSFET drain ; drain -> 10k -> A1
3// Battery + -> 10k -> A0 ; battery + -> 4.7 ohm load -> MOSFET drain ; drain -> 10k -> A1
4// MOSFET source -> GND ; gate <- D9 (220 ohm), gate -> 100k -> GND ; pil - / battery - -> GND
5const int BAT_PIN = A0;
6const int DRAIN_PIN = A1;
7const int LOAD_PIN = 9;
8const float VREF = 5.00;        // 5V pininde ölçülen / measured on the 5V pin
9const float R_LOAD = 4.7;       // yük direnci, multimetreyle ölç / load resistor, measure it
10const float CUTOFF_V = 3.00;    // Li-ion 3,00 V ; alkalin AA / alkaline AA 0,90 V
11
12float mAh = 0.0;
13float wh = 0.0;
14unsigned long lastMs = 0;
15unsigned long startMs = 0;
16bool running = false;
17
18float readPin(int pin) {
19  analogRead(pin);                          // kanal değişti, ilk okumayı at / discard first reading
20  unsigned long sum = 0;
21  for (int i = 0; i < 32; i++) sum += analogRead(pin);
22  return (sum / 32.0) * VREF / 1024.0;
23}
24
25float loadCurrent(float vBat) {
26  return (vBat - readPin(DRAIN_PIN)) / R_LOAD;   // dirençteki gerilim / R / voltage across R / R
27}
28
29void setup() {
30  Serial.begin(9600);
31  pinMode(LOAD_PIN, OUTPUT);
32  digitalWrite(LOAD_PIN, LOW);              // yük kapalı / load off
33  delay(1000);
34
35  float vOpen = readPin(BAT_PIN);           // yüksüz gerilim / open-circuit voltage
36  if (vOpen < CUTOFF_V + 0.1) {
37    Serial.println(F("Pil zayif ya da takili degil / Battery low or missing"));
38    return;
39  }
40  digitalWrite(LOAD_PIN, HIGH);             // yükü aç / load on
41  delay(1000);
42  float vLoad = readPin(BAT_PIN);
43  float amps = loadCurrent(vLoad);
44  Serial.print(F("Bos / Open: "));
45  Serial.print(vOpen, 3);
46  Serial.print(F(" V  Yuklu / Loaded: "));
47  Serial.print(vLoad, 3);
48  Serial.print(F(" V  Ic direnc / Internal R: "));
49  Serial.print((vOpen - vLoad) / amps * 1000.0, 0);
50  Serial.println(F(" mOhm"));
51
52  running = true;
53  startMs = lastMs = millis();
54}
55
56void loop() {
57  if (!running) return;
58  unsigned long now = millis();
59  if (now - lastMs < 1000) return;          // saniyede bir ölç / measure once per second
60
61  float hours = (now - lastMs) / 3600000.0;
62  lastMs = now;
63  float vBat = readPin(BAT_PIN);
64  float amps = loadCurrent(vBat);
65  mAh += amps * 1000.0 * hours;             // akım x süre / current x time
66  wh += vBat * amps * hours;
67
68  Serial.print((now - startMs) / 1000);
69  Serial.print(F(" s  "));
70  Serial.print(vBat, 3);
71  Serial.print(F(" V  "));
72  Serial.print(amps, 3);
73  Serial.print(F(" A  "));
74  Serial.print(mAh, 0);
75  Serial.println(F(" mAh"));
76
77  if (vBat <= CUTOFF_V) {                   // kesme gerilimi / cut-off voltage
78    digitalWrite(LOAD_PIN, LOW);
79    running = false;
80    Serial.print(F("Bitti / Done: "));
81    Serial.print(mAh, 0);
82    Serial.print(F(" mAh, "));
83    Serial.print(wh, 2);
84    Serial.println(F(" Wh"));
85  }
86}

Con un carico da 4,7 Ω una cella 18650 si scarica con una corrente che parte da circa 0,9 A e scende verso 0,65 A; il test di una cella sana da 2500 mAh dura circa tre ore. Per il litio non impostare mai il cut-off sotto 3,0 V, altrimenti la cella si danneggia. Se provi una pila alcalina AA, imposta CUTOFF_V a 0,9 V; con lo stesso carico assorbe circa 0,3 A. Puoi confrontare il risultato con l'etichetta e con il calcolatore di durata della batteria. La resistenza interna di una 18650 nuova misurata così, portapile e cavi compresi, di solito è sotto 0,15 Ω; una cella sopra 0,3 Ω non andrebbe usata dove servono correnti elevate. Per capire le unità di capacità, dai un'occhiata all'articolo su mAh e capacità della batteria.

Non cortocircuitare mai le celle al litio e non appoggiare la resistenza di carico su una superficie infiammabile; una resistenza che dissipa circa 4 W può arrivare a 80–100 °C. Non lasciare il test senza sorveglianza e non provare mai celle gonfie o ammaccate.

Idee di progetti con un voltmetro con Arduino

  • Monitor della batteria con allarme di bassa tensione: controlla la batteria a 12 V di un camper o di un impianto solare e fai suonare un buzzer quando scende sotto 11,8 V.
  • Logger per pannello solare: scrivi ogni minuto su una scheda SD la tensione del pannello e, con l'INA219, la sua corrente, poi calcola la produzione giornaliera in Wh.
  • Indicatore per alimentatore da banco: aggiungi un voltmetro e un INA219 all'uscita di un modulo LM2596 per trasformarlo in un alimentatore da laboratorio.
  • Monitoraggio remoto della batteria: invia la tensione misurata con un ESP32 a Home Assistant via MQTT, oppure ricevi un messaggio Telegram quando è bassa.
  • Controllo di pacchi 18650: misura la capacità delle celle che ricarichi con un TP4056 e abbina celle di capacità simile per costruire un pacco bilanciato.
  • Display a cifre grandi: mostra il valore su un display a 7 segmenti o un display OLED invece che sull'LCD, abbastanza grande da leggerlo da lontano.

Errori comuni e come risolverli

SintomoCausa probabileSoluzione
La lettura è sempre più alta o più bassa del 2–5%Nel codice VREF è 5,00 V ma la scheda è alimentata con un'altra tensioneMisura il pin 5V e scrivilo in VREF, oppure usa il metodo readVcc
Il valore salta continuamenteIl negativo della sorgente non è collegato al GND di Arduino o la linea è rumorosaCollega una massa comune, fai la media, aggiungi 100 nF sul pin
Con tensioni alte resta bloccato sullo stesso valoreIl pin ha raggiunto il riferimento e l'ADC è saturo a 1023Allarga l'intervallo aumentando il rapporto del partitore
La lettura si piega in alto e non è lineareDispersione dello zener o parte alta dell'ADC dell'ESP32Tieni il pin sotto 4 V (2,5 V sull'ESP32) o usa uno Schottky
Sull'ESP32 la lettura va a 0 o si blocca quando parte il Wi-FiIl partitore è su un pin ADC2Usa uno dei pin ADC1, GPIO 32–39
L'INA219 mostra corrente negativaVIN+ e VIN− sono invertitiIl positivo della sorgente va su VIN+, quello del carico su VIN−
L'LCD è acceso ma non mostra testoIndirizzo I2C o contrasto sbagliatiTrova l'indirizzo con uno scanner I2C e ruota il trimmer sul retro
Prima di collegare ad Arduino un partitore appena montato, accendi la sorgente e misura la tensione del punto centrale con il multimetro. Se è vicina al valore calcolato e sotto il riferimento, puoi collegarla al pin in sicurezza. Questo controllo di dieci secondi evita che due resistenze scambiate brucino la scheda.

Un voltmetro con Arduino è uno dei modi migliori per capire come funziona una misura: con due resistenze, una formula e un po' di calibrazione ottieni risultati vicini a quelli di un multimetro; aggiungi un sensore di corrente e diventa un wattmetro, aggiungi un MOSFET e diventa un tester di batterie. Nell'app BlueGrays il progetto "Voltmetro digitale con LCD" ti permette di costruire lo stesso circuito passo passo con schema e codice pronto, e da lì passare ai progetti di monitoraggio delle batterie e misura della potenza.

Domande frequenti

Quanti volt può misurare Arduino?

Su un pin analogico puoi collegare direttamente al massimo 5 V (3,3 V su ESP32 e Pico). Con un partitore di tensione questo limite si può alzare quanto vuoi: con 30 kΩ + 7,5 kΩ misuri 25 V, con 100 kΩ + 10 kΩ 50 V. Oltre qualche decina di volt però sicurezza e isolamento diventano importanti, e la tensione di rete non si misura mai così.

Perché il mio voltmetro con Arduino misura male?

La causa più comune è la tensione di riferimento: nel codice c'è 5,00 V ma la scheda riceve 4,7–4,9 V dalla USB, quindi tutte le letture si spostano della stessa proporzione. Altre cause sono resistenze al 5%, la mancanza di una massa comune e un partitore con resistenza troppo alta. Si risolve misurando il pin 5V e scrivendolo nel codice, o usando il metodo readVcc, e poi regolando il coefficiente CAL con una tensione nota.

Si può usare il modulo sensore di tensione 0–25 V con un ESP32?

Sì, ma con attenzione. Dato che il modulo divide per 5, con un ESP32 misuri al massimo 16,5 V; se tocchi 25 V sul pin arrivano 5 V e l'ESP32 si danneggia. Costruire un partitore da 100 kΩ + 10 kΩ è più sicuro e anche più preciso, perché l'ADC resta nella sua zona lineare.

Si può misurare la tensione di rete a 230 V con Arduino?

Mai con un partitore di tensione: è potenzialmente letale e collega Arduino alla rete. Per la tensione di rete si usano moduli come lo ZMPT101B, che contiene un piccolo trasformatore e garantisce l'isolamento galvanico. La sua uscita è alternata, quindi il codice calcola il valore efficace (RMS).

Arduino può misurare tensioni negative?

Non direttamente; un pin analogico non legge sotto GND e può danneggiarsi. La soluzione è spostare il segnale verso 5 V con delle resistenze: per esempio due resistenze uguali tra il segnale e 5 V creano un punto centrale che porta l'intervallo da −5 V a +5 V su 0–5 V. Per lavori più precisi si usa un traslatore di livello con amplificatore operazionale.

Un voltmetro con Arduino può essere preciso come un multimetro?

Un voltmetro con Uno calibrato misura da 0 a 25 V con un errore inferiore all'1%, sufficiente per la maggior parte dei progetti e vicino a un multimetro economico. A causa dell'ADC a 10 bit la risoluzione è limitata a circa 24 mV su un intervallo di 25 V. Per risultati migliori puoi usare un ADC esterno a 16 bit come l'ADS1115, resistenze allo 0,1% e un riferimento di precisione.

Vedi tutti i progetti
Misurare l'intensità luminosa con LDR
#11Principiante

Misurare l'intensità luminosa con LDR

Vuoi vedere quanto è luminosa la tua stanza sotto forma di numero? L'LDR, un piccolo componente sensibile alla luce, misura la luce ambiente e l'Arduino scrive il valore sullo schermo del computer ogn

4.6(81)
139
Lettura dell'intensità luminosa con il modulo LDR ESP32
#113Principiante

Lettura dell'intensità luminosa con il modulo LDR ESP32

Monitoraggio in tempo reale sul Serial Monitor del valore grezzo dell'ADC del modulo LDR e della percentuale relativa di luce calcolata dai valori di riferimento al buio e alla luce. Questa percentuale non è una misurazione in lux. Spiega il principio di calibrazione del modulo. È consigliabile eseguirlo prima del Progetto 10, poiché serve a determinare il valore di soglia.

4.6(36)
55
Voltmetro digitale con display LCD
#56Intermedio
Premium

Voltmetro digitale con display LCD

Scopri quanta tensione dà una pila o un alimentatore con uno strumento costruito da te. Un partitore fatto di due resistenze abbassa la tensione alta a un livello che la scheda può leggere, e l'Arduin

4.5(27)
36
Misura di temperatura con NTC e display Lcd 2x16
#44Principiante
Premium

Misura di temperatura con NTC e display Lcd 2x16

Misura la temperatura dell'ambiente con un sensore che sembra una piccola perlina. Questo componente, chiamato NTC, fa passare la corrente sempre più facilmente man mano che si scalda; l'Arduino legge

4.5(33)
44
Utilizzo dello schermo LCD con I2C
#32Principiante
Premium

Utilizzo dello schermo LCD con I2C

Regala al tuo Arduino uno schermo tutto suo e fagli scrivere il primo messaggio. Lo schermo LCD a due righe si collega con pochi fili; prima compare un saluto nella riga in alto, poi un secondo testo

4.8(53)
70
Schermo LCD I2C per ESP32 (16x2)
#119Intermedio
Premium

Schermo LCD I2C per ESP32 (16x2)

In questo progetto visualizziamo del testo collegando un display LCD a 16x2 caratteri all'ESP32 tramite il protocollo I2C. Grazie all'I2C possiamo controllare il display utilizzando solo 2 pin di dati (SDA e SCL); si elimina così lo spreco dei 6+ pin tipici del collegamento parallelo classico. Il codice stampa un messaggio fisso sulla prima riga e un contatore che aumenta ogni secondo sulla seconda riga. Inoltre, all'inizio, eseguendo lo scanner I2C, stampiamo l'indirizzo del display sul Serial

4.9(23)
40
Misurazione della distanza tramite display LCD
#31Avanzato
Premium

Misurazione della distanza tramite display LCD

Uno strumento che misura le distanze senza righello: muovi la mano avanti e indietro davanti al sensore e guarda il numero cambiare. L'HC-SR04 manda un'onda sonora e ascolta l'eco, e l'Arduino calcola

4.6(45)
59
Luminosità di un LED con Potenziometro su ESP32 (Analogico → PWM)
#115Intermedio
Premium

Luminosità di un LED con Potenziometro su ESP32 (Analogico → PWM)

In questo progetto controlliamo in modo analogico la luminosità di un LED tramite un potenziometro. Il pin ADC dell'ESP32 legge la tensione tra 0 e 3,3 V dal potenziometro; il valore viene convertito in un segnale PWM (Pulse Width Modulation) e inviato al LED. Ruotando il potenziometro, il LED si accende e si spegne gradualmente. Con Arduino Core 3.0+ si usa direttamente analogWrite(); su ESP32-S2/S3 la risoluzione dell'ADC è fissata a 12 bit.

4.5(19)
32