Réponse de l'ADC d'un Arduino

De Wiki LOGre
Aller à : navigation, rechercher
Langue : Français  • English

La fonction analogRead() de l'Arduino renvoie un entier compris entre 0 et 1023. Comment convertir cette valeur en une vraie tension en volts ? On trouve des informations contradictoires sur le Web, les formules les plus courantes étant

[math]V = V_\text{ref} \times \frac{n}{1023}[/math]

et

[math]V = V_\text{ref} \times \frac{n}{1024},[/math]

Vref est la tension de référence (typiquement 5 V) et n est la valeur lue. La différence est faible, mais elle a alimenté de longues discussions. J'ai donc voulu trancher expérimentalement. Cette expérience a aussi fourni des informations sur le niveau de bruit et la capacité du bruit à augmenter la résolution de la mesure.

Formules classiques

Les formules que j'ai trouvées sur le Web peuvent toutes se mettre sous la forme

[math]V = V_\text{ref} \times \frac{n+n_0}{E},[/math]

n0 est un offset (typiquement zéro) et E un facteur d'échelle.

En réalité, avec un convertisseur idéal à 10 bits, l'intervalle des tensions mesurables est divisé en 1024 sous-intervalles, chacun correspondant à un résultat possible. La formule ci-dessous est alors sensé donner le milieu de l'intervalle associé à la valeur n, sauf éventuellement pour les valeurs extrêmes 0 et 1023.

Dans ce qui suit, chaque formule est caractérisée par ses valeurs de E et n0, et pour chacune est représenté le découpage de l'intervalle mesurable en les 1024 sous-intervalles.

E = 1023, n0 = 0 : tutoriels Arduino

Beaucoup de blogs et tutoriels Arduino utilisent cette formule, à commencer par le tutoriel officiel Read Analog Voltage. Le découpage de l'intervalle mesurable est alors comme ceci :

   0                                         Vref
   |---|-------|------- ⋅⋅⋅ ------|-------|---|
   ^       ^                          ^       ^
   0       1                        1022    1023

En haut, l'intervalle de tensions entre 0 et Vref. En bas, les tensions données par la formule pour chaque valeur de n sont repérées par le caractère ^.

On remarque que, avec cette formule, le premier et le dernier intervalle sont moitié moins larges que tous les autres.

E = 1024, n0 = 0 : fiche technique de Atmel

C'est la formule qu'on trouve dans les fiches techniques des microcontrôleurs AVR, et notamment sur celle de l'ATmega328P (en bas de page). Étant donné que c'est la documentation du constructeur, c'est a priori la formule de référence.

   0                                         Vref
   |---|-------|--- ⋅⋅⋅ --|-------|-----------|
   ^       ^                  ^       ^       ^
   0       1                1022    1023   (1024)

Ici, le premier intervalle est moitié moins large que les autres, alors que le dernier fait 1,5 fois la largeur normale.

E = 1024, n0 = 0,5 : Nick Gammon

J'ai trouvé cette formule sur le site de Nick Gammon : ADC conversion on the Arduino (analogRead) – How to interpret the results. Elle n'est pas très répandue, mais j'apprécie le fait qu'elle divise l'intervalle mesurable en 1024 intervalles d'égale largeur :

   0                                         Vref
   |-------|-------|--- ⋅⋅⋅ --|-------|-------|
       ^       ^                  ^       ^
       0       1                1022    1023

Technique de mesure

Je génère la tension variable à l'aide d'un potentiomètre et je la mesure à la fois avec un multimètre et avec un Arduino. Le circuit est différent suivant que je veux mesurer des tensions proches de zéro où proches de Vref :

     proche de 0       proche de Vref
   
         Vcc               Vcc
         ╶┬╴               ╶┬╴
         ┌┴┐                ├────┐
         │ │1 MΩ            │  ╭─┴─╮
         │ │               ┌┴┐ │ V │
         └┬┘         10 kΩ │ │ ╰─┬─╯
          │                │ │←──┴─── Ain
         ┌┴┐               └┬┘
   10 kΩ │ │←──┬─── Ain     │
         │ │ ╭─┴─╮         ┌┴┐
         └┬┘ │ V │         │ │
          │  ╰─┬─╯         │ │1 MΩ
          ├────┘           └┬┘
         ╶┴╴               ╶┴╴
         GND               GND
Lecture de l'ADC d'un Arduino. En haut à gauche : les mesures moyennées sont affichées par l'Arduino sous forme de bargraphe. À droite : les résultats sont reportés à la main dans vim.

Ceci permet d'avoir une bonne résolution, à la fois pour le réglage au potentiomètre et pour la mesure au multimètre (symbolisé par le rectangle arrondi avec un « V »).

L'Arduino est programmé pour mesurer en continu (« free running mode ») à raison de une mesure toutes les 104 µs. Ces mesures passent par un filtre passe-bas du premier ordre avec une constante de temps de 4096 mesures, soit environ 426 ms. Le résultat est affiché sur le port série sous forme de bargraphe, avec une résolution de 1/128 de pas de convertisseur.

Résultats

Ci dessous les résultats de mes mesures sur un STEMTera Breadboard, qui est basé sur un ATmega328P et est compatible avec un Arduino Uno. D'abord, le bas de l'échelle, soit les potentiels compris entre 0 et environ 50 mV :

ADC-Arduino-bottom.png

Sur ce graphique, la valeur moyennée est tracée en fonction de la tension d'entrée. Les croix rouges représentent les mesures, la courbe continue est un ajustement.

Ensuite, les mesures pour le haut de l'échelle, soit environ Vref − 50 mV à Vref :

ADC-Arduino-top.png

La courbe continue représente l'ajustement, qui est commun aux deux jeux de mesures. Cet ajustement donne E = 1026,1 et n0 = 2,2, soit la formule

[math]V = V_\text{ref} \times \frac{n+2,2}{1026,1}[/math]

À noter que la courbe ajustée comporte aussi un terme oscillant, qui permet d'obtenir une succession de marches et qui représente donc l'effet de la discrétisation.

J'ai ensuite refait mes mêmes mesures sur un Arduino Uno rev. 2 et un Uno rev. 3, avec des résultats similaires. Voici un tableau comparatif :

carte E n0
STEMTera 1026,1 2,2
Uno rev. 2 1026,3 2,4
Uno rev. 3 1026,1 2,3

Discussion

Les valeurs mesurées de E et n0 représentent des constantes d'étalonnage spécifiques à chaque Arduino. Il est intéressant de constater que ces valeurs sont plus proches les unes des autres qu'elles ne le sont des valeurs nominales (1024 et 0). À partir de ces mesures, j'aurais envie de proposer la formule

[math]V = V_\text{ref} \times \frac{n+2}{1026}[/math]

pour un ADC non étalonné. Mais en ayant caractérisé uniquement trois Arduinos, l'échantillonnage est insuffisant pour pouvoir généraliser de façon fiable. En tout cas, la polémique de 1023 contre 1024 n'est pas pertinente, car la différence entre ces valeurs est inférieure à l'erreur d'étalonnage.

Un autre aspect intéressant de ces mesures est le fait que les courbes prises sur le STEMTera ressemblent à une succession de marches. On trouve beaucoup d'articles qui expliquent qu'on peut augmenter la résolution de mesure en moyennant. Les courbes précédentes montrent que même en moyennant beaucoup (4096 mesures), on observe toujours la discrétisation initiale. Les marches ne sont pas raides pour autant : le moyennage combiné au bruit a pour effet de les adoucir. Le fait qu'elles ne soient pas complètement éliminées montre seulement que le bruit dans cette expérience est insuffisant pour vraiment augmenter la résolution. Pourtant, aucune précaution n'a été prise pour limiter le bruit : le potentiomètre était manipulé à la main, sur un breadboard.

Les courbes mesurées sur les deux Arduinos Uno (pas montrées ici) ne montrent quasiment pas d'oscillations. Ceci montre que le bruit intrinsèque sur ces Arduinos est plus grand que sur le STEMTera, et suffisant pour permettre au moyennage d'augmenter la résolution.

On trouve sur le Web des tentatives d'amélioration de la résolution qui se basent sur l'injection de bruit synthétique. Les mesures ci-dessus montrent que l'ajout de bruit peut être nécessaire... ou pas suivant le niveau de bruit intrinsèque du convertisseur, qui curieusement varie d'un Arduino à un autre.