Multimètre Arduino
Dans la lignée des projets Arduino (horloge et mini station météo), je souhaitais réaliser un multimètre qui disposerait des fonctions ohmmètre, voltmètre et testeur de continuité. Je l’ai donc réalisé à base d’un Arduino nano. Explications.
Généralités
Ce projet s’est découpé en plusieurs morceaux, qu’il a fallu tester les uns après les autres afin de valider le fonctionnement global. Les morceaux sont :
- partie ohmmètre
- partie voltmètre
- partie continuité
- affichage sur écran OLED 128×32
- sélection des menus par bouton poussoir
- gestion du pôle commun
- assemblage final
Après pas mal d’heures de recherches pour avoir le système le plus satisfaisant, j’ai réussi à combiner pas mal de bons sujets pour arriver à mes fins.
Matériel
Pour réaliser ce multimètre, il faut :
- 1 arduino nano
- 1 écran OLED 128×32
- des résistances
- 2 relais 12 sur platine
- 1 led
- 1 platine d’essai
- des fils breadboard (mâle/femelle, mâle/mâle)
Schéma général
Ohmmètre
Pour mesurer une résistance via un Arduino, il faut passer par le célèbre pont diviseur de tension. On relie le milieu du pont diviseur sur une entrée analogique de l’Arduino pour obtenir la tension aux bornes de la résistance mesurée.
En considérant U2 la tension aux bornes de R2 et A1 la mesure faite sur le port analogique 1 de l’Arduino, et sachant que l’entrée fait 5V, on en déduit que U2 = A1 x 5 / 1024 et que R2 = U2 x R1 / (5-U2).
Pour améliorer la précision, nous allons utiliser des résistances R1 différentes pour avoir un résultat le plus pertinent possible. Le script interrogera chaque ligne de résistance avec la résistance à mesurer afin d’avoir le résultat le plus pertinent possible.
Voici le schéma :
Pour une précision ultime, il faut prendre des résistances avec 1% de tolérance.
Une fois le montage réalisé, nous pouvons tester avec le code suivant :
const byte resistorPin = A1; const byte resistorPins[] = {12,11,10,9,8,7,6}; # define NUMBERPINS sizeof(resistorPins) const int resistorValues[NUMBERPINS] = {220, 560, 1000, 2200, 4700, 10000, 22000}; int resistorReads[NUMBERPINS] = {}; double vx; float rx; double i; boolean novalue; void setup(void) { pinMode(resistorPin, INPUT); Serial.begin(9600); } //fonctions int readvalues(byte mask) { for(byte p = 0; p < NUMBERPINS; p++) { pinMode(resistorPins[p], INPUT); // High-impedance } for(byte p = 0; p < NUMBERPINS; p++) { if ((mask & (1 << p)) != 0) { pinMode(resistorPins[p], OUTPUT); digitalWrite(resistorPins[p], HIGH); } } return analogRead(resistorPin); } void loop(void){ for(byte p = 0; p < NUMBERPINS; p++) { resistorReads[p] = readvalues(1 << p); } novalue = true; for(byte p = NUMBERPINS; p > 0; p--) { if (resistorReads[p-1] >= 450) { vx = (resistorReads[p-1]) * (5.0 / 1024.0); i = (5.0/vx) - 1; rx = (resistorValues[p-1] / i); novalue = false; break; } } if (novalue) { vx = (resistorReads[0]) * (5.0 / 1024.0); i = (5.0/vx) - 1; rx = (resistorValues[0] / i); } if(vx > 4.8) { Serial.println("----INFINITY----"); } else { if(rx < 1000) { Serial.print(rx); } else { rx = rx / 1000; Serial.print(rx); Serial.print("k"); } Serial.println(" Ohms"); } delay(500); }
Source : https://jpralves.net/post/2015/08/18/ohmmeter-with-auto-ranging.html
Voltmètre
Sur le voltmètre, le principe est exactement le même, sauf que nous connaissons les 2 résistances et nous pouvons donc en déduire la tension qui traverse R2.
Pour avoir une bonne précision de mesure, il faut prendre des résistances assez élevées et le choix est fait pour R1=100 kohm et R2 = 10kohm. Avec ces valeurs, on obtient un pont diviseur par 10, c’est à dire qu’avec 5V d’entrée d’Arduino, nous pouvons mesurer jusqu’à 50V théoriques. Je vous conseille de vous limiter à 30V.
On reliera le centre du diviseur de tension sur la borne A6.
Voici le code du voltmètre :
const int pinVoltmeter = 6; float vout = 0.0; float vin = 0.0; float R1 = 100000.0; float R2 = 10000.0; int value = 0; void setup(void) { Serial.begin(9600); pinMode(pinVoltmeter, INPUT); } void loop(void){ value = analogRead(pinVoltmeter); vout = (value * 5.0) / 1024.0; vin = vout / (R2/(R1+R2)); if (vin<0.09) { vin=0.0; } Serial.print(vin); Serial.println("V"); delay(500); }
Source : http://www.electroschematics.com/9351/arduino-digital-voltmeter/
Continuité
Pour la continuité, il le s’agit ni plus ni moins que d’allumer une led quand le circuit est fermé !
const int pinContinuity=2; void setup(void) { Serial.begin(9600); pinMode(pinContinuity,OUTPUT); digitalWrite(pinContinuity,LOW); } void loop(void){ digitalWrite(pinContinuity,HIGH); }
Affichage sur écran OLED
Pour l’écran OLED, j’ai utilisé la librairie u8g2 à installer dans les librairies du programmes Arduino. A partir des fichiers d’exemples, j’ai réussi à trouver la bonne police d’écriture : logisoso. C’est une librairie qui fait 32 pixel de haut, soit la hauteur totale de l’écran.
Concernant le câblage, il est connecté via I2C et le brochage est le suivant :
- Vcc sur 5V
- GND sur GND
- SCL sur A5
- SDA sur A4
Pour afficher un texte sur l’écran, voici l’exemple de code :
#include <Arduino.h> #include <U8g2lib.h> #ifdef U8X8_HAVE_HW_SPI #include <SPI.h> #endif #ifdef U8X8_HAVE_HW_I2C #include <Wire.h> #endif U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather ESP8266/32u4 Boards + FeatherWing OLED void setup(void) { u8g2.begin(); } void loop(void){ u8g2.clearBuffer(); u8g2.setFont(u8g2_font_logisoso32_tr); u8g2.drawStr(0,32,"MULTIM"); u8g2.sendBuffer(); }
La ligne U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C dans les fichiers exemple fait partie d’une longue liste d’écran. Il faut choisir le 128×32 UNIVISION avec en paramètrte SCL et SDA.
Pour le reste, c’est très simple. On l’initialise, on charge la police puis on écrit avec la commande u8g2.drawStr.
Enfin, pour formater des chiffres, il faut les transformer en chaine de caractères, et voici comment faire :
char tempBuffer2[6]; //on déclare un buffer temporaire de 6 caractères char Sortie[7]; //on déclare la sortie à 7 caractères (1 caractère d'unité) dtostrf(vin, 4, 2, tempBuffer2); //on transforme vin(tension finale) sur 4 caractères dans tempBuffer2 snprintf(Sortie,20, "%sV", tempBuffer2); //on rajoute l'unité V en fin de chaine avec snprintf u8g2.drawStr(0,32,Sortie); //on l'affiche à l'écran u8g2.sendBuffer();
Bouton poussoir
Pour changer de menu, j’ai longtemps hésité avec un selecteur rotatif, mais les prix de ceux ci m’ont convaincu de faire plus simple et moins cher. Du coup, j’ai utilisé un bouton poussoir qui, à chaque appui, faire passer d’une fonction à une autre : accueil -> ohmmetre -> voltmètre -> continuité -> accueil. Chaque menu lance une fonction dans laquelle on gère le partie correspondante.
Pour gérer cela, on raccorde le bouton sur une entrée (j’ai choisi A2) puis on le relie au GND.
Voici le code correspondant :
const int button = A2; int buttonNb = 0; //en fct des menus void setup(void) { pinMode(button, INPUT); digitalWrite(button, HIGH); } void loop(void){ int val = digitalRead(button); if (val == LOW) { buttonNb += 1; delay(100); } if (buttonNb > 3) { buttonNb = 0; } if(buttonNb == 0){ Serial.println("Accueil"); } if(buttonNb == 1){ ohmmeter(); } if(buttonNb == 2){ voltmeter(); } if(buttonNb == 3){ continuity(); } }
Pôle commun
Comme les multimètres, je souhaitais avoir uniquement 2 fils de mesure : le « + » et la masse. Pour que le « + » soit commun entre l’ohmmètre, le voltmètre et le testeur de continuité, il faut que les circuits soient séparés car le voltmètre perturbe l’ohmmètre et vice versa.
Du coup, pour régler le problème, j’ai choisi de contrôler les liaisons Arduino via des relais, qui permettent de couper le circuit de l’un quand l’autre est en marche ! Imparable.
Les 2 entrées des 2 relais sont reliées sur les pin D3 et D4. Elles contrôlent les sorties relais, qui gèrent l’entrée « + » du voltmètre et le milieu du pont diviseur de l’ohmmètre.
Note : ces relais s’activent à l’état bas !
Voici le code de gestion du pôle commun.
const int pinRelais = 3; const int pinRelais2 = 4; void setup(void) { Serial.begin(9600); pinMode(pinRelais,OUTPUT); digitalWrite(pinRelais,HIGH); pinMode(pinRelais2,OUTPUT); digitalWrite(pinRelais2,HIGH); } void loop(void){ int val = digitalRead(button); if (val == LOW) { buttonNb += 1; delay(100); } if (buttonNb > 3) { buttonNb = 0; } if(buttonNb == 0){ digitalWrite(pinContinuity,LOW); } if(buttonNb == 1){ digitalWrite(pinRelais,HIGH); digitalWrite(pinRelais2,LOW); ohmmeter(); } if(buttonNb == 2){ digitalWrite(pinRelais,LOW); digitalWrite(pinRelais2,HIGH); voltmeter(); } if(buttonNb == 3){ digitalWrite(pinRelais,HIGH); digitalWrite(pinRelais2,HIGH) continuity(); } }
Assemblage final
L’assemblage, un peu compliqué car beaucoup de fil n’est pas très compliqué à réaliser. Voici quelques photos :
La suite ?
La suite sera une boite imprimée en 3D, comme d’habitude. L’alimentation générale se fera par une pile carrée 9V, avec un interrupteur. Des douilles bananes seront en sortie pour brancher des cordons bananes dessus.
Le code source
Le code source global est disponible sur github ici :
Bonjour Fabien,
Puis-je avoir votre contact SVP pour un petit projet ?
Merci
Salut Fabien. Génial tes programmes pour ma par, seul la partie voltmetre m’intéresse. Je cherche à faire un programme qui puisse surveiller une ou voir deux tensions en même temps et qui aurait comme utilité de déclencher un signal lumineux (led) lorsque la tension est trop basse… Tu penses que c’est réalisable ? Par exemple, surveillance d’une pile de 2 piles de 9v et que lorsqu l’une des deux arriverait au seuil de 7v, basculement de l’alimentation sur l’autre pile signalé par une led…
Merci pour tes lumières…?
Bonsoir,
il faut alors faire 2 fois le montage sur 2 ports de l’arduino.
Il faut gérer l’alimentation via un relais et le seuil bas activerait le relais de l’alim2 et fermerait le relais de l’alim 1 (moi je ferais comme ca mais il y a peut être d’autres solutions !!).
Oui c’est ce que je voudrais, mais dans les 2 sens… En gros, pendant que l’une travaille, l’autre pourrait être en charge et ainsi faire un cycle infini entre les 2 accus…
J’ai fait plusieurs essais sur arduino mais mes programmes sont loin d’être au point et ne démarrent même pas ??bref je sature la… Si vous pouviez m’aider sa serait cool.
Merci de m’avoir répondu c’est déjà beaucoup je voudrais pas abuser de votre temps…
Je pense que ce n’est pas une bonne solution de faire tourner les 2 en même temps, c’est source de problème. Pas simple l’histoire !
Est-ce que tu as pu faire l’article sur la boîte imprimé en 3d ?
Bonjour,
non finalement je ne l’ai jamais fait 🙁
Mais on en trouve plein d’équivalent sur le site thingiverse