Tutoriel · Débutant · 30 min de lecture
Lire des tensions analogiques : références CAN et diviseurs
analogRead rend un rapport, pas une tension. Choisissez une référence stable, dimensionnez un diviseur, et construisez un moniteur de batterie qui dit vrai.
Introduction
analogRead() est la fonction la plus accueillante sur Arduino et l’une des plus silencieusement trompeuses. Elle rend un nombre entre 0 et 1023, tout le monde traite ce nombre comme une tension, et la plupart du temps rien ne se passe mal.
Cela se passe mal sur un robot, car un robot a des moteurs, et les moteurs déplacent cela même par rapport à quoi ce nombre est mesuré.
analogRead rend un rapport
Le CAN ne mesure pas des volts. Il compare son entrée à une référence et rend compte du rapport :
reading = 1023 × V_in / V_ref
Sur un Arduino Uno, V_ref vaut par défaut AVCC — le rail 5 V de la carte. Donc analogRead() répond vraiment « quelle fraction du rail 5 V est ceci ? », et le convertir en volts en multipliant par 5/1023 n’est correct que tant que le rail vaut exactement 5 V.
Vous savez déjà que ce n’est pas le cas, dès que les moteurs tournent.
La référence est le bogue
Câblez une batterie via un diviseur vers A0 et regardez le nombre quand les moteurs démarrent.
Une coupure batterie basse construite sur la première conception fait l’inverse de son travail : plus le robot travaille dur, plus la batterie semble en forme. Et la panne est silencieuse, car chaque lecture individuelle est un rapport parfaitement valide.
Le correctif est une référence qui ne bouge pas. L’ATmega328P embarque une référence bandgap 1,1 V :
analogReference(INTERNAL); // 1.1 V on an Uno; INTERNAL1V1 on a Mega
analogRead(A0); // discard — the reference needs a moment to settle
Jetez toujours la première lecture après un changement de référence. La référence interne et le condensateur d’entrée ont besoin de temps, et le premier échantillon est pris avant qu’ils l’aient eu.
Dimensionner le diviseur
La référence vaut désormais 1,1 V et votre pack 8,4 V, le diviseur doit donc ramener le haut de plage juste sous la référence :
V_adc = V_pack × R2 / (R1 + R2)
Avec R1 = 68 kΩ et R2 = 10 kΩ, le rapport vaut 0,128, donc un pack plein de 8,4 V présente 1,077 V — juste sous la référence, en utilisant presque toute l’échelle. Trois nombres à vérifier sur tout diviseur conçu :
| Vérification | Ce diviseur | Pourquoi |
|---|---|---|
| Haut de plage contre référence | 1,077 V contre 1,1 V | Au-dessus de la référence et ça écrête à plat |
| Courant de repos | 108 µA | Draine 2,6 mAh par jour — négligeable face à 2000 mAh |
| Impédance de sortie (R1∥R2) | 8,7 kΩ | Garder sous ~10 kΩ, voir ci-dessous |
Comparez avec la version naïve — un diviseur 20 kΩ/10 kΩ lu contre le rail 5 V. Il place un pack plein à 2,80 V, soit 573 pas sur 1023 possibles, et il utilise 164 pas sur toute la plage 6,0–8,4 V du pack contre 286 pour la meilleure conception. Presque deux fois la résolution, pour les deux mêmes résistances et une ligne de code.
La résolution n’est pas la précision
Dix bits contre une référence 5 V font 4,88 mV par pas ; contre la référence 1,1 V, 1,07 mV. Aucun de ces nombres n’est votre précision.
Ce qui vous limite vraiment :
- Tolérance de référence. La bandgap vaut nominalement 1,1 V et varie de quelques pour cent entre puces. C’est une erreur d’échelle fixe, donc mesurez-la une fois par carte : injectez une tension connue, lisez les pas, et résolvez la vraie référence. Stockez cette constante. C’est une étape d’étalonnage, pas un raffinement optionnel.
- Bruit. L’alimentation d’un robot est bruitée, et moyenner est la réponse bon marché. Moyenner N échantillons réduit le bruit aléatoire de √N — 16 échantillons sont 4 fois plus silencieux, un bit utile de plus. Cela ne fait rien pour une erreur d’échelle.
- Impédance de source. Le CAN charge un petit condensateur d’échantillonnage-blocage via ce à quoi il est connecté. Une source haute impédance ne peut pas le remplir dans le temps imparti, et le résidu du canal lu précédemment est encore dedans.
Ce dernier point produit un bogue distinctif à nommer.
Des voies qui ressemblent à leurs voisines
Lisez A0 puis A1 avec des sources haute impédance et chaque lecture est tirée vers la précédente. Balayez un potentiomètre sur A0 et regardez A1 bouger en sympathie. Rien n’est mal câblé.
Deux correctifs, utilisables ensemble :
int readSettled(uint8_t pin) {
analogRead(pin); // charge the sample-and-hold on this channel
return analogRead(pin); // then take the one you keep
}
Lire deux fois et jeter la première donne au condensateur une seconde fenêtre d’échantillonnage pour atteindre la nouvelle tension. L’autre correctif est de baisser l’impédance de source — d’où le diviseur ci-dessus en 68 kΩ/10 kΩ plutôt que le 100 kΩ/100 kΩ plus net d’apparence qui donne 50 kΩ d’impédance de sortie.
Où cela apparaît sur un robot
- Suivi de batterie, comme ci-dessus — et c’est ce qui rend une coupure basse tension assez fiable pour protéger un pack Li-ion.
- Capteurs de ligne analogiques. Un réseau de réflectance IR donne une valeur continue par capteur, ce qui permet à un suiveur de ligne de calculer une position lisse plutôt qu’un drapeau gauche/droite. Ces capteurs sont lus contre le même rail que les moteurs affaissent, d’où une dérive d’étalonnage du suiveur de ligne quand la batterie se vide.
- Mesure de courant, un shunt ou capteur à effet Hall dont la sortie est une tension.
- Potentiomètres comme boutons de réglage, le moyen le plus amical de régler un gain PID sans reflasher.
- Pas pour un capteur 5 V sur carte 3,3 V. Un ESP32 ou un Raspberry Pi exige le diviseur pour la protection, pas seulement pour la plage.
Quand ça tourne mal
| Symptôme | Généralement |
|---|---|
| La lecture batterie monte quand les moteurs démarrent | Référencée au rail affaissé ; utilisez INTERNAL |
| Lecture bloquée à 1023 | Entrée au-dessus de la référence — rapport de diviseur trop élevé |
| Une voie recopie celle lue avant elle | Impédance de source trop haute ; lisez deux fois et jetez |
| Les lectures sautent de dizaines de pas | Bruit d’alimentation ; moyennez, et vérifiez les rails d’alimentation |
| Tension systématiquement fausse de quelques pour cent | Référence interne non étalonnée — mesurez-la une fois |
Première lecture fausse après analogReference() |
Attendu ; jetez-la |
| L’étalonnage du capteur de ligne dérive quand la batterie se vide | Lectures référencées au rail sur un rail qui chute |
| Seulement 15 % de la plage utilisée | Diviseur dimensionné pour 5 V lu contre 1,1 V |
La règle qui évite l’essentiel : décidez de votre référence avant tout le reste. Chaque nombre rendu par le CAN est relatif à elle, donc une référence qui bouge fait de chaque lecture une histoire sur deux choses à la fois.
Explorer le graphe
Fait partie de ces réalisations
Les projets et parcours d'apprentissage qui incluent ce tutoriel.
Pour aller plus loin