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

multimetre v0.4_bb

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 :

ohmmetre_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 :

7 Comments

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.