Een slimme voltmeter bouwen met Arduino en smartphone – Eenvoudig DIY-project
Onderdelen en benodigdheden
| Onderdeel | Aantal |
|---|---|
| Arduino UNO | 1 |
| PHPoC WiFi Shield voor Arduino | 1 |
| Weerstand 100k ohm | 1 |
| Weerstand 1M ohm | 1 |
| Draadjes (jumper wires) | 1 set |
Over dit project
Demonstratie
Als je nieuw bent met Arduino, kun je beginnen met de Arduino-tutorials voor beginners.
Hoe het werkt
We kunnen de analoge ingangspin van de Arduino gebruiken om spanning te meten. De maximaal meetbare spanning is echter 5V.
Om het meetbereik te vergroten, gebruiken we een spanningsdeler.
In theorie
De formule is:
V_meten = (R1 + R2) / R2 × V_in
verhouding = (R1 + R2) / R2
=> V_meten = verhouding × V_in
Als we kiezen voor R1 = 10 × R2, dan geldt:
V_meten = 11 × V_in
Aangezien de maximaal toegestane V_in 5V is, is de maximaal meetbare spanning 55V.
Om de stroom door de Arduino-pin te beperken (wat schade kan veroorzaken), kiezen we zo mogelijke hoge weerstandswaarden.
Ik heb gekozen voor R1 = 1 Mohm, R2 = 100 Kohm.
In de praktijk
Er zijn in de praktijk enkele problemen:
- De waarden van R1 en R2 hebben foutmarges. Deze fouten veroorzaken afwijkingen in V_meten.
- De voeding van de Arduino kan onstabiel zijn. Dit maakt de V_REF van de analoge ingang onstabiel, wat leidt tot fouten in de berekening van V_in en daarmee ook in V_meten.
Deze problemen worden opgelost in de kalibratiefase.
Kalibratie
1. De echte waarde van (R1 + R2) / R2 meten
Dit hoeft maar één keer gedaan te worden om de verhouding te bepalen.
Aansluiting volgens onderstaand schema:
verhouding = (R1 + R2) / R2 = V_meten / V_in = A1_leeswaarde / A0_leeswaarde
verhouding = A1_leeswaarde / A0_leeswaarde
Code voor deze kalibratie: zie ResisterCalibration.ino in de codesectie.
2. Onstabiliteit van de voeding
Onstabiliteit in de voeding zorgt voor onstabiliteit in de referentie spanning van de analoge pin. Dit veroorzaakt foutieve metingen.
Om dit op te lossen, meten we de referentie spanning regelmatig.
Hoe de referentie spanning te meten?
Sluit 3.3V aan op pin A1.
De referentie spanning wordt indirect gemeten op basis van de waarde in A1:
V_referentie = 1023 × 3.3 / A1_waarde
Hoe V_meten te berekenen:
V_in = mapFloat(A0_waarde, 0, 1023, 0, V_referentie); V_meten = verhouding × V_in;
Hoofdaansluiting:
Hoe te bouwen
- Aansluiten volgens het "weerstand kalibratie" schema
ResistorCalibration.inouploaden- Seriële Plotter openen
- De verhoudingswaarde kopiëren
- Deze waarde vervangen in regel 5 van
Voltmeter.ino - Opnieuw aansluiten volgens het "hoofdaansluiting" schema
Voltmeter.inouploaden- Web User Interface (
voltmeter.phpenvoltmeter_body.jpg) uploaden naar de PHPoC Shield - De webpagina benaderen via
https://phpoc_shield_ip_adres/voltmeter.phpom de spanning te zien.
Je kunt de spanning op je smartphone bekijken als volgt:
Aansluittips:
De beste Arduino starterset voor beginners
Bekijk de beste Arduino-set voor beginners.
Code
ResistorCalibration.ino Arduino
Aansluiting zoals beschreven in het kalibratiedeel. De code eenmalig uitvoeren, Seriële Plotter openen, de verhoudingswaarde kopiëren en deze vervangen in regel 5 van 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;
double A1_read_value;
A0_read_value = analogReadAverage(A0, 20);
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
Dit is de hoofdcode. Voordat je deze uploadt, moet je:
ResistorCalibration.inouploaden- Seriële Monitor openen
- De verhoudingswaarde kopiëren en vervangen in regel 5 van deze code
double V_measure;
double V_in;
double V_reference;
double ratio = 11.59;
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);
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
Dit bestand is de Web User Interface. Het moet samen met de achtergrondafbeelding voltmeter_body.jpg naar de PHPoC Shield geüpload worden.
<!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("KAN NIET verbinden met 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");
buffer = buffer.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>
Schema's
Moet geüpload worden naar de PHPoC Shield.
Productieproces
- Bouw een DIY Photoshop-bedieningsconsole met Arduino Nano RP2040
- Betrouwbaar Arduino RFID Aanwezigheidssysteem Aangedreven door Python
- Universele Android-afstandsbediening bouwen met Arduino, 1Sheeld en IR-besturing
- Bouw een betrouwbare infrarode hartslagsensor met Arduino: stapsgewijze handleiding
- Nauwkeurige Frequentie- en Duty Cycle-meting met Arduino UNO
- Bouw een DIY Voltmeter met Arduino en Nokia 5110 Display – Stap-voor-Stap Handleiding
- Realtime afstandsmeting met Arduino Sonar & Processing visualisatie
- MobBob: Bouw Je Eigen Arduino Robot, Naadloos Bestuurd via Android Smartphone
- Naadloze LED-dimmer met Bolt IoT en Arduino UNO
- Bouw een Slimme Arduino-gestuurde Robotarm: Eenvoudige DIY Handleiding
- Bouw een compacte FM-radio met Arduino Nano en RDA5807M