Construye un Voltímetro Inteligente con Arduino y Smartphone – Proyecto DIY Fácil
Componentes y materiales
| Arduino UNO | × | 1 |
| PHPoC WiFi Shield para Arduino | × | 1 |
| Resistencia 100 kΩ | × | 1 |
| Resistencia 1 MΩ | × | 1 |
| Cables jumper | × | 1 |
Sobre el proyecto
Demostración
Si eres nuevo en Arduino, puedes comenzar con los tutoriales de Arduino para principiantes.
Cómo funciona
Podemos usar una entrada analógica de Arduino para medir voltaje. Sin embargo, el voltaje máximo medible es de 5 V.
Para aumentar el rango de medición, necesitamos un divisor de voltaje.
En teoría
Tenemos:
V_medida = (R1 + R2) / R2 × V_entrada
ratio = (R1 + R2) / R2
⇒ V_medida = ratio × V_entrada
Si elegimos R1 = 10 × R2, obtenemos:
V_medida = 11 × V_entrada
Dado que el máximo V_entrada permitido es 5 V, el voltaje máximo medible es 55 V.
Para limitar la corriente que circula por el pin de Arduino y evitar daños, debemos elegir valores de resistencia lo más altos posible.
He elegido R1 = 1 MΩ, R2 = 100 kΩ.
En la práctica
Surgen dos problemas principales:
- Los valores reales de R1 y R2 tienen tolerancias, lo que introduce error en V_medida.
- La alimentación de Arduino puede ser inestable, haciendo que la referencia de voltaje (V_REF) de la entrada analógica fluctúe. Esto causa errores en el cálculo de V_entrada y, por tanto, en V_medida.
Estos problemas se resuelven en la parte de Calibración.
Calibración
1. Medir el valor real de (R1 + R2) / R2
Solo es necesario hacerlo una vez para obtener el ratio.
Cableado según la imagen:
ratio = (R1 + R2) / R2 = V_medida / V_entrada = A1_valor_leido / A0_valor_leido
ratio = A1_valor_leido / A0_valor_leido
Código para esta calibración → ver ResisterCalibration.ino en la sección de código.
2. Inestabilidad de la alimentación
La inestabilidad de la fuente de alimentación causa inestabilidad en la referencia de voltaje del pin analógico, lo que produce mediciones erróneas.
Para solucionarlo, debemos medir la referencia de voltaje frecuentemente.
¿Cómo medir la referencia de voltaje?
Conecta 3,3 V al pin A1.
La referencia de voltaje se mide indirectamente basándose en el valor leído en A1:
V_referencia = 1023 × 3,3 / A1_valor
Cómo calcular V_medida:
V_entrada = mapFloat(A0_valor, 0, 1023, 0, V_referencia); V_medida = ratio × V_entrada;
Cableado principal:
Pasos a seguir
- Cablea según el circuito de "calibración de resistencias".
- Sube
ResistorCalibration.ino. - Abre el Serial Plotter.
- Copia el valor del ratio.
- Reemplaza ese valor en la línea 5 de
Voltmeter.ino. - Re-cablea según el "cableado principal".
- Sube
Voltmeter.ino. - Sube la interfaz web (voltmeter.php y voltmeter_body.jpg) al PHPoC Shield.
- Accede a la página web
https://ip_del_phpoc_shield/voltmeter.phppara ver el voltaje.
Puedes ver el voltaje en tu smartphone como se muestra a continuación:
Consejos de cableado
El mejor kit de inicio de Arduino para principiantes
Consulta El mejor kit de Arduino para principiantes.
Código
ResistorCalibration.inoVoltmeter.inovoltmeter.php
ResistorCalibration.ino Arduino
Cablea como se describe en la parte de calibración. Ejecuta este código una vez, abre el Serial Plotter, copia el valor del ratio y reemplázalo en la línea 5 de Voltmeter.ino.
double ratio;
int analogReadAverage(int pin, int read_time) {
unsigned long read_value = 0;
for(int i = 0; i < read_time; i++) {
read_value += analogRead(pin);
delay(2);
}
read_value /= read_time;
return read_value;
}
double resistorCalibration() {
double _ratio;
double A0_read_value = analogReadAverage(A0, 20);
double A1_read_value = analogReadAverage(A1, 20);
_ratio = A1_read_value / A0_read_value;
return _ratio;
}
void setup() {
Serial.begin(9600);
}
void loop() {
ratio = resistorCalibration();
Serial.print("ratio:");
Serial.println(ratio);
delay(200);
}
Voltmeter.ino Arduino
Este es el código principal. Antes de subirlo, debes:
- Subir
ResistorCalibration.ino. - Abrir el Serial Monitor.
- Copiar el valor del ratio y reemplazar el valor en la línea 5 de este código.
double V_measure;
double V_in;
double V_reference;
double ratio = 11.59; // Reemplaza con tu valor calibrado
double mapFloat(double x, double in_min, double in_max, double out_min, double out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
int analogReadAverage(int pin, int read_time) {
unsigned long read_value = 0;
for(int i = 0; i < read_time; i++) {
read_value += analogRead(pin);
delay(2);
}
read_value /= read_time;
return read_value;
}
double getVoltageReference() {
double A1_value = analogReadAverage(A1, 20); // A1 conectado a 3.3V
double V_REF = 1023 * 3.3 / A1_value;
return V_REF;
}
void setup() {
Serial.begin(9600);
}
void loop() {
V_reference = getVoltageReference();
double A0_value = analogReadAverage(A0, 20);
V_in = mapFloat(A0_value, 0, 1023, 0, V_reference);
V_measure = ratio * V_in;
Serial.println(V_measure);
delay(200);
}
voltmeter.php PHP
Este archivo es la interfaz de usuario web. Debe subirse al PHPoC Shield junto con la imagen de fondo voltmeter_body.jpg.
<!DOCTYPE html>
<html>
<head>
<title>PHPoC Shield - VOLTMETER</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<link rel="stylesheet" media="screen" href="https://fontlibrary.org/face/segment7" type="text/css"/>
<style>
html {height: 100%;}
body {width: 100%; height: 100%; text-align: center;}
.container {width: 100%; min-height: 99%; max-height: 100%;}
canvas {
background: url(voltmeter_body.jpg);
background-size: contain;
font-family: 'Segment7Standard';
font-weight: bold;
font-style: italic;
}
</style>
<script>
var COLOR_LCD_TEXT = "#000000";
var COLOR_LCD_BGR = "#00FFFF";
var IMG_WIDTH = 583;
var IMG_HEIGHT = 1235;
var METER_WIDTH, METER_HEIGHT;
var ws;
var canvas;
var ctx;
var buffer = "";
var voltage = 0;
function init() {
canvas = document.getElementById("graph");
ctx = canvas.getContext("2d");
canvas_resize();
update_view(voltage);
var ws_host_addr = "";
if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "[")) {
ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
ws_host_addr = ws_host_addr.replace(/:/g, "-");
ws_host_addr += ".ipv6-literal.net";
}
ws = new WebSocket("ws://" + ws_host_addr + "/serial_monitor", "uint8.phpoc");
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
ws.binaryType = "arraybuffer";
}
function ws_onopen() {}
function ws_onclose() {
alert("CANNOT connect to Arduino!");
ws.onopen = null; ws.onclose = null; ws.onmessage = null; ws = null;
}
function ws_onmessage(e_msg) {
e_msg = e_msg || window.event;
var u8view = new Uint8Array(e_msg.data);
buffer += String.fromCharCode.apply(null, u8view);
buffer = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
while(buffer.indexOf("\n") == 0) buffer = buffer.substr(1);
if(buffer.indexOf("\n") <= 0) return;
var pos = buffer.lastIndexOf("\n");
var str = buffer.substr(0, pos);
var arr = str.split("\n");
buffer = buffer.substr(pos + 1);
if(arr.length) {
voltage = parseFloat(arr[arr.length - 1]);
update_view(voltage);
}
}
function update_view(voltage) {
ctx.clearRect(0, 0, METER_WIDTH, METER_HEIGHT);
var top = METER_HEIGHT * 0.125;
var left = METER_WIDTH * 0.2;
var width = METER_WIDTH * 0.6;
var height = METER_HEIGHT * 0.12;
ctx.fillStyle = COLOR_LCD_BGR;
ctx.rect(left, top, width, height);
ctx.fill();
ctx.font = "italic 75px Segment7Standard";
ctx.textBaseline = "middle";
ctx.textAlign = "end";
ctx.fillStyle = COLOR_LCD_TEXT;
ctx.fillText(voltage.toFixed(2), left + width - 50, top + height / 1.8);
ctx.font = "18px Arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText("VDC", left + width - 25, top + height / 2);
ctx.font = "bold 32px Arial";
ctx.shadowBlur = 5;
ctx.shadowColor = "white";
ctx.fillStyle = "#00FFFF";
ctx.fillText("ARDUINO", METER_WIDTH / 2, METER_HEIGHT * 0.5);
ctx.fillText("WEB VOLTMETER", METER_WIDTH / 2, METER_HEIGHT * 0.55);
}
function canvas_resize() {
canvas.width = 0; canvas.height = 0;
var container = document.getElementById("container");
var height = container.clientHeight;
var ratio = height / IMG_HEIGHT;
var width = ratio * IMG_WIDTH;
METER_WIDTH = width; METER_HEIGHT = height;
canvas.width = METER_WIDTH; canvas.height = METER_HEIGHT;
update_view(voltage);
}
window.onload = init;
</script>
</head>
<body onresize="canvas_resize()">
<div class="container" id="container">
<canvas id="graph"></canvas>
</div>
</body>
</html>
Esquemáticos
Debe subirse al PHPoC Shield.
Proceso de manufactura
- Construye una consola de control DIY para Photoshop con Arduino Nano RP2040
- Sistema de Asistencia RFID Fiable con Arduino y Python
- Mando universal Android con Arduino, 1Sheeld y control IR
- Construye un Sensor de Ritmo Cardíaco por Infrarrojos Fiable con Arduino: Guía Paso a Paso
- Medición precisa de frecuencia y ciclo de trabajo con Arduino UNO
- Construye un voltímetro DIY con Arduino y pantalla Nokia 5110 – Guía paso a paso
- Medición de Distancia en Tiempo Real con Sonar Arduino y Visualización en Processing
- MobBob: Robot Arduino Impreso en 3D, Controlado por Smartphone Android
- Control de brillo LED sin interrupciones con Bolt IoT y Arduino UNO
- Brazo Robótico Inteligente Controlado por Arduino: Tutorial DIY Fácil
- Construye una Radio FM Compacta con Arduino Nano y RDA5807M