Entrées analogiques

En bref

  • Arduino Uno possède 6 entrées analogiques, A0, A1, A2, A3, A4 et A5
  • Pour mesurer l'entrée analogique A0 par exemple:
  •                             
    int N = analogRead(A0); // retourne un nombre compris entre 0 et 1023
    float V = N * 5.0 / 1024.0; // Valeur en Volts de la tension sur A0
                                
                            
    Dans l'instruction ci-dessus, Il est important que les opérandes soient de type float pour empêcher le compilateur d'effectuer une division entière, d'ou l'utilisation de '5.0' et non pas '5'


Convertisseur Analogique Numérique

Un convertisseur analogique-numérique (CAN ou ADC: Analog to Digital Converter ) est un dispositif électronique qui transforme un signal analogique en une valeur numérique entière exploitable par un système numérique.

Pour simplifier nous allons considérer un ADC qui fournit une valeur numérique sur deux bits

  • Avec 2 bits, le nombre N peut prendre \( 2^2 = 4\) combinaisons (00 = 0, 01 = 1, 10 = 2, 11 = 3)
  • Le convertisseur divise sa dynamique (Vref = 5V) en 4 subdivisions et affecte les valeurs de N aux tensions analogiques comme indiqué sur la figure ci-dessous
  • La subdivision \( \Delta = \frac{V_{ref}}{2^2} \) constitue la résolution du Convertisseur. Dans notre cas \( \Delta = \frac{5V}{4}=1.25V \)
  • Pour remonter à la valeur de V à partir de N, on utilise la formule : $$ V = N \times \Delta = N \times \frac{V_{ref}}{2^2} = N \times \frac{5V}{4}$$
  • On constate que la valeur de V ainsi déterminée peut être entachée d'un erreur qui peut atteindre \( Err_{max}=\frac{\Delta}{2} \). Pour les valeurs de V supérieures à 4.375V, qui ne constituent qu'une toute petite fraction de la dynamique totale, l'erreur peut atteindre Δ
    le tableau ci-dessous illustre cette constatation pour quelques valeurs de V
  • On constate que l'erreur de numérisation \(Err_{max}\) dépend du nombre de bits \(n\) du convertisseur: \( Err_{max}=\frac{\Delta}{2} = \frac{1}{2} \frac{V_{ref}}{2^n}\). Plus le nombre de bits (n) du convertisseur est important, plus l'erreur de numérisation est faible

Le Convertisseur de l'ARDUINO

  • Le processeur ATmega328P de l'Arduino UNO possède un ADC de 10 bits,
  • La résolution est \( \Delta = \frac{V_{ref}}{2^{10}} \),
  • Avec une dynamique de 5 Volts, la résolution est \( \Delta = \frac{5V}{1024}=4,883 mV \)
  • L'erreur de numérisation est \( Err_{max}=\frac{\Delta}{2} = 2.44 mV\)
  • L'Arduino dispose d'un seul ADC, mais de plusieurs entrées analogiques (6 sur Arduino Uno). Ceci est rendu possible grâce à un multiplexeur analogique intégré, qui permet de sélectionner une des entrées analogiques pour la conversion,
  • L'ADC affecte la valeur de N à l'entrée analogique V comme indiqué sur la figure ci-dessous:
  • Le calcul de V à partir de N se fait par la formule :

    V = N × 5 / 1024

  • Pendant longtemps (comme beaucoup de gens), j'ai utilisé 1023 à la place de 1024. On obtient quasiment les mêmes valeurs. Le résultat est légèrement meilleur pour V voisin de 5V mais pas pour le reste de l'intervalle. Après avoir consulté le datasheet de l'ATmega328P au paragraphe: ADC Conversion Result, j'utilise 2024 qui correspond mieux au fonctionnement interne de l'ADC. Il est vrai que la différence est minime, mais il vaut mieux se conformer aux spécifications du datasheet.

Amélioration de la précision grace à Vref

  • Par défaut, le convertisseur de l'Arduino travaille dans l'intervalle [0V , 5V], C'est la dynamique ΔV du convertisseur. La résolution est donnée par \( \Delta = \frac{\Delta V}{2^n} \)
  • Pour l'ADC de l'Arduino, n = 10 => \( \Delta = \frac{5}{1024}=4,883 mV \) => Erreur max = Δ/2 = 2.44mV
  • Si la tension à mesurer est issue d'un capteur dont la sortie est toujours comprise dans l'intervalle [0V , 1V], on gagnerait on précision si on peut obliger l'ADC à travailler avec une dynamique ΔV = 1V.
    On aura une résolution Δ = 1V/1024 = 0.97 mV et une erreur max = Δ/2 = 0.49 mV
  • Ceci est possible car l'ADC de l'Arduino travaille dans l'intervalle [0V , Vref]. Par défaut Vref = 5V mais on peut la modifier
  • Pour modifier la tension de référence, on utilise la fonction analogReference() et éventuellement l'entrée AREF de l'Arduino
  •                             
    analogReference(DEFAULT);  // Vref = 5V , errmax = 2.44 mV
    analogReference(INTERNAL);  // Vref = 1.1 V , errmax = 0.537 mV
    analogReference(EXTERNAL);  // Vref = entrée AREF , errmax = Vref/1024/2
                                
                            


Exemple basique

Chaque 1/2 seconde, on prend une mesure de l 'entrée A0 et on affiche le résultat sur le moniteur Série

Chaque 1/2 seconde, on mesure A0 et on affiche sur le moniteur Série
    
void setup() {
  Serial.begin(9600);
}

void loop() {
  int N = analogRead(A0);
  float V = N * 5.0 / 1024.0;
  Serial.print("N = ");
  Serial.print(N);
  Serial.print("  => V = ");
  Serial.print(V);
  Serial.println(" Volts");
  delay(500);
}
    

Exemple: Voltmètre à 6 canaux

Chaque 1/2 seconde, on mesure les 6 entrées analogiques et on affiche le résultat sur un afficheur LCD

Voltmètre 6 canaux
                        
#include <LiquidCrystal.h>
LiquidCrystal   lcd(12, 10, 5, 4, 3, 2);
void setup() {
  lcd.begin(16, 2);
}

void loop() {
  float V;
  lcd.clear();
  V = analogRead(A0) * 5.0 / 1024.0;
  lcd.print(V);
  lcd.print("  ");
  V = analogRead(A1) * 5.0 / 1024.0;
  lcd.print(V);
  lcd.print("  ");
  V = analogRead(A2) * 5.0 / 1024.0;
  lcd.print(V);
  lcd.setCursor(0, 1);
  V = analogRead(A3) * 5.0 / 1024.0;
  lcd.print(V);
  lcd.print("  ");
  V = analogRead(A4) * 5.0 / 1024.0;
  lcd.print(V);
  lcd.print("  ");
  V = analogRead(A5) * 5.0 / 1024.0;
  lcd.print(V);
  delay(500);
}
                        
                    


Exemple: Comparatif Vref=5V avec Vref=1.1V

  • Dans cet exemple, on mesure une tension de 0.5V = 500mV, d'abord ave Vref=5V ensuite avec Vref=1.1V
  • Le programme a été essayé sur Proteus Isis
  • Les résultat montrent clairement l'intérêt de travailler avec la tension de référence interne (Vref=1.1V)
  • Il est évident que si on veut mesurer une tension > 1.1V, on ne peut pas utiliser la tension de référence interne
Comparatif Vref
                        
void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println("\r\nMesure d'une tension de 0.5V = 500mV");
  analogReference(DEFAULT);
  int N = analogRead(A0);
  float V = N * 5000.0 / 1024.0;
  Serial.print("Vref=5V   =>  ");
  Serial.print(V, 3);
  Serial.print(" mV => erreur = ");
  Serial.print(500 - V, 3);
  Serial.println(" mV");
  
  analogReference(INTERNAL);
  N = analogRead(A0);
  V = N * 1100.0 / 1024.0;
  Serial.print("Vref=1.1V =>  ");
  Serial.print(V, 3);
  Serial.print(" mV => erreur = ");
  Serial.print(500 - V, 3);
  Serial.println(" mV");  delay(1000);
}          
                        
                    



Mise en forme des signaux analogiques

L'ADC de l'Arduino ne peut numériser que les tensions comprises entre 0V et 5V. Si le signal analogique à numériser est trop faible, il faut l'amplifier avant de le numériser. S'il contient une portion négative, il faut le décaler vers le haut pour que toute ses valeur soient positives. Si le signal est trop grand, il faut l'atténuer pour qu'il rentre dans l'intervalle [0V , 5V]

En résumer, avant de numériser un signal, il faut s'assurer que sa valeur minimale est >= à 0V et que sa valeur maximale est <= 5V.

Les montages ci-dessous peuvent servir à la réalisation de cette tâche



Exemple :

  • Le signal à mesurer est issu d'un capteur analogique qui fournit des valeurs comprises dans l'intervalle [-0.5V , +0.5V]
  • Il faut le transformer pour pour le ramener dans l'intervalle [0V , 5V]
  • On va utiliser l'amplificateur décaleur. La relation entre l'entrée et la sortie est Vs = A Ve + B Vr
  • La dynamique du signal d'entrée est ΔVe = 1V, celle du signal de sortie est ΔVs = 5 => le gain de l'ampli sera A = 5/1 = 5
  • Avec ce gain, le signal de sortie serait compris entre -2.5V et +2.5V donc il faut le décaler vers le haut de 2.5V => B Vr = 2.5
  • Si on prend Vr = 5V => B = 0.5 => R2/R1 = A/B = 5/0.5 = 10 => on prend R2=10k , R1 = 1k
  • Rb/Ra = A+B-1 = 5 + 0.5 - 1 = 4.5 => On prend Rb=45k , Ra = 10k