Grundlagen · 18 Min. Lesezeit

Analog-Digital-Wandler (ADC) erklärt: Arduino, ESP32, Pico

Was ist ein ADC und wie funktioniert er? Analog vs. digital, 10- und 12-Bit-Auflösung, analogReference, Umrechnung in Volt, ESP32-ADC2 und weniger Rauschen.

Ein ADC (Analog-Digital-Wandler) ist die Schaltung, die eine sich stetig ändernde Spannung an einem Pin in eine Zahl umwandelt, mit der der Mikrocontroller arbeiten kann. Jedes Mal, wenn du am Arduino analogRead() aufrufst, arbeitet dieser Wandler im Hintergrund: Der 10-Bit-ADC des Arduino Uno macht aus einer Spannung zwischen 0 und 5 V eine Zahl von 0 bis 1023, die 12-Bit-ADCs von ESP32 und Raspberry Pi Pico machen aus etwa 0–3,3 V eine Zahl von 0 bis 4095. Der ADC ist der Schlüssel, um alles mit einem analogen Ausgang auszulesen: Potentiometer, LDRs, Bodenfeuchtesensoren, Joysticks und Temperatursensoren.

In dieser Anleitung lernst du den Unterschied zwischen analogen und digitalen Signalen kennen, wie ein ADC eine Spannung Schritt für Schritt in eine Zahl umwandelt und wie Auflösung und Referenzspannung deine Messung beeinflussen. Mit echten Zahlen gehen wir die Formel zur Umrechnung eines Messwerts in Volt durch, ändern den Messbereich mit analogReference und schauen uns die Abtastrate sowie praktische Wege gegen Rauschen an. Außerdem behandeln wir den an den Rändern nicht linearen ADC des ESP32, den Konflikt zwischen ADC2 und WLAN sowie die Dämpfung (Attenuation), die Nutzung des ADC am Raspberry Pi Pico mit MicroPython und zum Schluss eine kurze Einführung in den DAC, der genau das Gegenteil macht.

Potentiometer mit dem ADC auslesen
Ein Potentiometer ist der einfachste Weg, einen ADC auszuprobieren: Die Spannung am mittleren Pin ändert sich beim Drehen zwischen 0 V und der Versorgungsspannung.

Was ist der Unterschied zwischen analogen und digitalen Signalen?

Ein analoges Signal ist eine Größe, die innerhalb eines Bereichs unendlich viele Werte annehmen kann und sich zeitlich stetig ändert. Wenn die Spannung am mittleren Pin eines Potentiometers von 0 V auf 5 V steigt, durchläuft sie jeden Wert dazwischen, etwa 1,2 V, 1,21 V und 1,215 V; auch die Schallwelle eines Mikrofons, die temperaturabhängige Spannung eines Thermistors oder die langsam sinkende Spannung einer Batterie sind analog. Ein digitales Signal kennt dagegen nur bestimmte Pegel. In der Logik-Welt des Arduino sind es zwei: LOW (0) und HIGH (1). Beim Uno wertet ein digitaler Eingang alles unter etwa 1,5 V als LOW und alles über 3,0 V als HIGH; der Bereich dazwischen ist undefiniert. Deshalb kann digitalRead() bei einem Akku 3,7 V nicht von 4,2 V unterscheiden und meldet beide Male HIGH. Die Stärke digitaler Signale ist ihre Störfestigkeit: 4,6 V und 5,0 V bedeuten dasselbe HIGH. Um einen analogen Wert zu messen, zu speichern oder damit zu rechnen, musst du ihn zuerst in eine Zahl, also einen digitalen Wert, umwandeln, und genau das erledigt der ADC.

Was ist ein ADC und wie funktioniert er?

Die Arbeit eines ADC lässt sich in zwei Schritten zusammenfassen. Der erste ist das Abtasten: Im Moment der Messung kopiert der Wandler die Eingangsspannung auf einen kleinen Kondensator (Sample-and-Hold-Schaltung) und hält sie konstant, bis die Wandlung fertig ist; beim ATmega328P hat dieser Kondensator etwa 14 pF. Der zweite ist die Quantisierung: Die gehaltene Spannung wird auf die nächstgelegene Stufe einer Skala gerundet, die die Referenzspannung in gleich große Stufen teilt, und die Nummer dieser Stufe wird als Ergebnis ausgegeben. Die ADCs in Arduino Uno, ESP32 und Pico arbeiten alle nach dem Verfahren der sukzessiven Approximation (SAR, Successive Approximation Register). Ein SAR-ADC funktioniert wie ein Zahlenratespiel: Zuerst probiert er die halbe Referenzspannung, setzt das höchstwertige Bit auf 1, wenn der Eingang größer ist, und lässt es auf 0, wenn er kleiner ist; dann probiert er die Hälfte des verbleibenden Bereichs und wiederholt das für jedes Bit. So findet ein 10-Bit-ADC mit nur 10 Vergleichen die richtige von 1024 möglichen Stufen. Der Einfachheit halber zeigt die Tabelle, wie ein 4-Bit-ADC mit 5 V Referenz einen Eingang von 3,2 V misst:

SchrittGeprüftes BitVergleichsspannungIst der Eingang (3,2 V) größer?Ergebnisbits
1Bit 3 (Wert 8)8 / 16 × 5 = 2,500 VJa → 11000
2Bit 2 (Wert 4)12 / 16 × 5 = 3,750 VNein → 01000
3Bit 1 (Wert 2)10 / 16 × 5 = 3,125 VJa → 11010
4Bit 0 (Wert 1)11 / 16 × 5 = 3,4375 VNein → 01010
ErgebnisAlle Bits geprüft1010 = 10 → 10 × 5 / 16 = 3,125 VFehler 0,075 V (eine Stufe = 0,3125 V)1010

Die Abweichung von 0,075 V im Ergebnis ist der Quantisierungsfehler, und kein ADC kommt um ihn herum: Liegt die echte Spannung zwischen zwei Stufen, kann der ADC nur eine davon melden. Der Fehler bleibt unter einer Stufe (LSB); je kleiner die Stufe, desto feiner die Messung. Weil sich der Sample-and-Hold-Kondensator bei jeder Messung aufladen muss, spielt auch der Widerstand der Quelle eine Rolle, die den ADC speist: Das Datenblatt des ATmega328P empfiehlt eine Quellimpedanz von etwa 10 kΩ oder weniger; ein hochohmigerer Spannungsteiler kann den Kondensator nicht rechtzeitig laden, und die Messwerte driften. Neben dem SAR-Typ in Mikrocontrollern gibt es weitere ADC-Arten. Sigma-Delta-ADCs sind langsam, aber sehr genau: Der in Wägeprojekten verwendete HX711 bietet 24 Bit, das per I2C angeschlossene ADS1115-Modul 16 Bit. Flash-ADCs nutzen für jede Stufe einen eigenen Komparator; sie sind extrem schnell und stecken zum Beispiel in Oszilloskopen.

ADC-Auflösung: Was bedeuten 10 Bit und 12 Bit?

Die Auflösung gibt an, in wie viele Stufen der ADC seinen Messbereich teilt. Ein N-Bit-ADC erzeugt 2^N Stufen: 10 Bit sind 1024 Stufen (0–1023), 12 Bit 4096 Stufen (0–4095) und 16 Bit 65.536 Stufen. Die Spannung einer Stufe heißt LSB (Least Significant Bit) und ergibt sich aus LSB = Vref / 2^N. Beim Arduino Uno sind das 5 V / 1024 = 4,88 mV, bei ESP32 und Pico 3,3 V / 4096 = 0,81 mV. Der Uno sieht also keine Änderungen unter 4,88 mV; mit einem LM35, der 10 mV/°C liefert, entspricht das einer Stufe von etwa 0,5 °C. Auflösung und Genauigkeit sind aber nicht dasselbe. Rauschen, Nichtlinearität und Referenzfehler machen einen Teil der Bits auf dem Papier wertlos. Das Maß dafür ist die effektive Anzahl der Bits (ENOB): Der ADC des RP2040 im Raspberry Pi Pico liefert ein 12-Bit-Ergebnis, laut Datenblatt liegt die effektive Bitzahl aber bei 8,7. Hier die ADCs der drei Boards im Vergleich:

EigenschaftArduino Uno R3ESP32 (WROOM-32)Raspberry Pi Pico
ADC-Auflösung10 Bit (0–1023)12 Bit (0–4095)12 Bit (in MicroPython auf 0–65535 skaliert)
Analoge Eingänge6 (A0–A5; beim Nano A0–A7)18 Kanäle: 8 an ADC1, 10 an ADC23 Pins (GP26–GP28) + VSYS/3 (GP29) + Temperatursensor
Standard-Messbereich0–5 VEtwa 0–3,1 V (11 dB Dämpfung)0–3,3 V (ADC_VREF)
Eine Stufe (LSB)4,88 mVEtwa 0,8 mV0,81 mV
ReferenzoptionenDEFAULT (5 V), INTERNAL (1,1 V), EXTERNAL (AREF)Dämpfung: 0, 2,5, 6 und 11 dBExterne Referenz am Pin ADC_VREF
AbtastrateEtwa 10.000 Messungen/s20 kHz – 2 MHz im Continuous-Modus (DMA)500.000 Messungen/s in Hardware
Hinweis zur GenauigkeitAbsoluter Fehler ±2 LSBAn den Rändern nicht linear, Kalibrierung nötigENOB 8,7 Bit, etwa 30 mV Offset
Analoger Ausgang (DAC)Keiner (PWM wird genutzt)2 Kanäle, 8 Bit (GPIO 25 und 26)Keiner (PWM wird genutzt)

Formel: ADC-Wert in Spannung umrechnen

Die Zahl, die der ADC liefert, sagt für sich allein nichts aus; um sie in eine Spannung umzurechnen, brauchst du die Referenzspannung und die Anzahl der Stufen: Spannung = ADC-Wert × Vref / 2^N. Beim Arduino Uno heißt das V = Wert × 5,0 / 1024; liefert analogRead() also 512, liegen am Pin 512 × 5 / 1024 = 2,50 V an. Umgekehrt findest du mit Wert = V × 1024 / Vref heraus, welcher Zahl eine bestimmte Spannung entspricht: 3,3 V liest der Uno als etwa 675. In vielen Beispielen wird statt durch 1024 durch 1023 geteilt. Das Datenblatt des ATmega328P nennt die Formel ADC = Vin × 1024 / Vref; der größte Wert 1023 steht für eine Stufe unterhalb von Vref. Teilst du durch 1023, zeigt der oberste Wert genau 5,00 V, dafür verschieben sich alle Werte um etwa 0,1 %. Dieser Unterschied ist kleiner als der eigene Fehler des ADC von ±2 LSB, beides funktioniert also; wichtig ist, im Projekt einheitlich zu bleiben. Die eigentlich große Fehlerquelle ist Vref selbst: Der 5V-Pin eines per USB versorgten Uno liegt oft irgendwo zwischen 4,7 und 5,1 V, und 5,0 in der Formel verursacht dann bis zu 5 % Fehler. Miss für genaue Messungen deshalb den 5V-Pin mit einem Multimeter und trage den echten Wert in den Code ein. Auch der einzige analoge Eingang des ESP8266 (A0) hat 10 Bit; der Chip selbst misst 0–1 V, und der eingebaute Spannungsteiler auf Boards wie NodeMCU und Wemos D1 Mini erweitert den Bereich auf etwa 0–3,2 V.

Board und EinstellungWertebereichUmrechnung in VoltBeispiel
Arduino Uno / Nano (DEFAULT, 5 V)0–1023V = Wert × 5,0 / 1024768 → 3,75 V
Uno, analogReference(INTERNAL)0–1023V = Wert × 1,1 / 1024512 → 0,55 V
ESP32 (11 dB)0–4095Kalibriert: analogReadMilliVolts() / 1000; grob: Wert × 3,3 / 40951650 mV → 1,65 V
Raspberry Pi Pico (read_u16)0–65535V = Wert × 3,3 / 6553532768 → 1,65 V
ESP8266 NodeMCU / Wemos D1 Mini (A0)0–1023V = Wert × 3,2 / 1024512 → 1,60 V

Potentiometer anschließen: Arduino, ESP32 und Pico

Potentiometer-PinArduino UnoESP32Raspberry Pi Pico
Äußerer Pin 15V3V33V3(OUT) (Pin 36)
Mittlerer Pin (Signal)A0GPIO 34 (ADC1_CH6)GP26 / ADC0 (Pin 31)
Äußerer Pin 2GNDGNDAGND (Pin 33) oder GND
Optionaler Entstörkondensator100 nF zwischen A0 und GND100 nF zwischen GPIO 34 und GND100 nF zwischen GP26 und AGND
Die analogen Eingänge von ESP32 und Raspberry Pi Pico vertragen höchstens 3,3 V; legst du den äußeren Pin des Potentiometers an 5 V oder schließt einen Sensor mit 5-V-Ausgang direkt an, kann der Pin dauerhaft beschädigt werden. Auch beim Uno darf am Eingang nie mehr als die Versorgungsspannung (5 V) oder weniger als 0 V anliegen; höhere Spannungen teilst du mit einem Spannungsteiler herunter. Ein analoger Pin, an dem nichts angeschlossen ist, liest zufällige Werte; das ist kein Defekt, der Pin hängt einfach "in der Luft".

Schritt für Schritt: deine erste ADC-Messung mit dem Arduino

  1. Schaltung aufbauen: Verbinde die äußeren Pins eines 10-kΩ-Potentiometers mit 5V und GND und den mittleren Pin mit A0.
  2. 5V-Pin messen: Miss mit dem Multimeter die Spannung zwischen 5V und GND und trage sie in die Konstante VREF im Code ein (z. B. 4.93).
  3. Code hochladen: Öffne den Sketch unten in der Arduino IDE, wähle Board und Port und lade ihn hoch.
  4. Seriellen Monitor öffnen: Stelle 9600 Baud ein und beobachte, wie sich der ADC-Wert beim Drehen zwischen 0 und 1023 ändert (Details in der Anleitung zum seriellen Monitor).
  5. Prüfen: Miss mit dem Multimeter zwischen A0 und GND und vergleiche mit der angezeigten Spannung; die Abweichung sollte bei etwa 10–20 mV bleiben.
C++ (Arduino IDE)
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() schließt eine Messung in etwa 100 µs ab und liefert eine ganze Zahl zwischen 0 und 1023. Der Code rechnet diese Zahl zuerst mit der Formel in Volt und dann mit map() in Prozent um. Da map() mit Ganzzahlen rechnet, fällt der Nachkommaanteil weg; brauchst du ein Ergebnis mit Nachkommastellen, rechne selbst mit float. Es handelt sich um eine ratiometrische Messung: Weil Potentiometer und ADC an denselben 5 V hängen, ändert sich die Knopfstellung, also der ADC-Wert, nicht, selbst wenn die Versorgung auf 4,9 V sinkt; nur die berechnete Spannung ändert sich. Dasselbe gilt für Sensoren, die über einen Teiler gelesen werden, etwa LDRs und NTCs. Misst du dagegen die Spannung einer Batterie oder einen Sensor mit festem mV-Ausgang wie den LM35, geht der tatsächliche Wert von Vref direkt ins Ergebnis ein.

Referenzspannung und analogReference

Die Referenzspannung (Vref) ist der obere Endpunkt der ADC-Skala: Erreicht oder übersteigt die Eingangsspannung Vref, bleibt das Ergebnis beim Maximalwert (1023) stehen. Eine kleinere Vref verengt den Messbereich, macht aber jede Stufe kleiner, sodass du kleine Signale feiner misst. Beim Arduino Uno wählst du die Referenz mit der Funktion analogReference(). Mit INTERNAL wird Vref zu 1,1 V und eine Stufe schrumpft auf 1,07 mV; einen LM35 (10 mV/°C) liest du dann in Schritten von etwa 0,1 °C, kannst dafür aber nichts über 1,1 V, also 110 °C, messen. Die interne 1,1-V-Referenz selbst schwankt von Chip zu Chip zwischen 1,0 und 1,2 V, deshalb lohnt sich bei genauen Projekten eine einmalige Kalibrierung mit dem Multimeter. Die ersten Messungen nach einem Referenzwechsel können ungenau sein, wie auch die Arduino-Dokumentation erwähnt; es ist also eine gute Gewohnheit, nach dem Umschalten ein paar Werte zu verwerfen. Außerdem wirkt die Einstellung auf alle analogen Pins des Boards gleichzeitig. Die Optionen unterscheiden sich je nach Board:

OptionReferenzBoardsWann verwenden?
DEFAULT5 V (3,3 V bei 3,3-V-Boards)Uno, Nano, Mega, LeonardoSensoren, die ratiometrisch zur Versorgung sind, z. B. Potentiometer, LDR, Joystick
INTERNAL1,1 V (ATmega328P); 2,56 V beim LeonardoUno, Nano, Leonardo (nicht beim Mega)Sensoren mit kleiner Spannung wie der LM35
INTERNAL1V1 / INTERNAL2V561,1 V / 2,56 VNur MegaKleine Signale am Mega
EXTERNALSpannung am AREF-Pin (0–5 V)Uno, Nano, MegaEigene Präzisionsreferenz nutzen (z. B. 2,5 V oder 4,096 V)
AR_INTERNALEtwa 1,43 V (interne Referenz des Chips)Uno R4 Minima und WiFiKleine Signale am Uno R4
Wenn du eine externe Referenz an AREF angeschlossen hast, musst du analogReference(EXTERNAL) aufrufen, bevor du analogRead() verwendest. Sonst wird die im Chip erzeugte Referenz mit der Spannung an AREF kurzgeschlossen, und der Mikrocontroller kann Schaden nehmen. Willst du zwischen Referenzen umschalten, schließe die externe Spannung über einen 5-kΩ-Widerstand an AREF an; da er mit dem internen Widerstand des Pins von etwa 32 kΩ einen Teiler bildet, sinkt die Spannung an AREF etwas (aus 2,5 V werden etwa 2,2 V). Lege an AREF nie weniger als 0 V oder mehr als 5 V an.

Abtastrate: Wie viele Messungen schafft ein ADC pro Sekunde?

Die Abtastrate gibt an, wie viele Messungen der ADC pro Sekunde durchführen kann. Beim Arduino Uno wird der ADC-Takt durch Teilen von 16 MHz durch 128 auf 125 kHz eingestellt, und eine Wandlung dauert 13 Takte; deshalb braucht analogRead() etwa 100 µs, und es sind höchstens rund 10.000 Messungen pro Sekunde möglich. Für langsam veränderliche Größen wie Temperatur, Licht oder Batteriespannung ist das mehr als genug; oft reichen schon 10 Messungen pro Sekunde. Bei schnellen Signalen kommt das Nyquist-Kriterium ins Spiel: Um ein Signal verlustfrei zu erfassen, musst du mindestens doppelt so schnell abtasten wie seine höchste Frequenz, in der Praxis bevorzugt man das 5- bis 10-Fache. Für 50-Hz-Netzbrummen brauchst du mindestens 100 Messungen/s, für Sprache bis 4 kHz mindestens 8.000 Messungen/s. Brauchst du am Uno schnellere Messungen, kannst du den ADC-Vorteiler verkleinern: Mit ADCSRA = (ADCSRA & 0xF8) | 0x04; in setup() wird der Vorteiler 16, der ADC-Takt steigt auf 1 MHz und analogRead() sinkt auf etwa 16 µs, auf Kosten von etwas Genauigkeit. Beim ESP32 erlauben einzelne analogRead()-Aufrufe Zehntausende Messungen pro Sekunde, und im Continuous-Modus mit DMA (in Arduino analogContinuous()) lässt sich eine Rate zwischen 20 kHz und 2 MHz wählen; dieser Modus funktioniert nur mit ADC1-Pins. Der ADC des Raspberry Pi Pico läuft mit einem eigenen 48-MHz-Takt, braucht pro Wandlung 96 Takte, also 2 µs, und erreicht 500.000 Messungen pro Sekunde; eine MicroPython-Schleife kommt da nicht mit, für volle Geschwindigkeit brauchst du das C-SDK und DMA.

ESP32-ADC: Nichtlinearität, ADC2-WLAN-Konflikt und Attenuation

Auf dem Papier misst der 12-Bit-ADC des ESP32 viermal feiner als der Uno, in der Praxis musst du aber auf drei Dinge achten. Erstens die Nichtlinearität: Nahe 0 V liest der ESP32-ADC bis etwa 100–150 mV nur 0, und am oberen Ende geht er bei 4095 in die Sättigung, bevor der Eingang 3,3 V erreicht; auch die Kurve dazwischen ist keine perfekte Gerade. Zweitens die Streuung der Referenz: Die interne Referenz des ESP32 beträgt laut Design 1100 mV, schwankt laut Espressif aber von Chip zu Chip zwischen 1000 und 1200 mV, was bei unkalibrierten Messungen einen Fehler von etwa ±9 % bedeutet. Darum schreibt Espressif bei der Produktion Kalibrierdaten in die eFuses der Chips. Die Arduino-Funktion analogReadMilliVolts() nutzt diese Daten, rechnet den Rohwert direkt in kalibrierte Millivolt um und ist meist deutlich genauer als analogRead() × 3,3 / 4095. Drittens die Dämpfung (Attenuation): Der ADC-Kern misst nur bis etwa 1 V, höhere Spannungen werden von einem einstellbaren Dämpfungsglied am Eingang verkleinert. Standard in Arduino sind 11 dB, womit Messungen bis etwa 3,1 V möglich sind, der von Espressif für diese Einstellung empfohlene genaue Bereich liegt aber bei 150–2450 mV. Bei kleinen Signalen verbessert eine geringere Dämpfung sowohl Genauigkeit als auch Auflösung:

DämpfungArduino-KonstanteGenauer MessbereichEinsatz
0 dBADC_0db100–950 mVKleine Signale, feinste Messung
2,5 dBADC_2_5db100–1250 mVSensorausgänge um 1 V
6 dBADC_6db150–1750 mVMittlere Signalpegel
11 dB (Standard)ADC_11db150–2450 mV (Messwerte reichen bis etwa 3,1 V)Potentiometer und 0–3,3-V-Sensoren
Beim ESP32 nutzt auch der WLAN-Treiber den ADC2. Sobald WLAN gestartet ist, kannst du die ADC2-Pins (GPIO 0, 2, 4, 12, 13, 14, 15, 25, 26, 27) nicht mehr lesen; ESP-IDF meldet dann einen Timeout-Fehler (ESP_ERR_TIMEOUT), und in aktuellen Versionen des Arduino-Cores liefert analogRead() einfach 0. Schließe analoge Sensoren in WLAN-Projekten deshalb immer an ADC1-Pins an: GPIO 32, 33, 34, 35, 36 (VP) und 39 (VN). Davon sind 34–39 reine Eingänge ohne interne Pull-up-Widerstände, was sie ideal für analoge Messungen macht. GPIO 0, 2, 12 und 15 sind außerdem Boot-Pins (Strapping-Pins) und für analoge Sensoren völlig ungeeignet.
C++ (Arduino IDE)
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}

Der Code zeigt zwei Ergebnisse nebeneinander: den mit der einfachen Formel umgerechneten Rohwert und den von analogReadMilliVolts() kalibrierten Wert. Drehst du das Potentiometer Richtung Anschlag, wird der Unterschied größer, und ganz unten, wo die Formel 0,000 V anzeigt, misst das Multimeter noch etwa 0,1 V. analogSetPinAttenuation() ändert die Dämpfung nur für einen Pin, analogSetAttenuation() für alle Pins. Der ESP32 rauscht deutlich stärker als der Uno, besonders während WLAN sendet; Espressif selbst empfiehlt einen 100-nF-Kondensator am Eingang und das Mitteln mehrerer Messungen, genau das macht der Mittelwert über 16 Messungen im Code. Neuere Chips wie ESP32-S3 und ESP32-C3 nutzen eine fortgeschrittenere Kalibrierung per Kurvenanpassung, aber Pinnummern und ADC2-Regeln unterscheiden sich je nach Modell, also wirf immer einen Blick auf die Pinbelegung deines Boards (Pinout-Tool). Wie du einen Teiler für Spannungen über 3,3 V baust, erklären wir in der Anleitung zum Spannungsteiler.

ADC am Raspberry Pi Pico (MicroPython)

Der Raspberry Pi Pico hat drei von außen nutzbare analoge Eingänge: GP26 (ADC0), GP27 (ADC1) und GP28 (ADC2). GP29 (ADC3) misst auf dem Board ein Drittel der Versorgungsspannung VSYS, und ADC4 ist mit dem internen Temperatursensor des Chips verbunden. Die MicroPython-Funktion read_u16() skaliert das 12-Bit-Ergebnis auf den Bereich 0–65535, damit derselbe Code auf verschiedenen Boards läuft, die echte Auflösung bleibt aber bei 4096 Stufen. Der RP2040 hat keine eigene Referenzspannung, er nutzt seine ADC-Versorgung als Referenz. Beim Pico wird diese Versorgung (ADC_VREF, Pin 35) aus dem Ausgang des 3,3-V-Schaltreglers (SMPS) gewonnen und über einen Widerstand von etwa 200 Ω gefiltert. Das Board-Datenblatt von Raspberry Pi nennt drei Folgen ganz offen: Die Genauigkeit der 3,3 V ist begrenzt, die Versorgung ist etwas verrauscht, und der Strom, den der ADC zieht, erzeugt einen Offset von etwa 30 mV. Die Abhilfen stehen im selben Dokument: GP23 auf HIGH setzen, um den Regler in den welligkeitsärmeren PWM-Modus zu schalten, einen ungenutzten ADC-Kanal mit AGND verbinden und dessen Messwert als Offset abziehen, und für deutlich bessere Genauigkeit eine 3,0-V-Referenz wie den LM4040 zwischen ADC_VREF und AGND schalten (der Messbereich wird dann 0–3,0 V). Außerdem hat der ADC des RP2040 bekanntermaßen kleine Sprünge (DNL-Fehler) bei den Werten 512, 1536, 2560 und 3584; das Mitteln mehrerer Messungen verringert ihre Wirkung. Beim Pico W ist GP23 für den Funkchip reserviert, dort wird der Reglermodus über WL_GPIO1 gesteuert; lösche auf einem Pico W also die GP23-Zeilen im folgenden Code.

MicroPython
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)

Methoden gegen ADC-Rauschen

Selbst beim Messen einer konstanten Spannung ist es normal, dass der ADC-Wert um ein, zwei Stufen schwankt; Quantisierung, Welligkeit der Versorgung, Störungen über lange Leitungen und Motoren oder WLAN-Sendungen in der Nähe tragen dazu bei. Am Uno gilt ein Zappeln von ±1–2 Stufen als gesund; deutlich mehr deutet meist auf ein Problem in der Schaltung hin. Gegen Rauschen kannst du in Hardware und Software vorgehen:

  • Kondensator ergänzen: Ein keramischer Kondensator mit 100 nF zwischen Analogpin und GND filtert schnelle Störungen und stellt bei hochohmigen Quellen Ladung für den Sample-and-Hold-Kondensator bereit.
  • Leitungen kurz halten: Ist das Sensorkabel lang, verdrille Signal- und GND-Leitung; führe Motor- und Relaisleitungen weg von analogen Leitungen.
  • Sauber erden: Der Rückstrom von Lasten mit hohem Strom wie Motoren, Relais und LED-Streifen darf nicht über die GND-Leitung des Sensors fließen; führe die Massen an einem Punkt zusammen (sternförmige Masseführung).
  • Saubere Referenz nutzen: Die USB-Versorgung ist verrauscht; bei absoluten Spannungsmessungen liefert die interne Referenz oder ein externer Referenz-IC stabilere Ergebnisse.
  • Nach Kanalwechsel erste Messung verwerfen: Der Multiplexer am ADC-Eingang kann Ladung vom vorherigen Kanal mitschleppen; liest du mehrere Pins nacheinander, verwirf an jedem Pin eine Messung.
  • Mitteln: Der Mittelwert aus N Messungen verringert zufälliges Rauschen etwa um den Faktor √N; 16 Messungen senken das Rauschen auf ein Viertel.
  • Oversampling: Summierst du 4^n Messungen und schiebst das Ergebnis um n Bit nach rechts, gewinnst du n zusätzliche Bit Auflösung; die Summe von 16 Messungen um 2 Bit verschoben macht aus den 10 Bit des Uno 12 Bit. Damit das klappt, braucht das Signal mindestens eine Stufe natürliches Rauschen.
  • Median- und Exponentialfilter: Ein Medianfilter entfernt plötzliche Ausreißer durch Motoren, ein exponentieller gleitender Mittelwert (EMA) liefert mit sehr wenig Speicher eine glatte Kurve.
C++ (Arduino IDE)
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}

Lädst du den Code hoch und öffnest den seriellen Plotter der Arduino IDE, siehst du drei Linien: Der Rohwert zittert, der Mittelwert aus 16 Messungen ist deutlich ruhiger, und der EMA ist die glatteste Kurve, reagiert aber etwas verzögert auf Änderungen. Der Koeffizient ALPHA liegt zwischen 0 und 1: 0,1 bedeutet, dass jede neue Messung mit 10 % ins Ergebnis eingeht und grob die letzten 10 Messungen wirken; erhöhst du ihn, reagiert der Filter schneller, rauscht aber stärker. Welcher Filter passt, hängt vom Signal ab; für eine langsam veränderliche Temperatur eignet sich ein kräftiger EMA, für einen Joystick, der schnell reagieren soll, ein kurzer Mittelwert. Gleitenden Mittelwert, Medianfilter und Hysterese vergleichen wir mit echten Sensorbeispielen in der Anleitung zum Filtern von Sensordaten.

Kurze Einführung in den DAC: von digital zu analog

Ein DAC (Digital-Analog-Wandler) macht das Gegenteil eines ADC: Er nimmt eine Zahl und erzeugt eine dazu proportionale Spannung. Schreibst du 0 in einen 8-Bit-DAC, bekommst du 0 V, bei 255 fast die Versorgungsspannung und bei 128 etwa die Hälfte. Die einfachsten DACs bestehen aus einem Widerstandsnetzwerk namens R-2R. Ein häufiges Missverständnis gleich vorweg: analogWrite() am Arduino Uno ist kein DAC, sondern erzeugt PWM; der Pin schaltet in Wahrheit schnell zwischen 0 V und 5 V hin und her. Für LED-Helligkeit und Motordrehzahl reicht das, brauchst du aber wirklich eine konstante Spannung, musst du den PWM-Ausgang mit einem RC-Tiefpass glätten; die Zeitkonstante des Filters berechnest du mit dem RC-Zeitkonstanten-Rechner. Und Boards mit echtem DAC: Der ESP32 hat an GPIO 25 und GPIO 26 zwei 8-Bit-DACs, die du mit dacWrite(pin, wert) ansprichst; ESP32-S3 und ESP32-C3 haben dagegen keinen DAC. Der Arduino Uno R4 besitzt an Pin A0 einen 12-Bit-DAC. Für Uno R3, Nano und Pico ist das per I2C angeschlossene 12-Bit-Modul MCP4725 der einfachste Weg. Mit einem DAC kannst du Töne erzeugen, Sinus- oder Dreiecksspannungen ausgeben und sogar den DAC-Ausgang mit einem ADC-Eingang verbinden, um den ADC mit bekannten Spannungen zu testen:

C++ (Arduino IDE)
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}

Projektideen mit dem ADC

  • Digitales Voltmeter: Miss mit einem Spannungsteiler 0–25 V und zeige das Ergebnis auf einem LCD; die Schritte findest du in der Anleitung Arduino-Voltmeter bauen.
  • Automatisches Nachtlicht: Lies die Spannung eines LDR und schalte die LEDs ein, wenn es dunkel wird.
  • Intelligenter Blumentopf: Starte mit dem analogen Ausgang eines Bodenfeuchtesensors eine Pumpe, sobald die Erde trocken ist.
  • Joystick-gesteuerter Roboter: Die zwei Achsen eines Joysticks sind zwei getrennte analoge Eingänge; wandle ihre Werte in Motordrehzahl und Richtung um.
  • Strommesser: Lies die stromproportionale Spannung eines ACS712 und sieh, wie viel Strom ein Gerät zieht.
  • Lautstärkeanzeige: Taste den analogen Ausgang eines KY-038-Schallsensors schnell ab und lass je nach Spitzenwert eine LED-Leiste leuchten.
  • Akkuanzeige: Miss in einem batteriebetriebenen Projekt die Spannung und zeige die Restladung in Prozent auf einem Display.

Häufige Fehler und ihre Lösungen

SymptomMögliche UrsacheLösung
Der Wert springt zufällig, obwohl nichts angeschlossen istDer Pin ist offen (floating)Sensor anschließen; unbenutzte Pins nicht lesen oder auf GND ziehen
Der Wert bleibt bei 1023 (beim ESP32 bei 4095) hängenEingang liegt über der Referenz, oder INTERNAL ist gewähltReferenz bzw. Dämpfung anpassen, hohe Spannung mit einem Teiler herunterteilen
Beim ESP32 liefert analogRead() mit aktivem WLAN 0Der Sensor hängt an einem ADC2-PinADC1-Pins GPIO 32–39 verwenden
Der ESP32 zeigt bei kleinen Spannungen 0 und bei großen 4095Der ADC ist an den Rändern nicht linearanalogReadMilliVolts() nutzen, Signal im Bereich 150–2450 mV halten
Die berechnete Spannung weicht 3–5 % vom Multimeter abVref ist nicht 5,00 V (USB-Versorgung)5V-Pin messen und in VREF eintragen oder einen Kalibrierfaktor ergänzen
Beim abwechselnden Lesen zweier Pins beeinflussen sich die WerteMultiplexer und hohe QuellimpedanzErste Messung nach dem Wechsel verwerfen, Quelle unter 10 kΩ halten, 100 nF ergänzen
Die Werte springen, wenn ein Motor oder Relais läuftStörungen auf der gemeinsamen GND-Leitung, Versorgung bricht einLasten über eine eigene GND-Leitung führen, Kondensatoren und Medianfilter nutzen
Nach Anlegen einer Spannung an AREF stimmen die Messungen nicht mehrAREF wurde ohne analogReference(EXTERNAL) benutztZuerst EXTERNAL wählen oder AREF über einen 5-kΩ-Widerstand anschließen
Nach Wahl von INTERNAL steht das Potentiometer schon auf halbem Weg bei 1023Die 1,1-V-Referenz gilt für alle analogen PinsVor dem Lesen ratiometrischer Sensoren zurück auf DEFAULT und ein paar Werte verwerfen
Beim Pico ist der Wert selbst mit Eingang an GND größer als 0ADC-Offset und Rauschen auf ADC_VREFEinen Kanal an AGND legen, Offset messen und abziehen; GP23 auf HIGH setzen
Am schnellsten prüfst du eine ADC-Schaltung, indem du eine bekannte Spannung misst. Verbinde den analogen Eingang zuerst mit GND und prüfe, ob ein Wert nahe 0 erscheint. Schließe dann eine AA-Batterie, deren Spannung du mit dem Multimeter gemessen hast, mit dem Minuspol an GND und dem Pluspol an den Analogpin an: Bei etwa 1,5 V solltest du am Uno rund 307 sehen, am ESP32 mit analogReadMilliVolts() rund 1500 mV und am Pico mit read_u16() rund 29.800. Stimmt das Ergebnis, sind Code und Verdrahtung in Ordnung; wenn nicht, liegt das Problem höchstwahrscheinlich bei der Referenzspannung oder der gemeinsamen Masse.

Der ADC ist die Brücke zwischen der physischen Welt und deinem Code: Kennst du Auflösung, Referenzspannung und Abtastrate, weißt du auch, was jede Zahl auf dem Bildschirm bedeutet und wie sehr du ihr trauen kannst. Miss am Uno die Referenz sauber, nutze am ESP32 die ADC1-Pins und analogReadMilliVolts(), berücksichtige am Pico Offset und Rauschen und beruhige das Ergebnis anschließend mit Mittelwerten und Filtern. In der BlueGrays-App findest du Projekte, die auf analogen Messungen aufbauen, etwa Lichtstärke mit einem LDR messen, ein digitales Voltmeter mit LCD, Temperaturmessung mit einem NTC sowie Servo- und LED-Helligkeitssteuerung mit einem Potentiometer, jeweils Schritt für Schritt mit Schaltplänen und Code.

Häufige Fragen

Was ist ein ADC und wofür braucht man ihn?

Ein ADC (Analog-Digital-Wandler) ist die Schaltung, die die Spannung an einem Pin in eine Zahl umwandelt, die der Mikrocontroller verarbeiten kann. Man braucht ihn, um Bauteile mit analogem Ausgang wie Potentiometer, LDRs sowie Temperatur- und Feuchtesensoren auszulesen. Beim Arduino startet der Befehl analogRead() diesen Wandler.

Was ist der Unterschied zwischen analogen und digitalen Signalen?

Ein analoges Signal kann jeden Wert innerhalb eines Bereichs annehmen und ändert sich stetig, ein digitales Signal besteht nur aus bestimmten Pegeln, beim Arduino LOW und HIGH. digitalRead() sagt dir nur, ob ein Pin 0 oder 1 ist, analogRead() dagegen als Zahl, wie hoch die Spannung ist.

Warum liefert analogRead beim Arduino Werte von 0 bis 1023?

Der ADC des Arduino Uno hat 10 Bit und erzeugt 2^10 = 1024 verschiedene Stufen, die von 0 bis 1023 nummeriert sind. Der Wert 0 steht für 0 V, 1023 für eine Stufe unterhalb der Referenzspannung (meist 5 V). Die 12-Bit-ADCs von ESP32 und Pico liefern Werte von 0 bis 4095.

Wie rechnet man einen ADC-Wert in Volt um?

Nutze die Formel Spannung = ADC-Wert × Referenzspannung / Anzahl der Stufen. Beim Arduino Uno ist das V = Wert × 5,0 / 1024; beim ESP32 liefert analogReadMilliVolts() direkt kalibrierte Millivolt. Beim Pico gilt für den read_u16()-Wert aus MicroPython V = Wert × 3,3 / 65535.

Funktionieren die ADC2-Pins des ESP32 mit WLAN?

Nein. Beim ESP32 nutzt auch der WLAN-Treiber die ADC2-Einheit, deshalb lassen sich die ADC2-Pins (GPIO 0, 2, 4, 12–15, 25–27) bei aktivem WLAN nicht lesen. Schließe analoge Sensoren in WLAN-Projekten an die ADC1-Pins (GPIO 32–39) an.

Was ist ein DAC und worin unterscheidet er sich vom ADC?

Ein DAC (Digital-Analog-Wandler) macht das Gegenteil eines ADC: Er wandelt eine Zahl in eine Spannung um. Mit einem ADC misst man die Spannung eines Sensors, mit einem DAC erzeugt man eine Spannung, etwa für Töne oder Signale. Der Arduino Uno hat keinen DAC, analogWrite() erzeugt PWM; der ESP32 hat zwei 8-Bit-DACs an GPIO 25 und 26, der Uno R4 einen 12-Bit-DAC an A0.

Alle Projekte ansehen
Lichtstärke messen mit LDR
#11Anfänger

Lichtstärke messen mit LDR

Willst du sehen, wie hell dein Zimmer ist, und zwar als Zahl? Der LDR, ein kleines lichtempfindliches Bauteil, misst das Umgebungslicht, und der Arduino schreibt den Wert jede halbe Sekunde auf deinen

4.6(81)
139
Digitales Voltmeter mit LCD-Anzeige
#56Mittel
Premium

Digitales Voltmeter mit LCD-Anzeige

Finde mit einem selbstgebauten Messgerät heraus, wie viel Spannung eine Batterie oder ein Netzteil liefert. Ein Teiler aus zwei Widerständen senkt hohe Spannungen auf ein Niveau, das die Platine lesen

4.5(27)
36
Messung der Lichtintensität mit dem ESP32-LDR-Modul
#113Anfänger

Messung der Lichtintensität mit dem ESP32-LDR-Modul

Echtzeit-Anzeige des ADC-Rohwerts des LDR-Moduls und des anhand von Dunkel- und Hellreferenzwerten berechneten relativen Lichtwerts in Prozent im Serial Monitor. Dieser Prozentwert ist keine Lux-Messung. Vermittelt die Kalibrierungslogik des Moduls. Sollte idealerweise vor Projekt 10 durchgeführt werden, da es zur Festlegung des Schwellenwerts dient.

4.6(36)
55
ESP32: LED-Helligkeit mit Potentiometer (Analog → PWM)
#115Mittel
Premium

ESP32: LED-Helligkeit mit Potentiometer (Analog → PWM)

In diesem Projekt steuern wir die Helligkeit einer LED analog über ein Potentiometer. Der ADC-Pin des ESP32 liest die vom Potentiometer kommende Spannung von 0-3,3 V aus, woraufhin dieser Wert in ein PWM-Signal (Pulsweitenmodulation) umgewandelt und an die LED gesendet wird. So leuchtet die LED beim Drehen des Potentiometers stufenweise auf und erlischt wieder. Mit Arduino Core 3.0+ kann analogWrite() direkt verwendet werden; bei ESP32-S2/S3 ist die ADC-Auflösung auf 12 Bit festgelegt.

4.5(19)
32
Temperaturmessung mit NTC und 2x16 Lcd Display
#44Anfänger
Premium

Temperaturmessung mit NTC und 2x16 Lcd Display

Miss die Umgebungstemperatur mit einem Sensor, der aussieht wie eine kleine Perle. Dieses Bauteil namens NTC lässt Strom umso leichter durch, je wärmer es wird; der Arduino liest diese Änderung, rechn

4.5(33)
44
Servomotorbetrieb mit Potentiometer
#36Anfänger
Premium

Servomotorbetrieb mit Potentiometer

Während du am Knopf des Potentiometers drehst, dreht sich der Arm des Servomotors einfach mit: Das eine Ende des Knopfes bedeutet null Grad, das andere eine halbe Umdrehung. Der Arduino liest die Stel

4.6(37)
52
Led-Steuerung mit Joystick
#59Mittel
Premium

Led-Steuerung mit Joystick

Drück den kleinen Hebel des Joysticks ganz in eine Richtung, und die LED für diese Richtung leuchtet: Für rechts, links, oben und unten gibt es vier verschiedene Farben. Lässt du den Hebel los, spring

4.7(50)
67
ESP32-Farbmischerlampe (3 Potentiometer + RGB-LED + OLED)
#138Fortgeschritten
Premium

ESP32-Farbmischerlampe (3 Potentiometer + RGB-LED + OLED)

Eine intelligente Farbmischer-Lampe mit ESP32, die durch Drehen von drei Potentiometern die gewünschte Farbe mischt! Wenn Sie die Potentiometer für Rot, Grün und Blau drehen, ändert die RGB-LED mit gemeinsamer Kathode sofort ihre Farbe. Auf dem SSD1306-OLED-Display werden für jede Farbe Werte im Bereich von 0 bis 255, visuelle Füllbalken und der HEX-Webfarbcode (z. B. #FF8040) in Echtzeit angezeigt. Ein professionelles Mini-Farbstudio – vermittelt in einem einzigen Projekt Kenntnisse über die RG

4.7(6)
10