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.

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.
| Scheda | ADC | Riferimento | 1 passo sul pin | 1 passo con partitore 0–25 V |
|---|---|---|---|---|
| Arduino Uno, Nano, Pro Mini | 10 bit (0–1023) | 5 V (AVcc) | 4,88 mV | 24,4 mV (30 kΩ + 7,5 kΩ) |
| ESP32 | 12 bit (0–4095) | Circa 3,3 V (attenuazione 11 dB) | Circa 0,8 mV | Circa 9 mV (100 kΩ + 10 kΩ) |
| Raspberry Pi Pico | 12 bit (0–65535 con read_u16) | 3,3 V (ADC_VREF) | 0,81 mV | 8,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.
| Intervallo | Arduino Uno (5 V): R1 + R2 | Pin a fondo scala | ESP32 / Pico (3,3 V): R1 + R2 | Pin a fondo scala |
|---|---|---|---|---|
| 0–10 V | 12 kΩ + 10 kΩ | 4,55 V | 33 kΩ + 10 kΩ | 2,33 V |
| 0–25 V | 30 kΩ + 7,5 kΩ (modulo pronto) | 5,00 V | 100 kΩ + 10 kΩ | 2,27 V |
| 0–30 V | 56 kΩ + 10 kΩ | 4,55 V | 120 kΩ + 10 kΩ | 2,31 V |
| 0–50 V | 100 kΩ + 10 kΩ | 4,55 V | 220 kΩ + 10 kΩ | 2,17 V |
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.
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 modulo | Funzione | Arduino Uno | ESP32 (partitore tuo) | Raspberry Pi Pico (partitore tuo) |
|---|---|---|---|---|
| VCC (morsetto) | Positivo della sorgente da misurare | Sorgente + | Estremo superiore di R1 | Estremo superiore di R1 |
| GND (morsetto) | Negativo della sorgente da misurare | Sorgente − | Sorgente − e GND | Sorgente − e GND |
| S | Segnale diviso | A0 | GPIO 34 (ADC1) | GP26 (ADC0, pin 31) |
| + | Non collegato nella maggior parte dei moduli | Non collegare | - | - |
| − | GND del modulo | GND | GND | GND (es. pin 33) |
Passo passo: il tuo primo voltmetro con Arduino
- 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.
- 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.
- Scrivi il valore misurato nella costante VREF del codice qui sotto e caricalo.
- 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.
- Apri il Monitor seriale a 9600 baud. Leggi la tensione e intanto misura la sorgente con il multimetro per confrontare i due valori.
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.
| Metodo | Codice | Vantaggio | Attenzione a |
|---|---|---|---|
| Predefinito (AVcc) | analogReference(DEFAULT) | Nessuna configurazione, intervallo completo 0–5 V | Qualsiasi variazione dell'alimentazione si ritrova nella lettura |
| Riferimento interno 1,1 V | analogReference(INTERNAL) | Stabile e indipendente dall'alimentazione | Varia 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'LM4040 | Questa 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 sotto | Nessun componente in più, resta preciso anche se cambia la USB o la pila | Funziona solo sulle schede AVR (Uno, Nano, Pro Mini); calibra una volta il valore di 1,1 V |
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}- 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.
- 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.
- 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).
- 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

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.
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.
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.
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

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.
| Caratteristica | Modulo di tensione + ACS712 (5A) | Modulo INA219 |
|---|---|---|
| Intervallo di tensione | 0–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 corrente | Circa 26 mA su un Uno | 0,1 mA |
| Corrente alternata | Sì | No |
| Collegamento | Due pin analogici | I2C (SDA, SCL), indirizzo 0x40 |
| Ideale per | Motori, corrente lato rete e dove serve isolamento | Piccole potenze in continua: batterie, pannelli solari, dispositivi USB |
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)

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.
| Componente | Collegamento | Nota |
|---|---|---|
| Batteria + | Ad A0 tramite 10 kΩ; anche all'estremo superiore della resistenza di carico | Metti 100 nF tra A0 e GND |
| Resistenza di carico da 4,7 Ω | Tra batteria + e il drain del MOSFET | Resistenza a cemento da almeno 5 W (meglio 10 W); con una 18650 passano circa 0,9 A e scalda |
| Drain del MOSFET | Estremo inferiore della resistenza di carico; ad A1 tramite 10 kΩ | Metti 100 nF anche tra A1 e GND |
| Source del MOSFET | GND | Qui va anche il negativo della batteria |
| Gate del MOSFET | A D9 tramite 220 Ω; a GND con 100 kΩ | Usa un MOSFET logic-level come l'IRLZ44N |
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.
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
| Sintomo | Causa probabile | Soluzione |
|---|---|---|
| La lettura è sempre più alta o più bassa del 2–5% | Nel codice VREF è 5,00 V ma la scheda è alimentata con un'altra tensione | Misura il pin 5V e scrivilo in VREF, oppure usa il metodo readVcc |
| Il valore salta continuamente | Il negativo della sorgente non è collegato al GND di Arduino o la linea è rumorosa | Collega una massa comune, fai la media, aggiungi 100 nF sul pin |
| Con tensioni alte resta bloccato sullo stesso valore | Il pin ha raggiunto il riferimento e l'ADC è saturo a 1023 | Allarga l'intervallo aumentando il rapporto del partitore |
| La lettura si piega in alto e non è lineare | Dispersione dello zener o parte alta dell'ADC dell'ESP32 | Tieni 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-Fi | Il partitore è su un pin ADC2 | Usa uno dei pin ADC1, GPIO 32–39 |
| L'INA219 mostra corrente negativa | VIN+ e VIN− sono invertiti | Il positivo della sorgente va su VIN+, quello del carico su VIN− |
| L'LCD è acceso ma non mostra testo | Indirizzo I2C o contrasto sbagliati | Trova l'indirizzo con uno scanner I2C e ruota il trimmer sul retro |
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.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
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

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.

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

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

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

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

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

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.
Altri articoli
App BlueGrays
Costruisci questo circuito passo passo sul telefono
Schema, codice ed elenco componenti in un’unica schermata. Oltre 200 progetti Arduino, ESP32 e Pico da realizzare.
Inquadra con il telefono
Punta la fotocamera sul codice: si apre lo store del tuo telefono.
oppure apri lo store

