Voltímetro con Arduino: medir 0–25 V con LCD y calibración
Cómo hacer un voltímetro con Arduino: medir 0–25 V con divisor, elegir resistencias, protección zener, calibración, LCD, vatímetro INA219 y probador.
Un voltímetro con Arduino es un instrumento de medida que puedes montar en una tarde: dos resistencias, una entrada analógica y unas pocas líneas de código bastan para medir con precisión de 0 a 25 V y mostrarlo en una pantalla. Las entradas analógicas de Arduino leen como máximo 5 V, así que para medir una tensión mayor primero la reduces con un divisor de voltaje y luego la vuelves a escalar en el código con la misma relación. Los monitores de batería, los indicadores de fuentes de alimentación, los registradores de paneles solares y los probadores de pilas se basan en esta misma idea.
En esta guía verás paso a paso cómo elegir las resistencias según el rango de medida, cómo un diodo zener y una resistencia en serie protegen la entrada analógica de sobretensiones, cómo funciona el módulo sensor de voltaje de 0–25 V y cómo el ajuste de la tensión de referencia y la calibración acercan tus lecturas a las de un multímetro. Después mostrarás el valor en una pantalla LCD I2C, montarás el mismo voltímetro con un ESP32 y una Raspberry Pi Pico, añadirás medición de corriente con un INA219 para convertirlo en vatímetro y, por último, construirás un probador que mide la capacidad real de una batería en mAh.

¿Cómo funciona un voltímetro con Arduino?
Arduino no conoce la tensión directamente: su ADC (convertidor analógico-digital) compara la tensión de la entrada analógica con una tensión de referencia y devuelve el resultado como un número entero. El ADC del Arduino Uno es de 10 bits: lee 0 para 0 V y 1023 para la tensión de referencia (5 V por defecto). La tensión en el pin es Vpin = lectura × Vref / 1024. Si hay un divisor de voltaje en la entrada, la tensión que realmente mides es Vent = Vpin × (R1 + R2) / R2. Así que la precisión de todo el voltímetro depende de tres cosas: el valor real de Vref, la relación entre las dos resistencias y el error propio del ADC.
| Placa | ADC | Referencia | 1 paso en el pin | 1 paso con divisor de 0–25 V |
|---|---|---|---|---|
| Arduino Uno, Nano, Pro Mini | 10 bits (0–1023) | 5 V (AVcc) | 4,88 mV | 24,4 mV (30 kΩ + 7,5 kΩ) |
| ESP32 | 12 bits (0–4095) | Unos 3,3 V (atenuación de 11 dB) | Unos 0,8 mV | Unos 9 mV (100 kΩ + 10 kΩ) |
| Raspberry Pi Pico | 12 bits (0–65535 con read_u16) | 3,3 V (ADC_VREF) | 0,81 mV | 8,9 mV (100 kΩ + 10 kΩ) |
Divisor de voltaje y elección de resistencias para 0–25 V
La tensión que mides entra por la resistencia superior R1, el punto medio donde se unen las dos resistencias va al pin analógico y la resistencia inferior R2 va a GND. Para elegirlas, primero decide la tensión máxima y luego busca una relación que deje el pin un poco por debajo de la referencia a esa tensión, por ejemplo unos 4,5 V en un Uno. La pareja de 30 kΩ y 7,5 kΩ de los módulos comerciales divide exactamente entre 5: 25 V en la entrada dan 5,00 V en el pin. Tampoco elijas los valores al azar: si la resistencia total es muy baja, el divisor consume corriente inútilmente de la fuente que mides; si es muy alta, el condensador de muestreo interno del ADC no llega a cargarse y la lectura se desvía. La hoja de datos del ATmega328P recomienda que la fuente que alimenta una entrada analógica no supere los 10 kΩ; en un divisor, esa resistencia es R1 en paralelo con R2 (6 kΩ para 30 kΩ y 7,5 kΩ). La fórmula en detalle y el efecto de carga están en el artículo sobre el divisor de voltaje.
| Rango | Arduino Uno (5 V): R1 + R2 | Pin a fondo de escala | ESP32 / Pico (3,3 V): R1 + R2 | Pin a fondo de escala |
|---|---|---|---|---|
| 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Ω (módulo comercial) | 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 |
Protección: diodo zener, resistencia en serie y condensador
Aunque el divisor esté bien calculado, una punta equivocada, un pico en la fuente o tocar por error 48 V en lugar de 25 V pueden subir el pin por encima de 5 V. Los pines del ATmega328P soportan como máximo la alimentación más 0,5 V. Dentro del pin hay diodos de protección hacia 5 V y GND, pero solo aguantan corrientes pequeñas. La buena noticia es que la resistencia superior del divisor ya limita la corriente. Con una R1 de 30 kΩ, aunque toques 50 V, al pin le llega como mucho 1,5 mA. Para reducir aún más esa corriente y absorber el exceso de tensión con seguridad, puedes añadir estas capas.
- Resistencia en serie: Coloca una resistencia de 4,7–10 kΩ entre el punto medio del divisor y el pin analógico. Ante una sobretensión, la corriente hacia los diodos internos del pin baja a microamperios.
- Condensador de 100 nF: Conéctalo entre el pin analógico y GND. Compensa la mayor resistencia de fuente que añade la resistencia en serie, porque el ADC toma de este condensador la carga que necesita al muestrear. Además filtra el ruido y los picos cortos.
- Diodo zener de 5,1 V: Conecta un zener como el 1N4733A o el BZX55C5V1 con el cátodo al pin y el ánodo a GND. Cuando la tensión intenta superar 5,1 V, el zener conduce y desvía el exceso a GND.
- Cuidado con la fuga del zener: Un zener empieza a consumir una pequeña corriente algo por debajo de su tensión de ruptura, y con un divisor de alta resistencia esa corriente baja la lectura. Si usas zener, mantén el máximo del pin en torno a 4 V, o usa en su lugar un diodo Schottky (BAT85) del pin a la línea de 5 V.
- Polaridad invertida: Si conectas las puntas al revés, al pin le llega tensión negativa. La resistencia en serie limita la corriente; para más seguridad puedes añadir un segundo diodo Schottky con el ánodo a GND y el cátodo al pin.
El módulo sensor de voltaje (0–25 V)
Si no quieres soldar, puedes usar el pequeño módulo rojo o azul que se vende como "voltage sensor". No tiene nada mágico: un divisor formado por exactamente una resistencia de 30 kΩ y otra de 7,5 kΩ, una bornera de tornillo y un conector de tres pines. Como la relación es 5, con un Arduino de 5 V mides de 0 a 25 V, pero con una placa de 3,3 V solo hasta 16,5 V. En una placa de 3,3 V, tocar 25 V pone 5 V en el pin y lo daña, así que para ESP32 y Pico es más seguro montar tu propio divisor de la tabla anterior. El módulo no lleva diodo de protección, por lo que las medidas con zener o Schottky de la sección anterior también se aplican aquí.
| Pin del módulo | Función | Arduino Uno | ESP32 (tu propio divisor) | Raspberry Pi Pico (tu propio divisor) |
|---|---|---|---|---|
| VCC (bornera) | Positivo de la fuente a medir | Fuente + | Extremo superior de R1 | Extremo superior de R1 |
| GND (bornera) | Negativo de la fuente a medir | Fuente − | Fuente − y GND | Fuente − y GND |
| S | Señal dividida | A0 | GPIO 34 (ADC1) | GP26 (ADC0, pin 31) |
| + | Sin conexión en la mayoría de módulos | No conectar | - | - |
| − | GND del módulo | GND | GND | GND (p. ej. pin 33) |
Paso a paso: tu primer voltímetro con Arduino
- Conecta el pin S del módulo a A0 y el pin − a GND. Si montas tu propio divisor, pon la de 30 kΩ del lado de la fuente y la de 7,5 kΩ del lado de GND, y lleva el punto medio a A0.
- Conecta el Arduino por USB, mide con el multímetro entre el pin 5V y GND y apunta el valor. La tensión del USB suele estar entre 4,7 y 5,1 V.
- Escribe el valor medido en la constante VREF del código de abajo y súbelo.
- Conecta la fuente que quieres medir a la bornera del módulo: positivo a VCC, negativo a GND. Para la primera prueba va perfecta una pila de 9 V o una fuente regulable.
- Abre el Monitor Serie a 9600 baudios. Lee la tensión y, al mismo tiempo, mide la fuente con el multímetro y compara los dos valores.
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}El código promedia 32 lecturas cada vez, así que la oscilación de ±1 paso del ADC casi desaparece y el último dígito se estabiliza. La primera lectura se descarta porque el condensador de muestreo del ADC aún conserva carga del canal anterior. Redondear a cero todo lo que esté por debajo de 0,05 V evita que aparezcan valores aleatorios como 0,02–0,04 V cuando no hay nada conectado. Recuerda que la resolución es de 24,4 mV: aunque veas dos decimales, el último dígito cambia en pasos de 0,02–0,03 V. Si necesitas más resolución, reduce el rango; con un divisor de 0–10 V un paso baja a 10,7 mV.
Tensión de referencia y calibración
Se suele decir que los voltímetros con Arduino "miden mal", pero la fuente real del error casi siempre es la referencia. Si en el código pone 5,00 V y la placa recibe 4,80 V del USB, cada lectura sale un 4 % alta: una batería de 12,00 V aparece como 12,50 V. Esta tensión cambia de un ordenador de sobremesa a un portátil y de un cable USB a otro, y si alimentas la placa con un adaptador externo entra en juego su regulador y el valor vuelve a cambiar. Hay tres soluciones: medir el pin 5V y escribirlo en el código, usar una referencia interna fija o recalcular en cada medida la tensión de alimentación de la propia placa.
| Método | Código | Ventaja | Ten en cuenta |
|---|---|---|---|
| Por defecto (AVcc) | analogReference(DEFAULT) | Sin configuración, rango completo de 0–5 V | Lo que haga la alimentación lo hará también la lectura |
| Referencia interna de 1,1 V | analogReference(INTERNAL) | Estable e independiente de la alimentación | Varía entre 1,0 y 1,2 V según la placa; la relación del divisor debe ser de unos 23 (p. ej. 220 kΩ + 10 kΩ) |
| Referencia externa (AREF) | analogReference(EXTERNAL) | La mejor precisión con una referencia como el LM4040 | Esta línea debe ejecutarse antes de aplicar tensión a AREF, o habrá un cortocircuito con la referencia interna |
| Medir la alimentación (readVcc) | El código de abajo | Sin piezas extra, sigue siendo preciso aunque cambie el USB o la pila | Solo funciona en placas AVR (Uno, Nano, Pro Mini); calibra una vez el valor de 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 la referencia interna: Ejecuta el código readVcc y compara el valor de Vcc del Monitor Serie con lo que mide tu multímetro en el pin 5V. Nuevo bandgapMv = 1100 × medido / mostrado. Por ejemplo, si la placa muestra 5,12 V y el multímetro 4,98 V, escribe 1100 × 4,98 / 5,12 ≈ 1070.
- Calibración de un punto: Conecta una tensión conocida cerca del máximo del rango (p. ej. 12 V). CAL = valor del multímetro / valor de Arduino. Este factor también corrige el error de relación por la tolerancia de las resistencias.
- Calibración de dos puntos: Si ves un desplazamiento fijo en tensiones bajas, mide en dos puntos, uno bajo (p. ej. 2 V) y otro alto (p. ej. 20 V). Pendiente = (M2 − M1) / (A2 − A1), desplazamiento = M1 − pendiente × A1; el resultado es real = pendiente × lectura + desplazamiento (M es el valor del multímetro y A el de Arduino).
- Comprueba: Después de calibrar, verifica el resultado con una tercera tensión en mitad del rango. Un voltímetro con Uno montado con cuidado mide de 0 a 25 V con menos de un 1 % de error.
Voltímetro digital con pantalla LCD

Para que el voltímetro no dependa del ordenador, basta con mostrar el valor en una pantalla LCD I2C. Conecta GND de la LCD a GND, VCC a 5V, SDA a A4 y SCL a A5. Instala desde el Gestor de Bibliotecas la biblioteca LiquidCrystal I2C (Frank de Brabander). La dirección de la pantalla suele ser 0x27, o 0x3F en algunos módulos. El código siguiente muestra la tensión actual en la línea superior y, en la inferior, los valores mínimo y máximo desde el encendido; así también captas la caída de tensión de una batería mientras funciona un motor.
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}Voltímetro con ESP32
El ESP32 funciona a 3,3 V y sus pines no aguantan más de 3,6 V, así que para 0–25 V usa un divisor de 100 kΩ + 10 kΩ: 25 V en la entrada dan 2,27 V en el pin. Conecta el divisor a uno de los pines ADC1 (GPIO 32–39); los pines ADC2 no funcionan mientras el Wi-Fi está activo. El ADC del ESP32 es de 12 bits, pero no es lineal en los extremos: apenas ve nada por debajo de 0,15 V y su error crece por encima de 2,5 V. La función analogReadMilliVolts() usa datos de calibración grabados en el chip de fábrica y da un resultado en milivoltios mucho más preciso que el valor en bruto. Para eliminar el desplazamiento restante, el código aplica la calibración de dos puntos de la sección anterior con las constantes GAIN y 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}Voltímetro con Raspberry Pi Pico (MicroPython)
En la Raspberry Pi Pico las entradas analógicas son GP26, GP27 y GP28. Conecta a GP26 el mismo divisor de 100 kΩ + 10 kΩ que en el ESP32. En MicroPython, read_u16() devuelve el resultado de 12 bits escalado a 0–65535. La referencia del ADC de la Pico se obtiene filtrando la línea de 3,3 V; para más precisión, mide entre ADC_VREF (pin 35) y GND con el multímetro y escribe el valor en VREF. El código trae además un extra: en la Pico estándar, GP29 (ADC3) está conectado a un divisor interno que divide entre 3 la entrada de alimentación VSYS. Así, sin ninguna pieza más, también lees la tensión de la batería que alimenta la Pico. En la Pico W y la Pico 2 W, GP29 se comparte con el chip inalámbrico, por lo que esta línea no funciona directamente en esas placas.
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)Añadir corriente para hacer un vatímetro: ACS712 o INA219

Cuando añades medición de corriente a un voltímetro, también obtienes la potencia: P = V × I. Si una batería de 12 V entrega 1,5 A, la potencia es de 18 W. Si sumas la potencia a lo largo del tiempo, obtienes la energía: una carga de 18 W que funciona 2 horas consume 36 Wh. Hay dos opciones habituales. El ACS712 tiene salida analógica, mide también corriente alterna y ofrece aislamiento; se añade al voltímetro como un segundo canal analógico. El INA219 es un medidor de potencia de continua que mide tensión y corriente en el mismo chip con 12 bits de precisión y se comunica por I2C; por sí solo ya es un vatímetro completo.
| Característica | Módulo de voltaje + ACS712 (5A) | Módulo INA219 |
|---|---|---|
| Rango de tensión | 0–25 V (según el divisor) | 0–26 V (dentro del chip) |
| Rango de corriente | ±5 A | ±3,2 A (con shunt de 0,1 Ω) |
| Resolución de corriente | Unos 26 mA en un Uno | 0,1 mA |
| Corriente alterna | Sí | No |
| Conexión | Dos pines analógicos | I2C (SDA, SCL), dirección 0x40 |
| Ideal para | Motores, corriente del lado de red y donde haga falta aislamiento | Pequeñas potencias de continua: baterías, paneles solares y dispositivos 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}El INA219 calcula la corriente a partir de la pequeña caída de tensión en la resistencia shunt de 0,1 Ω entre VIN+ y VIN−, por eso el módulo se conecta en serie en el lado positivo de la fuente (lado alto). Como la tensión de bus se mide entre VIN− y GND, el código le suma la caída del shunt para obtener la tensión real de la fuente. La calibración por defecto es para 32 V y 2 A; si solo vas a medir unos cientos de miliamperios, activa la línea setCalibration_16V_400mA() para reducir el rango a 400 mA y ganar precisión con corrientes pequeñas. La energía se obtiene sumando en cada vuelta la potencia actual multiplicada por el tiempo transcurrido; se pone a cero al apagar el Arduino, así que, para conservarla, guarda el valor cada cierto tiempo en la EEPROM. El código que hace el mismo cálculo con el ACS712 está en la sección de potencia y energía del artículo sobre el ACS712.
Probador de baterías: un voltímetro que mide la capacidad (mAh)

La tensión de una batería no dice exactamente cuánta energía le queda; una celda cargada pero desgastada también puede marcar 4,1 V. La forma de conocer la capacidad real es descargarla a través de una carga conocida e ir sumando la corriente a lo largo del tiempo: mAh = Σ (corriente × tiempo). En este circuito un MOSFET conecta y desconecta la carga, y el Arduino mide una vez por segundo la tensión de la batería y la del extremo inferior de la resistencia de carga. La diferencia entre ambas, dividida por la resistencia de carga, da la corriente. Cuando la batería llega a su tensión de corte, el MOSFET se apaga y se muestra el resultado. Al principio, el código compara además la tensión sin carga y con carga para calcular la resistencia interna; cuanto mayor es, más cae la tensión de la batería con corrientes altas.
| Componente | Conexión | Nota |
|---|---|---|
| Batería + | A A0 a través de 10 kΩ; también al extremo superior de la resistencia de carga | Pon 100 nF entre A0 y GND |
| Resistencia de carga de 4,7 Ω | Entre batería + y el drenador del MOSFET | Resistencia cerámica de al menos 5 W (mejor 10 W); con una 18650 circulan unos 0,9 A y se calienta |
| Drenador del MOSFET | Extremo inferior de la resistencia de carga; a A1 a través de 10 kΩ | Pon también 100 nF entre A1 y GND |
| Fuente del MOSFET | GND | Aquí va también el negativo de la batería |
| Puerta del MOSFET | A D9 a través de 220 Ω; a GND con 100 kΩ | Usa un MOSFET de nivel lógico como el 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 una carga de 4,7 Ω, una celda 18650 se descarga con una corriente que empieza en unos 0,9 A y baja hacia 0,65 A; probar una celda sana de 2500 mAh lleva unas tres horas. En iones de litio nunca pongas el corte por debajo de 3,0 V, o la celda se estropea. Si pruebas una pila alcalina AA, pon CUTOFF_V en 0,9 V; con la misma carga consume unos 0,3 A. Puedes comparar el resultado con la etiqueta y con la calculadora de duración de batería. La resistencia interna de una 18650 nueva medida así, incluidos portapilas y cables, suele estar por debajo de 0,15 Ω; una celda por encima de 0,3 Ω no debería usarse en aplicaciones de alta corriente. Para entender las unidades de capacidad, echa un vistazo al artículo sobre mAh y capacidad de batería.
Ideas de proyectos con un voltímetro con Arduino
- Monitor de batería con alarma de baja tensión: Vigila la batería de 12 V de una autocaravana o una instalación solar y haz sonar un zumbador cuando baje de 11,8 V.
- Registrador de panel solar: Guarda cada minuto en una tarjeta SD la tensión del panel y, con el INA219, su corriente, y calcula la producción diaria en Wh.
- Indicador para fuente regulable: Añade un voltímetro y un INA219 a la salida de un módulo LM2596 para convertirlo en una fuente de laboratorio.
- Control remoto de la batería: Envía la tensión medida con un ESP32 a Home Assistant por MQTT o recibe un mensaje de Telegram cuando esté baja.
- Revisión de packs 18650: Prueba la capacidad de las celdas que cargas con un TP4056 y empareja celdas de capacidad parecida para montar un pack equilibrado.
- Indicador de dígitos grandes: Muestra el valor en un display de 7 segmentos o una pantalla OLED en lugar de la LCD, lo bastante grande para leerlo de lejos.
Errores frecuentes y cómo solucionarlos
| Síntoma | Causa probable | Solución |
|---|---|---|
| La lectura sale siempre un 2–5 % alta o baja | VREF es 5,00 V en el código pero la placa funciona con otra tensión | Mide el pin 5V y escríbelo en VREF, o usa el método readVcc |
| El valor no deja de saltar | El negativo de la fuente no está unido al GND de Arduino o la línea tiene ruido | Conecta una masa común, promedia y añade 100 nF en el pin |
| Se queda en el mismo valor con tensiones altas | El pin alcanzó la referencia y el ADC se saturó en 1023 | Amplía el rango aumentando la relación del divisor |
| La lectura se curva en la parte alta y no es lineal | Fuga del zener o extremo superior del ADC del ESP32 | Mantén el pin por debajo de 4 V (2,5 V en el ESP32) o usa un Schottky |
| En el ESP32 la lectura es 0 o se congela al activar el Wi-Fi | El divisor está en un pin ADC2 | Usa uno de los pines ADC1, GPIO 32–39 |
| El INA219 muestra corriente negativa | VIN+ y VIN− están invertidos | El positivo de la fuente va a VIN+ y el de la carga a VIN− |
| La LCD se ilumina pero no muestra texto | Dirección I2C o contraste incorrectos | Busca la dirección con un escáner I2C y gira el trimmer trasero |
Un voltímetro con Arduino es una de las mejores formas de aprender cómo funciona una medida: con dos resistencias, una fórmula y un poco de calibración obtienes resultados cercanos a los de un multímetro; si añades un sensor de corriente se convierte en vatímetro y, con un MOSFET, en probador de baterías. En la app BlueGrays, el proyecto "Voltímetro digital con LCD" te permite montar el mismo circuito paso a paso con esquema y código listo, y desde ahí pasar a proyectos de monitorización de baterías y medida de potencia.
Preguntas frecuentes
¿Cuántos voltios puede medir un Arduino?
A un pin analógico se pueden conectar directamente como máximo 5 V (3,3 V en el ESP32 y la Pico). Con un divisor de voltaje ese límite se amplía tanto como quieras: con 30 kΩ + 7,5 kΩ mides 25 V y con 100 kΩ + 10 kΩ, 50 V. Eso sí, por encima de unas decenas de voltios la seguridad y el aislamiento pasan a ser importantes, y la tensión de red nunca se mide así.
¿Por qué mi voltímetro con Arduino mide mal?
La causa más habitual es la tensión de referencia: en el código pone 5,00 V pero la placa recibe 4,7–4,9 V del USB y todas las lecturas se desvían en la misma proporción. Otras causas son las resistencias del 5 %, la falta de masa común y un divisor con demasiada resistencia. Se soluciona midiendo el pin 5V y escribiéndolo en el código, o usando el método readVcc, y ajustando el factor CAL con una tensión conocida.
¿Se puede usar el módulo sensor de voltaje de 0–25 V con un ESP32?
Se puede, pero con cuidado. Como la relación del módulo es 5, con un ESP32 solo mides hasta 16,5 V; si tocas 25 V llegan 5 V al pin y el ESP32 se daña. Montar tu propio divisor de 100 kΩ + 10 kΩ es más seguro y también más preciso, porque mantiene el ADC en su zona lineal.
¿Se puede medir la tensión de red de 230 V con Arduino?
Nunca con un divisor de voltaje: es potencialmente mortal y conecta el Arduino a la red. Para la tensión de red se usan módulos como el ZMPT101B, que lleva un pequeño transformador y ofrece aislamiento galvánico. Su salida es alterna, así que el código calcula el valor eficaz (RMS).
¿Puede Arduino medir tensiones negativas?
No directamente; un pin analógico no lee por debajo de GND y puede dañarse. La solución es desplazar la señal hacia 5 V con resistencias: por ejemplo, dos resistencias iguales entre la señal y 5 V crean un punto medio que lleva el rango de −5 V a +5 V a 0–5 V. Para trabajos más precisos se usa un desplazador de nivel con amplificador operacional.
¿Puede un voltímetro con Arduino ser tan preciso como un multímetro?
Un voltímetro con Uno calibrado mide de 0 a 25 V con menos de un 1 % de error, suficiente para la mayoría de proyectos y cercano a un multímetro económico. Por el ADC de 10 bits, la resolución se limita a unos 24 mV en el rango de 25 V. Para mejores resultados puedes usar un ADC externo de 16 bits como el ADS1115, resistencias del 0,1 % y una referencia de precisión.
Proyectos para hacer después de leer esto
Ver todos los proyectos
Medir la intensidad de luz con LDR
¿Quieres ver en números cuánta luz hay en tu habitación? El LDR, una pequeña pieza sensible a la luz, mide la luz ambiente y el Arduino escribe el valor en la pantalla del ordenador cada medio segundo

Lectura de la intensidad luminosa con el módulo LDR del ESP32
Visualización en tiempo real en el monitor serie del valor bruto del ADC del módulo LDR y del porcentaje relativo de luz calculado a partir de referencias de oscuridad y claridad. Este porcentaje no es una medición en lux. Explica el funcionamiento de la calibración del módulo. Es recomendable realizarlo antes del Proyecto 10, ya que se utiliza para determinar el valor umbral.

Voltímetro digital con pantalla LCD
Descubre cuánto voltaje da una pila o un adaptador con un medidor hecho por ti. Un divisor de dos resistencias baja la tensión alta a un nivel que la placa puede leer, y el Arduino calcula el valor re

Medición de temperatura con NTC y pantalla LCD 2x16
Mide la temperatura del ambiente con un sensor que parece una pequeña cuenta. Esta pieza, llamada NTC, deja pasar la electricidad con más facilidad cuanto más se calienta; el Arduino lee ese cambio, l

Uso de la pantalla LCD con I2C
Dale a tu Arduino su propia pantalla y haz que escriba su primer mensaje. La pantalla LCD de dos líneas se conecta con solo unos pocos cables; primero aparece un saludo en la línea de arriba, luego un

Pantalla LCD I2C para ESP32 (16x2)
En este proyecto, mostramos texto conectando una pantalla LCD de 16x2 caracteres al ESP32 a través del protocolo I2C. Gracias al I2C, podemos controlar la pantalla con solo 2 pines de datos (SDA y SCL); así se elimina el desperdicio de pines que supone la conexión paralela clásica, que requiere más de 6 pines. El código imprime un mensaje fijo en la primera línea y un contador que aumenta cada segundo en la segunda línea. Además, al inicio ejecutamos el escáner I2C para mostrar la dirección de l

Medición de distancias mediante pantalla LCD
Un aparato que mide distancias sin regla: mueve la mano delante del sensor y mira cómo cambia el número. El HC-SR04 envía una onda de sonido y escucha su eco, y el Arduino calcula la distancia en cent

Brillo de LED con Potenciómetro en ESP32 (Analógico → PWM)
En este proyecto controlamos el brillo de un LED de forma analógica mediante un potenciómetro. El pin ADC del ESP32 lee la tensión de 0-3,3 V procedente del potenciómetro y este valor se convierte en una señal PWM (modulación por ancho de pulso) que se envía al LED. Al girar el potenciómetro, el LED se enciende y se apaga gradualmente. Con Arduino Core 3.0+ se usa directamente analogWrite(); en el ESP32-S2/S3, la resolución del ADC es de 12 bits.
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

