Convertisseur analogique-numérique (ADC) avec Arduino et ESP32
Qu'est-ce qu'un ADC (CAN) ? Analogique et numérique, résolution 10 et 12 bits, analogReference, conversion en volts, ADC2 de l'ESP32 et réduction du bruit.
Un ADC (convertisseur analogique-numérique, ou CAN) est le circuit qui transforme la tension présente sur une broche, qui peut varier en continu, en un nombre que le microcontrôleur peut exploiter. Chaque fois que tu appelles analogRead() sur un Arduino, ce convertisseur travaille en coulisse : l'ADC 10 bits de l'Arduino Uno transforme une tension comprise entre 0 et 5 V en un nombre de 0 à 1023, tandis que les ADC 12 bits de l'ESP32 et du Raspberry Pi Pico transforment environ 0–3,3 V en un nombre de 0 à 4095. L'ADC est la clé pour lire tout composant à sortie analogique : potentiomètres, LDR, capteurs d'humidité du sol, joysticks et capteurs de température.
Dans ce guide, tu vas découvrir la différence entre signaux analogiques et numériques, comment un ADC convertit une tension en nombre étape par étape, et comment la résolution et la tension de référence influencent tes mesures. Avec des chiffres réels, nous verrons la formule qui convertit une mesure en volts, la modification de la plage de mesure avec analogReference, la fréquence d'échantillonnage et des moyens pratiques de réduire le bruit. Nous aborderons aussi l'ADC de l'ESP32, non linéaire aux extrémités, le conflit entre l'ADC2 et le Wi-Fi et le réglage d'atténuation, l'utilisation de l'ADC du Raspberry Pi Pico en MicroPython et, pour finir, une courte introduction au DAC, qui fait exactement l'inverse.

Quelle est la différence entre un signal analogique et un signal numérique ?
Un signal analogique est une grandeur qui peut prendre une infinité de valeurs dans une plage donnée et qui varie de façon continue dans le temps. Quand la tension sur la broche centrale d'un potentiomètre passe de 0 V à 5 V, elle traverse toutes les valeurs intermédiaires, comme 1,2 V, 1,21 V ou 1,215 V ; l'onde sonore d'un micro, la tension d'une thermistance qui varie avec la température ou la tension d'une pile qui baisse lentement sont aussi analogiques. Un signal numérique, lui, ne connaît que certains niveaux. Dans le monde de la logique de l'Arduino, il y en a deux : LOW (0) et HIGH (1). Sur l'Uno, une entrée numérique considère tout ce qui est en dessous d'environ 1,5 V comme LOW et tout ce qui dépasse 3,0 V comme HIGH ; la zone intermédiaire est indéfinie. C'est pourquoi digitalRead() ne fait pas la différence entre 3,7 V et 4,2 V sur une batterie et répond HIGH dans les deux cas. La force du signal numérique est sa résistance au bruit : 4,6 V et 5,0 V signifient le même HIGH. Pour mesurer, enregistrer ou utiliser dans un calcul une valeur analogique, il faut d'abord la convertir en nombre, autrement dit en valeur numérique, et c'est le rôle de l'ADC.
Qu'est-ce qu'un ADC et comment fonctionne-t-il ?
Le travail d'un ADC se résume en deux étapes. La première est l'échantillonnage : au moment de la mesure, le convertisseur copie la tension d'entrée sur un petit condensateur (circuit d'échantillonnage-blocage) et la maintient constante jusqu'à la fin de la conversion ; sur l'ATmega328P, ce condensateur fait environ 14 pF. La seconde est la quantification : la tension maintenue est arrondie au palier le plus proche d'une échelle qui divise la tension de référence en paliers égaux, et le numéro de ce palier est renvoyé comme résultat. Les ADC de l'Arduino Uno, de l'ESP32 et du Pico sont tous du type à approximations successives (SAR, Successive Approximation Register). Un ADC SAR fonctionne comme un jeu de devinette : il essaie d'abord la moitié de la référence, met le bit de poids fort à 1 si l'entrée est plus grande et le laisse à 0 si elle est plus petite, puis essaie la moitié de la plage restante et répète l'opération pour chaque bit. Un ADC 10 bits trouve ainsi le bon palier parmi 1024 possibilités en seulement 10 comparaisons. Pour simplifier, le tableau montre comment un ADC 4 bits avec une référence de 5 V mesure une entrée de 3,2 V :
| Étape | Bit testé | Tension de comparaison | L'entrée (3,2 V) est-elle plus grande ? | Bits du résultat |
|---|---|---|---|---|
| 1 | Bit 3 (vaut 8) | 8 / 16 × 5 = 2,500 V | Oui → 1 | 1000 |
| 2 | Bit 2 (vaut 4) | 12 / 16 × 5 = 3,750 V | Non → 0 | 1000 |
| 3 | Bit 1 (vaut 2) | 10 / 16 × 5 = 3,125 V | Oui → 1 | 1010 |
| 4 | Bit 0 (vaut 1) | 11 / 16 × 5 = 3,4375 V | Non → 0 | 1010 |
| Résultat | Tous les bits testés | 1010 = 10 → 10 × 5 / 16 = 3,125 V | Erreur de 0,075 V (un palier = 0,3125 V) | 1010 |
L'écart de 0,075 V dans le résultat est l'erreur de quantification, et aucun ADC n'y échappe : si la tension réelle se situe entre deux paliers, l'ADC ne peut indiquer que l'un des deux. L'erreur reste inférieure à un palier (LSB) ; plus le palier est petit, plus la mesure est fine. Comme le condensateur d'échantillonnage doit se charger à chaque mesure, la résistance de la source qui attaque l'ADC compte aussi : la fiche technique de l'ATmega328P recommande une impédance de sortie d'environ 10 kΩ ou moins ; un pont diviseur de tension plus résistif n'arrive pas à charger le condensateur à temps et les mesures dérivent. En plus du type SAR des microcontrôleurs, il existe d'autres familles d'ADC. Les ADC sigma-delta sont lents mais très précis : le HX711 utilisé dans les projets de pesée offre 24 bits, et le module ADS1115 relié en I2C, 16 bits. Les ADC flash utilisent un comparateur distinct pour chaque palier ; ils sont extrêmement rapides et équipent par exemple les oscilloscopes.
Résolution de l'ADC : que signifient 10 bits et 12 bits ?
La résolution indique en combien de paliers l'ADC découpe sa plage de mesure. Un ADC de N bits produit 2^N paliers : 10 bits correspondent à 1024 paliers (0–1023), 12 bits à 4096 (0–4095) et 16 bits à 65 536. La tension d'un palier s'appelle le LSB (bit de poids faible) et se calcule avec LSB = Vref / 2^N. Sur l'Arduino Uno, cela donne 5 V / 1024 = 4,88 mV, et sur l'ESP32 et le Pico, 3,3 V / 4096 = 0,81 mV. L'Uno ne voit donc pas les variations inférieures à 4,88 mV ; avec un LM35 qui délivre 10 mV/°C, cela représente un pas d'environ 0,5 °C. Mais résolution et précision ne sont pas la même chose. Le bruit, la non-linéarité et l'erreur de référence d'un ADC rendent inutiles une partie des bits annoncés sur le papier. On mesure cela avec le nombre effectif de bits (ENOB) : l'ADC du RP2040 du Raspberry Pi Pico fournit un résultat sur 12 bits, mais selon sa fiche technique son nombre effectif de bits est de 8,7. Comparons les ADC des trois cartes :
| Caractéristique | Arduino Uno R3 | ESP32 (WROOM-32) | Raspberry Pi Pico |
|---|---|---|---|
| Résolution de l'ADC | 10 bits (0–1023) | 12 bits (0–4095) | 12 bits (mis à l'échelle 0–65535 en MicroPython) |
| Entrées analogiques | 6 (A0–A5 ; A0–A7 sur le Nano) | 18 canaux : 8 sur ADC1, 10 sur ADC2 | 3 broches (GP26–GP28) + VSYS/3 (GP29) + capteur de température |
| Plage de mesure par défaut | 0–5 V | Environ 0–3,1 V (atténuation 11 dB) | 0–3,3 V (ADC_VREF) |
| Un palier (LSB) | 4,88 mV | Environ 0,8 mV | 0,81 mV |
| Options de référence | DEFAULT (5 V), INTERNAL (1,1 V), EXTERNAL (AREF) | Atténuation : 0 ; 2,5 ; 6 et 11 dB | Référence externe sur la broche ADC_VREF |
| Fréquence d'échantillonnage | Environ 10 000 mesures/s | 20 kHz – 2 MHz en mode continu (DMA) | 500 000 mesures/s en matériel |
| Remarque sur la précision | Erreur absolue ±2 LSB | Non linéaire aux extrémités, étalonnage nécessaire | ENOB de 8,7 bits, décalage d'environ 30 mV |
| Sortie analogique (DAC) | Aucune (on utilise le PWM) | 2 canaux, 8 bits (GPIO 25 et 26) | Aucune (on utilise le PWM) |
Formule pour convertir la valeur de l'ADC en volts
Le nombre renvoyé par l'ADC ne veut rien dire tout seul ; pour le convertir en tension, tu utilises la tension de référence et le nombre de paliers : Tension = valeur ADC × Vref / 2^N. Sur l'Arduino Uno, cela donne V = valeur × 5,0 / 1024 ; si analogRead() a renvoyé 512, la tension sur la broche est de 512 × 5 / 1024 = 2,50 V. Dans l'autre sens, tu trouves le nombre correspondant à une tension avec valeur = V × 1024 / Vref : 3,3 V se lit environ 675 sur l'Uno. Dans beaucoup d'exemples, on divise par 1023 au lieu de 1024. La fiche technique de l'ATmega328P donne la formule ADC = Vin × 1024 / Vref ; la valeur maximale, 1023, représente un palier sous Vref. Diviser par 1023 affiche exactement 5,00 V pour la valeur maximale, mais décale toutes les valeurs d'environ 0,1 %. Cet écart est plus petit que l'erreur propre de l'ADC (±2 LSB), donc les deux conviennent ; l'important est de rester cohérent dans le projet. La vraie grosse source d'erreur, c'est Vref lui-même : la broche 5V d'un Uno alimenté en USB se situe souvent entre 4,7 et 5,1 V, et écrire 5,0 dans la formule entraîne jusqu'à 5 % d'erreur. Pour des mesures précises, mesure donc la broche 5V avec un multimètre et mets la vraie valeur dans le code. L'unique entrée analogique de l'ESP8266 (A0) est elle aussi sur 10 bits ; la puce mesure 0–1 V, et le pont diviseur intégré sur des cartes comme la NodeMCU et la Wemos D1 Mini étend cette plage à environ 0–3,2 V.
| Carte et réglage | Plage lue | Conversion en volts | Exemple |
|---|---|---|---|
| Arduino Uno / Nano (DEFAULT, 5 V) | 0–1023 | V = valeur × 5,0 / 1024 | 768 → 3,75 V |
| Uno, analogReference(INTERNAL) | 0–1023 | V = valeur × 1,1 / 1024 | 512 → 0,55 V |
| ESP32 (11 dB) | 0–4095 | Étalonné : analogReadMilliVolts() / 1000 ; approximatif : valeur × 3,3 / 4095 | 1650 mV → 1,65 V |
| Raspberry Pi Pico (read_u16) | 0–65535 | V = valeur × 3,3 / 65535 | 32768 → 1,65 V |
| ESP8266 NodeMCU / Wemos D1 Mini (A0) | 0–1023 | V = valeur × 3,2 / 1024 | 512 → 1,60 V |
Câbler un potentiomètre : Arduino, ESP32 et Pico
| Broche du potentiomètre | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| Broche extérieure 1 | 5V | 3V3 | 3V3(OUT) (broche 36) |
| Broche centrale (signal) | A0 | GPIO 34 (ADC1_CH6) | GP26 / ADC0 (broche 31) |
| Broche extérieure 2 | GND | GND | AGND (broche 33) ou GND |
| Condensateur antiparasite (facultatif) | 100 nF entre A0 et GND | 100 nF entre GPIO 34 et GND | 100 nF entre GP26 et AGND |
Pas à pas : ta première mesure ADC avec Arduino
- Monte le circuit : relie les broches extérieures d'un potentiomètre de 10 kΩ au 5V et au GND, et sa broche centrale à A0.
- Mesure la broche 5V : mesure au multimètre la tension entre 5V et GND et reporte-la dans la constante VREF du code (par ex. 4.93).
- Téléverse le code : ouvre le sketch ci-dessous dans l'IDE Arduino, choisis la carte et le port, puis téléverse-le.
- Ouvre le moniteur série : règle-le sur 9600 bauds et regarde la valeur de l'ADC varier entre 0 et 1023 quand tu tournes le bouton (détails dans le guide du moniteur série).
- Vérifie : mesure au multimètre entre A0 et GND et compare avec la tension affichée ; l'écart devrait rester autour de 10–20 mV.
1// Potansiyometreyi ADC ile okuma / Reading a potentiometer with the ADC
2// Kenar bacaklar 5V ve GND'ye, orta bacak A0'a / Outer legs to 5V and GND, wiper to A0
3const int POT_PIN = A0;
4const float VREF = 5.0; // 5V pininde ölçtüğün gerilim / voltage you measured on the 5V pin
5
6void setup() {
7 Serial.begin(9600);
8}
9
10void loop() {
11 int raw = analogRead(POT_PIN); // 0-1023 arası sayı / number between 0-1023
12 float volts = raw * VREF / 1024.0; // sayıyı volta çevir / convert the number to volts
13 int percent = map(raw, 0, 1023, 0, 100); // yüzdeye ölçekle / scale to percent
14
15 Serial.print(F("ADC: "));
16 Serial.print(raw);
17 Serial.print(F(" Gerilim / Voltage: "));
18 Serial.print(volts, 3);
19 Serial.print(F(" V Yuzde / Percent: "));
20 Serial.println(percent);
21 delay(200);
22}analogRead() termine une mesure en environ 100 µs et renvoie un entier entre 0 et 1023. Le code convertit d'abord ce nombre en volts avec la formule, puis en pourcentage avec map(). Comme map() travaille en arithmétique entière, il supprime la partie décimale ; si tu as besoin d'un résultat à virgule, fais le calcul toi-même avec un float. Il s'agit d'une mesure ratiométrique : comme le potentiomètre et l'ADC sont alimentés par le même 5 V, la position du bouton, donc la valeur de l'ADC, ne change pas même si l'alimentation descend à 4,9 V ; seule la tension calculée change. Il en va de même pour les capteurs lus via un pont diviseur, comme les LDR et les CTN. En revanche, quand tu mesures la tension d'une pile ou un capteur à sortie fixe en mV comme le LM35, la valeur réelle de Vref se répercute directement sur le résultat.
Tension de référence et analogReference
La tension de référence (Vref) est le haut de l'échelle de l'ADC : si la tension d'entrée atteint ou dépasse Vref, le résultat reste bloqué à la valeur maximale (1023). Réduire Vref rétrécit la plage de mesure, mais rend chaque palier plus petit, ce qui permet de mesurer plus finement les petits signaux. Sur l'Arduino Uno, tu choisis la référence avec la fonction analogReference(). Avec l'option INTERNAL, Vref passe à 1,1 V et un palier descend à 1,07 mV ; tu peux lire un LM35 (10 mV/°C) par pas d'environ 0,1 °C, mais en contrepartie rien au-dessus de 1,1 V, soit 110 °C, n'est mesurable. La référence interne de 1,1 V elle-même peut varier entre 1,0 et 1,2 V d'une puce à l'autre ; pour les projets précis, un étalonnage unique au multimètre s'impose. Les premières mesures après un changement de référence peuvent être fausses, comme le signale aussi la documentation Arduino, donc jeter quelques mesures après le changement est une bonne habitude. Par ailleurs, ce réglage s'applique à toutes les broches analogiques de la carte à la fois. Les options diffèrent selon la carte :
| Option | Référence | Cartes | Quand l'utiliser ? |
|---|---|---|---|
| DEFAULT | 5 V (3,3 V sur les cartes en 3,3 V) | Uno, Nano, Mega, Leonardo | Capteurs ratiométriques par rapport à l'alimentation : potentiomètre, LDR, joystick |
| INTERNAL | 1,1 V (ATmega328P) ; 2,56 V sur le Leonardo | Uno, Nano, Leonardo (pas sur le Mega) | Capteurs à faible tension comme le LM35 |
| INTERNAL1V1 / INTERNAL2V56 | 1,1 V / 2,56 V | Mega uniquement | Petits signaux sur le Mega |
| EXTERNAL | La tension sur la broche AREF (0–5 V) | Uno, Nano, Mega | Utiliser ta propre référence de précision (par ex. 2,5 V ou 4,096 V) |
| AR_INTERNAL | Environ 1,43 V (référence interne de la puce) | Uno R4 Minima et WiFi | Petits signaux sur l'Uno R4 |
Fréquence d'échantillonnage : combien de mesures par seconde ?
La fréquence d'échantillonnage correspond au nombre de mesures que l'ADC peut faire en une seconde. Sur l'Arduino Uno, l'horloge de l'ADC est réglée à 125 kHz en divisant les 16 MHz par 128, et une conversion dure 13 cycles d'horloge ; c'est pourquoi analogRead() prend environ 100 µs et qu'on peut faire au maximum à peu près 10 000 mesures par seconde. Pour des grandeurs qui varient lentement, comme la température, la lumière ou la tension d'une batterie, c'est largement suffisant ; souvent, 10 mesures par seconde suffisent même. Pour les signaux rapides, c'est le théorème de Nyquist qui s'applique : pour capter un signal sans le perdre, il faut échantillonner au moins deux fois plus vite que sa fréquence la plus élevée, et en pratique on préfère 5 à 10 fois. Pour voir le ronflement secteur à 50 Hz, il faut au moins 100 mesures/s, et pour enregistrer la voix jusqu'à 4 kHz, au moins 8 000 mesures/s. Si tu as besoin de mesurer plus vite sur l'Uno, tu peux réduire le prédiviseur de l'ADC : avec ADCSRA = (ADCSRA & 0xF8) | 0x04; dans setup(), le prédiviseur passe à 16, l'horloge de l'ADC monte à 1 MHz et analogRead() descend à environ 16 µs, au prix d'un peu de précision. Sur l'ESP32, des appels isolés à analogRead() permettent des dizaines de milliers de mesures par seconde, et le mode continu avec DMA (analogContinuous() sous Arduino) permet de choisir une fréquence entre 20 kHz et 2 MHz ; ce mode ne fonctionne qu'avec les broches de l'ADC1. L'ADC du Raspberry Pi Pico tourne sur sa propre horloge de 48 MHz, termine chaque conversion en 96 cycles, soit 2 µs, et atteint 500 000 mesures par seconde ; une boucle MicroPython ne peut pas suivre ce rythme, et pour la pleine vitesse il faut le SDK C et le DMA.
ADC de l'ESP32 : non-linéarité, conflit ADC2/Wi-Fi et atténuation
Sur le papier, l'ADC 12 bits de l'ESP32 mesure quatre fois plus finement que celui de l'Uno, mais en pratique il faut surveiller trois points. Le premier est la non-linéarité : près de 0 V, l'ADC de l'ESP32 lit 0 jusqu'à environ 100–150 mV, et en haut de l'échelle il sature à 4095 avant que l'entrée n'atteigne 3,3 V ; la courbe entre les deux n'est pas non plus une droite parfaite. Le deuxième est la dispersion de la référence : par conception, la référence interne de l'ESP32 vaut 1100 mV, mais d'après Espressif elle varie entre 1000 et 1200 mV d'une puce à l'autre, ce qui représente une erreur d'environ ±9 % sur des mesures non étalonnées. C'est pourquoi Espressif inscrit des données d'étalonnage dans les eFuses des puces en production. La fonction Arduino analogReadMilliVolts() utilise ces données pour convertir directement la valeur brute en millivolts étalonnés et donne, dans la plupart des cas, un résultat bien plus juste que le calcul analogRead() × 3,3 / 4095. Le troisième est l'atténuation : le cœur de l'ADC ne mesure que jusqu'à environ 1 V, et les tensions plus élevées sont réduites par un atténuateur réglable à l'entrée. Sous Arduino, le réglage par défaut est de 11 dB, ce qui permet de lire jusqu'à environ 3,1 V, mais la plage précise recommandée par Espressif pour ce réglage est de 150 à 2450 mV. Pour les petits signaux, baisser l'atténuation améliore à la fois la précision et la résolution :
| Atténuation | Constante Arduino | Plage précise | Utilisation |
|---|---|---|---|
| 0 dB | ADC_0db | 100–950 mV | Petits signaux, mesure la plus fine |
| 2,5 dB | ADC_2_5db | 100–1250 mV | Sorties de capteurs autour de 1 V |
| 6 dB | ADC_6db | 150–1750 mV | Signaux de niveau moyen |
| 11 dB (par défaut) | ADC_11db | 150–2450 mV (la lecture va jusqu'à environ 3,1 V) | Potentiomètres et capteurs 0–3,3 V |
1// ESP32 ADC: ham değer ve kalibre milivolt / ESP32 ADC: raw value and calibrated millivolts
2// Potansiyometre: 3V3, GND ve orta bacak GPIO 34 / Pot: 3V3, GND and wiper to GPIO 34
3const int POT_PIN = 34; // ADC1_CH6, Wi-Fi açıkken de çalışır / ADC1_CH6, works with Wi-Fi on
4
5void setup() {
6 Serial.begin(115200);
7 analogReadResolution(12); // 0-4095 (varsayılan / default)
8 analogSetPinAttenuation(POT_PIN, ADC_11db); // yaklaşık 3,1 V'a kadar / up to about 3.1 V
9}
10
11void loop() {
12 uint32_t rawSum = 0;
13 uint32_t mvSum = 0;
14 for (int i = 0; i < 16; i++) { // 16 ölçümün ortalaması / average of 16 readings
15 rawSum += analogRead(POT_PIN); // ham ADC değeri / raw ADC value
16 mvSum += analogReadMilliVolts(POT_PIN); // eFuse kalibrasyonlu mV / eFuse-calibrated mV
17 }
18 float raw = rawSum / 16.0;
19 float naiveV = raw * 3.3 / 4095.0; // basit formül / naive formula
20 float calibratedV = mvSum / 16.0 / 1000.0; // kalibre edilmiş / calibrated
21
22 Serial.printf("Ham / Raw: %4.0f Formul / Formula: %.3f V Kalibre / Calibrated: %.3f V\n",
23 raw, naiveV, calibratedV);
24 delay(500);
25}Le code affiche deux résultats côte à côte : la valeur brute convertie avec la formule simple et la valeur étalonnée par analogReadMilliVolts(). En tournant le potentiomètre vers les extrémités, tu verras l'écart grandir, et tout en bas, là où la formule affiche 0,000 V, le multimètre mesure encore environ 0,1 V. analogSetPinAttenuation() change l'atténuation d'une seule broche, tandis qu'analogSetAttenuation() la change pour toutes. L'ESP32 est nettement plus bruité que l'Uno, surtout quand le Wi-Fi émet ; Espressif conseille lui-même d'ajouter un condensateur de 100 nF sur l'entrée et de moyenner plusieurs échantillons, ce que fait la moyenne de 16 mesures du code. Les puces plus récentes comme l'ESP32-S3 et l'ESP32-C3 utilisent un étalonnage plus évolué par ajustement de courbe, mais les numéros de broches et les règles de l'ADC2 varient selon le modèle : consulte toujours le brochage de ta carte (outil Pinout). Nous expliquons comment monter un pont diviseur pour mesurer des tensions supérieures à 3,3 V dans le guide du pont diviseur de tension.
ADC du Raspberry Pi Pico (MicroPython)
Le Raspberry Pi Pico possède trois entrées analogiques accessibles de l'extérieur : GP26 (ADC0), GP27 (ADC1) et GP28 (ADC2). GP29 (ADC3) mesure sur la carte un tiers de la tension d'alimentation VSYS, et l'ADC4 est relié au capteur de température interne de la puce. La fonction read_u16() de MicroPython met le résultat 12 bits à l'échelle 0–65535 pour que le même code fonctionne sur différentes cartes, mais la résolution réelle reste de 4096 paliers. Le RP2040 n'a pas de tension de référence séparée : il utilise sa propre alimentation d'ADC comme référence. Sur le Pico, cette alimentation (ADC_VREF, broche 35) provient de la sortie du régulateur à découpage 3,3 V (SMPS), filtrée par une résistance d'environ 200 Ω. La fiche technique de la carte Raspberry Pi en cite clairement trois conséquences : la précision du 3,3 V est limitée, l'alimentation est un peu bruitée, et le courant consommé par l'ADC crée un décalage d'environ 30 mV. Les remèdes figurent dans le même document : mettre GP23 à HIGH pour faire passer le régulateur en mode PWM, avec moins d'ondulation ; relier un canal d'ADC inutilisé à AGND et soustraire sa mesure comme décalage ; et, pour une bien meilleure précision, brancher une référence de 3,0 V comme le LM4040 entre ADC_VREF et AGND (la plage de mesure devient alors 0–3,0 V). On sait aussi que l'ADC du RP2040 présente de petits sauts (erreurs DNL) aux valeurs 512, 1536, 2560 et 3584 ; moyenner plusieurs mesures réduit leur effet. Sur le Pico W, GP23 est réservée à la puce sans fil et le mode du régulateur se commande via WL_GPIO1 ; sur un Pico W, supprime donc les lignes GP23 du code ci-dessous.
1from machine import ADC, Pin
2import time
3
4pot = ADC(26) # GP26 = ADC0 (pin 31)
5chip_temp = ADC(4) # dahili sıcaklık sensörü / internal temperature sensor
6VREF = 3.3 # ADC_VREF; multimetreyle ölçüp düzelt / measure and correct with a multimeter
7
8# Yalnız Pico ve Pico 2 (W değil): SMPS PWM moduna, daha az gürültü / Plain Pico and Pico 2 only (not W): SMPS to PWM mode, less noise
9smps_mode = Pin(23, Pin.OUT)
10smps_mode.value(1)
11
12
13def read_average(adc, samples=16):
14 total = 0
15 for _ in range(samples):
16 total += adc.read_u16() # 0-65535 (12 bit ölçeklenmiş / 12-bit scaled)
17 return total / samples
18
19
20while True:
21 raw = read_average(pot)
22 volts = raw * VREF / 65535 # sayıyı volta çevir / convert the number to volts
23 t_volts = read_average(chip_temp) * VREF / 65535
24 temp_c = 27 - (t_volts - 0.706) / 0.001721 # RP2040 veri sayfası formülü / RP2040 datasheet formula
25 print("ADC: {:5d} {:.3f} V Yonga / Chip: {:.1f} C".format(int(raw), volts, temp_c))
26 time.sleep(0.5)Méthodes pour réduire le bruit de l'ADC
Même en mesurant une tension stable, il est normal que la valeur de l'ADC bouge d'un ou deux paliers ; la quantification, l'ondulation de l'alimentation, les parasites captés par les longs fils et les moteurs ou émissions Wi-Fi à proximité y contribuent. Sur l'Uno, une variation de ±1–2 paliers est considérée comme saine ; beaucoup plus signale généralement un problème dans le circuit. Tu peux combattre le bruit à la fois côté matériel et côté logiciel :
- Ajoute un condensateur : un condensateur céramique de 100 nF entre la broche analogique et GND filtre les parasites rapides et fournit une charge prête au condensateur d'échantillonnage avec les sources très résistives.
- Garde des fils courts : si le câble du capteur est long, torsade ensemble les fils de signal et de GND ; fais passer les fils des moteurs et des relais loin des lignes analogiques.
- Soigne la masse : le courant de retour des charges gourmandes comme les moteurs, relais et rubans LED ne doit pas passer par le fil GND du capteur ; rassemble les masses en un seul point (masse en étoile).
- Utilise une référence propre : l'alimentation USB est bruitée ; pour les mesures de tension absolue, la référence interne ou un circuit de référence externe donnent des résultats plus stables.
- Jette la première mesure après un changement de canal : le multiplexeur à l'entrée de l'ADC peut garder la charge du canal précédent ; quand tu lis plusieurs broches à la suite, sacrifie une mesure sur chaque broche.
- Fais la moyenne : la moyenne de N mesures réduit le bruit aléatoire d'un facteur d'environ √N ; 16 mesures le divisent par quatre.
- Suréchantillonnage (oversampling) : si tu additionnes 4^n mesures et décales le résultat de n bits vers la droite, tu gagnes n bits de résolution ; décaler de 2 bits la somme de 16 mesures fait passer les 10 bits de l'Uno à 12. Pour que cela marche, le signal doit comporter au moins un palier de bruit naturel.
- Filtres médian et exponentiel : le filtre médian supprime les pics soudains dus aux moteurs, et la moyenne mobile exponentielle (EMA) donne une courbe lisse avec très peu de mémoire.
1// Ham, ortalama ve EMA filtreli ADC değerleri / Raw, averaged and EMA-filtered ADC values
2// Serial Plotter ile izle / Watch with the Serial Plotter
3const int SENSOR_PIN = A0;
4const float ALPHA = 0.1; // EMA katsayısı (0-1) / EMA coefficient (0-1)
5float ema = 0;
6
7void setup() {
8 Serial.begin(115200);
9 analogRead(SENSOR_PIN); // ilk okumayı at / discard the first reading
10 ema = analogRead(SENSOR_PIN); // filtreyi başlat / seed the filter
11}
12
13void loop() {
14 int raw = analogRead(SENSOR_PIN); // ham değer / raw value
15
16 long sum = 0;
17 for (int i = 0; i < 16; i++) { // 16 ölçüm topla / sum 16 readings
18 sum += analogRead(SENSOR_PIN);
19 }
20 float average = sum / 16.0; // ortalama (0-1023) / average (0-1023)
21
22 ema += ALPHA * (raw - ema); // üstel hareketli ortalama / exponential moving average
23
24 Serial.print(F("ham:"));
25 Serial.print(raw);
26 Serial.print(F(" ortalama:"));
27 Serial.print(average);
28 Serial.print(F(" ema:"));
29 Serial.println(ema);
30 delay(20);
31}Quand tu téléverses le code et ouvres le traceur série de l'IDE Arduino, tu vois trois courbes : la valeur brute tremble, la moyenne de 16 mesures est nettement plus calme et l'EMA est la courbe la plus lisse, mais elle réagit aux changements avec un peu de retard. Le coefficient ALPHA se choisit entre 0 et 1 : 0,1 signifie que chaque nouvelle mesure compte pour 10 % dans le résultat, si bien qu'à peu près les 10 dernières mesures ont un effet ; en l'augmentant, la réponse devient plus rapide mais le bruit augmente. Le bon filtre dépend du signal : une EMA forte convient à une température qui varie lentement, une moyenne courte à un joystick qui doit réagir vite. Nous comparons moyenne mobile, filtre médian et hystérésis sur des exemples réels de capteurs dans le guide sur le filtrage des données de capteurs.
Courte introduction au DAC : du numérique à l'analogique
Un DAC (convertisseur numérique-analogique, ou CNA) fait l'inverse d'un ADC : il reçoit un nombre et produit une tension proportionnelle. Si tu écris 0 dans un DAC 8 bits, tu obtiens 0 V, avec 255 une valeur proche de la tension d'alimentation et avec 128 environ la moitié. Les DAC les plus simples sont faits d'une échelle de résistances appelée R-2R. Dissipons au passage une confusion fréquente : analogWrite() sur l'Arduino Uno n'est pas un DAC, il génère du PWM ; la broche commute en réalité très vite entre 0 V et 5 V. Pour la luminosité d'une LED ou la vitesse d'un moteur, cela suffit, mais si tu as vraiment besoin d'une tension stable, il faut ajouter un filtre passe-bas RC sur la sortie PWM ; tu peux calculer la constante de temps du filtre avec l'outil de constante de temps RC. Côté cartes dotées d'un vrai DAC : l'ESP32 possède deux DAC 8 bits sur GPIO 25 et GPIO 26, utilisables avec dacWrite(broche, valeur), alors que l'ESP32-S3 et l'ESP32-C3 n'en ont pas. L'Arduino Uno R4 dispose d'un DAC 12 bits sur la broche A0. Pour l'Uno R3, le Nano et le Pico, le plus simple est le module MCP4725 12 bits relié en I2C. Avec un DAC, tu peux produire du son, générer des ondes sinusoïdales ou triangulaires, et même relier la sortie du DAC à une entrée de l'ADC pour tester l'ADC avec des tensions connues :
1// ESP32 DAC ile sinüs dalgası / Sine wave with the ESP32 DAC
2// Çıkış GPIO 25'te, osiloskopla izle / Output on GPIO 25, watch it with an oscilloscope
3const int DAC_PIN = 25; // DAC1 = GPIO 25 (DAC2 = GPIO 26)
4const int STEPS = 64; // bir periyottaki nokta sayısı / points per period
5uint8_t sineTable[STEPS];
6
7void setup() {
8 for (int i = 0; i < STEPS; i++) {
9 sineTable[i] = 128 + 127 * sin(2 * PI * i / STEPS); // 1-255 arası tablo / table between 1-255
10 }
11}
12
13void loop() {
14 for (int i = 0; i < STEPS; i++) {
15 dacWrite(DAC_PIN, sineTable[i]); // 0 → 0 V, 255 → yaklaşık 3,3 V / 0 → 0 V, 255 → about 3.3 V
16 delayMicroseconds(150); // yaklaşık 100 Hz / roughly 100 Hz
17 }
18}Idées de projets avec l'ADC
- Voltmètre numérique : mesure de 0 à 25 V avec un pont diviseur et affiche le résultat sur un écran LCD ; les étapes sont dans le guide fabriquer un voltmètre avec Arduino.
- Veilleuse automatique : lis la tension d'une LDR et allume les LED quand il fait sombre.
- Pot de fleurs intelligent : utilise la sortie analogique d'un capteur d'humidité du sol pour lancer une pompe quand la terre est sèche.
- Robot piloté au joystick : les deux axes d'un joystick sont deux entrées analogiques distinctes ; convertis leurs valeurs en vitesse et en direction des moteurs.
- Ampèremètre : lis la tension proportionnelle au courant d'un ACS712 pour savoir combien un appareil consomme.
- Indicateur de niveau sonore : échantillonne rapidement la sortie analogique d'un capteur de son KY-038 et allume une barre de LED selon la valeur crête.
- Jauge de batterie : mesure la tension dans un projet sur pile et affiche la charge restante en pourcentage sur un écran.
Erreurs fréquentes et solutions
| Symptôme | Cause probable | Solution |
|---|---|---|
| La valeur varie au hasard alors que rien n'est branché | La broche est flottante | Branche le capteur ; ne lis pas les broches inutilisées ou tire-les à GND |
| La valeur reste bloquée à 1023 (4095 sur l'ESP32) | L'entrée dépasse la référence, ou INTERNAL est sélectionné | Ajuste la référence ou l'atténuation, abaisse les tensions élevées avec un pont diviseur |
| Sur l'ESP32, analogRead() renvoie 0 dès que le Wi-Fi est actif | Le capteur est sur une broche de l'ADC2 | Utilise les broches de l'ADC1, GPIO 32–39 |
| L'ESP32 affiche 0 pour les petites tensions et 4095 pour les grandes | L'ADC n'est pas linéaire aux extrémités | Utilise analogReadMilliVolts() et garde le signal entre 150 et 2450 mV |
| La tension calculée diffère de 3–5 % du multimètre | Vref n'est pas 5,00 V (alimentation USB) | Mesure la broche 5V et mets la valeur dans VREF, ou ajoute un coefficient d'étalonnage |
| En lisant deux broches à la suite, les valeurs s'influencent | Multiplexeur et résistance de source élevée | Jette la première mesure après le changement, garde la source sous 10 kΩ, ajoute 100 nF |
| Les valeurs sautent quand un moteur ou un relais fonctionne | Bruit sur la ligne GND commune, alimentation qui chute | Donne aux charges leur propre retour GND, utilise des condensateurs et un filtre médian |
| Les mesures sont fausses après avoir appliqué une tension sur AREF | AREF utilisée sans appeler analogReference(EXTERNAL) | Sélectionne d'abord EXTERNAL ou relie AREF via une résistance de 5 kΩ |
| Après avoir choisi INTERNAL, le potentiomètre atteint 1023 à mi-course | La référence de 1,1 V s'applique à toutes les broches analogiques | Reviens à DEFAULT avant de lire des capteurs ratiométriques et jette quelques mesures |
| Sur le Pico, la valeur dépasse 0 même avec l'entrée à GND | Décalage de l'ADC et bruit sur ADC_VREF | Relie un canal à AGND, mesure le décalage et soustrais-le ; mets GP23 à HIGH |
L'ADC est le pont entre le monde physique et ton code : quand tu connais sa résolution, sa tension de référence et sa fréquence d'échantillonnage, tu sais aussi ce que représente chaque nombre affiché et à quel point tu peux t'y fier. Sur l'Uno, mesure correctement la référence ; sur l'ESP32, utilise les broches de l'ADC1 et analogReadMilliVolts() ; sur le Pico, tiens compte du décalage et du bruit ; puis lisse le résultat avec des moyennes et des filtres. Dans l'application BlueGrays, tu trouveras des projets basés sur la mesure analogique, comme la lecture de l'intensité lumineuse avec une LDR, un voltmètre numérique avec écran LCD, la mesure de température avec une CTN et le contrôle d'un servo et de la luminosité d'une LED avec un potentiomètre, avec schémas et code pas à pas.
Questions fréquentes
Qu'est-ce qu'un ADC et à quoi sert-il ?
Un ADC (convertisseur analogique-numérique, ou CAN) est le circuit qui convertit la tension d'une broche en un nombre que le microcontrôleur peut traiter. Il sert à lire les composants à sortie analogique comme les potentiomètres, les LDR et les capteurs de température et d'humidité. Sur Arduino, c'est l'instruction analogRead() qui le met en marche.
Quelle est la différence entre un signal analogique et un signal numérique ?
Un signal analogique peut prendre n'importe quelle valeur dans une plage et varie en continu, alors qu'un signal numérique ne comporte que certains niveaux, LOW et HIGH sur Arduino. digitalRead() indique seulement si une broche vaut 0 ou 1, tandis qu'analogRead() donne la valeur de la tension sous forme de nombre.
Pourquoi analogRead renvoie-t-il des valeurs de 0 à 1023 sur Arduino ?
L'ADC de l'Arduino Uno est sur 10 bits et produit 2^10 = 1024 paliers différents, numérotés de 0 à 1023. La valeur 0 représente 0 V, et 1023 un palier sous la tension de référence (généralement 5 V). Les ADC 12 bits de l'ESP32 et du Pico renvoient des valeurs de 0 à 4095.
Comment convertir une valeur ADC en tension ?
Utilise la formule tension = valeur ADC × tension de référence / nombre de paliers. Sur l'Arduino Uno, cela donne V = valeur × 5,0 / 1024 ; sur l'ESP32, analogReadMilliVolts() fournit directement des millivolts étalonnés. Sur le Pico, pour la valeur read_u16() de MicroPython, on utilise V = valeur × 3,3 / 65535.
Les broches ADC2 de l'ESP32 fonctionnent-elles avec le Wi-Fi ?
Non. Sur l'ESP32, le pilote Wi-Fi utilise lui aussi l'unité ADC2 ; quand le Wi-Fi est actif, on ne peut donc pas lire les broches de l'ADC2 (GPIO 0, 2, 4, 12–15, 25–27). Dans les projets Wi-Fi, branche les capteurs analogiques sur les broches de l'ADC1 (GPIO 32–39).
Qu'est-ce qu'un DAC et quelle différence avec un ADC ?
Un DAC (convertisseur numérique-analogique) fait l'inverse d'un ADC : il convertit un nombre en tension. L'ADC sert à mesurer la tension venant d'un capteur, le DAC à produire une tension, comme un son ou un signal. L'Arduino Uno n'a pas de DAC et analogWrite() génère du PWM ; l'ESP32 a deux DAC 8 bits sur GPIO 25 et 26, et l'Uno R4 un DAC 12 bits sur A0.
Projets à réaliser après cet article
Voir tous les projets
Mesurer l'intensité lumineuse avec une LDR
Envie de voir en chiffres à quel point ta chambre est lumineuse ? Le LDR, une petite pièce sensible à la lumière, mesure la lumière ambiante, et l'Arduino écrit la valeur sur l'écran de ton ordinateur

Voltmètre numérique avec écran LCD
Découvre quelle tension fournit une pile ou un adaptateur avec un appareil de mesure fait maison. Un diviseur de deux résistances abaisse la tension élevée à un niveau que la carte peut lire, et l'Ard

Mesure de l'intensité lumineuse avec le module LDR ESP32
Suivi en temps réel sur le moniteur série de la valeur brute de l'ADC du module LDR et du pourcentage relatif de luminosité calculé à partir de références dans l'obscurité et à la lumière. Ce pourcentage n'est pas une mesure en lux. Permet de comprendre le principe de calibrage du module. Il est préférable de réaliser cet exercice avant le projet 10, car il sert à déterminer la valeur seuil.

Luminosité d'une LED avec un Potentiomètre sur ESP32 (Analogique → PWM)
Dans ce projet, nous contrôlons la luminosité d'une LED de manière analogique à l'aide d'un potentiomètre. La broche ADC de l'ESP32 lit la tension entre 0 et 3,3 V provenant du potentiomètre, puis cette valeur est convertie en signal PWM (modulation de largeur d'impulsion) envoyé à la LED. Ainsi, la LED s'allume et s'éteint progressivement. Avec Arduino Core 3.0+, analogWrite() est utilisable directement; sur ESP32-S2/S3, la résolution de l'ADC est fixée à 12 bits.

Mesure de la température avec NTC et écran LCD 2x16
Mesure la température ambiante avec un capteur qui ressemble à une petite perle. Cette pièce, appelée NTC, laisse passer l'électricité de plus en plus facilement en chauffant ; l'Arduino lit ce change

Utilisation d'un servomoteur avec un potentiomètre
Quand tu tournes le bouton du potentiomètre, le bras du servomoteur tourne avec lui : un bout du bouton correspond à zéro degré, l'autre à un demi-tour. L'Arduino lit sans arrêt la position du bouton,

Contrôle de LED avec un joystick
Pousse à fond le petit levier du joystick dans une direction, et la LED de cette direction s'allume : il y a quatre couleurs différentes pour droite, gauche, haut et bas. Quand tu lâches le levier, il

Lampe à mélangeur de couleurs ESP32 (3 potentiomètres + LED RVB + écran OLED)
Une lampe mélangeuse de couleurs intelligente qui vous permet de créer la couleur de votre choix en tournant 3 potentiomètres grâce à l'ESP32 ! À mesure que vous tournez les potentiomètres rouge, vert et bleu, la LED RVB à cathode commune change de couleur en temps réel. L'écran OLED SSD1306 affiche en temps réel la valeur de chaque couleur sur une plage de 0 à 255, des barres de remplissage visuelles et le code couleur HEX (#FF8040, par exemple). Un mini-studio de couleur professionnel — il per
Autres articles
- Pont diviseur de tension : formule, calcul et exemples Arduino
- Qu'est-ce qu'un potentiomètre ? Lecture analogique et contrôle avec Arduino
- Qu'est-ce que le PWM ? Guide d'analogWrite, du rapport cyclique et de la fréquence sur Arduino
- Qu'est-ce qu'un capteur de lumière LDR ? Mesurer la lumière avec Arduino et veilleuse automatique
Application BlueGrays
Réalise ce montage pas à pas sur ton téléphone
Schéma, code et liste des composants sur un seul écran. Plus de 200 projets Arduino, ESP32 et Pico à réaliser.
Scanne avec ton téléphone
Pointe l’appareil photo vers le code : la boutique d’applications de ton téléphone s’ouvre.
ou ouvre la boutique

