Der ESP32 verfügt über zwei integrierte Analog-Digital-Wandler, auch ADC (engl. analog-to-digital converter). Diese arbeiten mit einem Sample-and-Hold-Schaltkreis, sodass die Eingangsspannung während der Wandlung stabil gehalten wird.
Der ESP32 bietet mehrere ADC-Kanäle, die über die Software ausgewählt werden können. Über die ADC-Konfiguration lassen sich Einstellungen wie Auflösung, Abtastrate und Referenzspannung festlegen. Der digitalisierte Wert wird anschließend als Ganzzahl (Integer) bereitgestellt.
In diesem Abschnitt wird die Funktionsweise des ADCs anhand des Wägeverfahrens (sukzessive Approximation) erklärt. Außerdem zeigen wir, wie man die digitalisierten Werte in eine Spannung umrechnet, auf einem OLED-Display anzeigt und externe analoge Sensoren mit Spannungen im Bereich von 0 bis 3,3 V anschließt.
Die Funktionsweise wird in Abb. 1 gezeigt. Der ADC verfügt über zwei interne ADC-Moule:
ADC1
ADC2
Der Sample-and-Hold-Schaltkreis sorgt für stabile Meßergebnisse. Würde die Spannung sich während der Messung ändern, wäre das Messergebnis ungenau. Aus diesem Grund wird die Messung in zwei Schritt durchgeführt: Abtastphase (sample) und Haltephase (hold).
In der Abtastphase ist der Kondensator mit dem Eingangspin verbunden und lädt sich auf die angschlossene Spannung auf. In der Haltephase wird der Kondensator vom Eingangspin getrennt und hält seine Spannung konstant. Der ADC kann nun den digitalen Wert in Ruhe berechnen.
Der ESP32 unterstützt verschiedene Spannungsbereiche für sein ADC-Modul. Hierzu werden verschiedene Dämpfungswerte (engl. attenuation) vorgegeben. Standard ist ein Spannungsbereich von 0 - 3,3 V. Dieser kann über einen Funktionsaufruf angepasst werden:
adc = ADC(pin)
adc.atten(ADC.ATTN_11DB)
| Spannungsbereich | Dämpfung | Code |
|---|---|---|
| 0 – 1 V | 0 dB | ADC.ATTN_0DB |
| 0 – 1,34 V | 2,5 dB | ADC.ATTN_2_5DB |
| 0 – 2 V | 6 dB | ADC.ATTN_6DB |
| 0 – 3,3 V | 11 dB | ADC.ATTN_11DB |
Das ADC-Modul hat eine Standardauflösung von 12 Bit. Eine geringere Auflösung kann drei Vorteile haben: schnellere Messung, geringeres Rauschen und weniger Speicherbedarf.
adc = ADC(pin)
adc.width(ADC.WIDTH_12BIT)
| Auflösung | Digitalwerte | Code |
|---|---|---|
| 9 Bit | 0 - 511 | ADC.WIDTH_9BIT |
| 10 Bit | 0-1023 | ADC.WIDTH_10BIT |
| 11 Bit | 0-2047 | ADC.WIDTH_11BIT |
| 12 Bit | 0-4095 | ADC.WIDTH_12BIT |
Man beachte, dass die Geschwindigkeit oder die Abtastrate nur indirekt über die Auflösung, Anzahl der Kanäle und WiFi-Nutzung (bei ADC2) gesteuert werden kann.
Beim Wägeverfahren wird die analoge Spannung Schritt für Schritt digitalisiert.
Der ESP32 verfügt über einen 12-Bit-ADC, d. h. die Auflösung beträgt 212 = 4096 Schritte. Somit kann eine Eingangsspannung zwischen 0 V und 3,3 V in einen digitalen Wert zwischen 0 und 4095 umgewandelt werden.
Funktionsweise des Wägeverfahrens:
Die Klasse ADC ist Teil des machine-Moduls. Nachdem Erzeugen des ADC-Objekts kann der Wert gemessen und ausgewertet werden.
Mit der Funktion adc.read() wird ein Digitalwert von 0-4095 bei einer 12-Bit-Auflösung zurückgegen. Bei geringer Auflösung ist der Wertebereich entsprechend kleiner.
Mit adc.read_u16() wird der Digital wert auf einen Bereich von 0-65535 skaliert und mit adc.read_uv() wird der Digitalwert in Mikrovolt zurück gegeben. Da die Spannung sich proportional zum Digitalwert verhält, kann diese auch einfach über den Dreisatz berechnet werden.
from machine import ADC
adc = ADC(pin) # Erstelle für einen Pin ein ADC-Objekt
wert = adc.read() # Analogwert entsprechend von 0-4095 (12-Bit-Auflösung)
wert2 = adc.read_u16() # Analogwert im Bereich von 0-65535
wert3 = adc.read_uv() # Analogwert in Mikrovolt
spannung_mV = wert * 3300 / 4095
print(f"ADC: {wert} Spannung: {spannung_mV} mV")
value = poti.read_u16(). Für die Ausgabe direkt in Mikrovolt gibt es die Funktion value = poti.read_uv().
Mit einem Potentiometer lässt sich bspw. die Lautstärke in Audiogeräten (Radio, Gitarrenverstärker) steuern oder die Helligkeit von LEDs einstellen. Des Weiteren dienen sie zur Feinjustierung und Kalibrierung in vielen elektronischen Schaltungen.
Mit dem Potentiometer (auch Poti) an unserem Board (s. Abb. 3) lässt sich mit Hilfe des Analog-Digital-Wandlers eine Spannung zwischen 0 und 3,3 V erfassen und in einen digitalen Wert zwischn 0 und 4095 umwandeln.
from machine import Pin, ADC
poti = ADC(2)
while True:
wert1 = poti.read() # 0–4095
print(f"Poti: {wert1}")
time.sleep(0.2)
Umgebungslichtsensoren (english: ambient light) dienen der Tagerkennung oder können ermitteln, ob das Licht in Räumen ausgeschaltet ist. Der Sensor wandelt Lichtenergie in ein elektrisches Signal.
Ein Lärmpegelsensor wird eingesetzt, um die Lautstärke bzw. den Schalldruckpegel in der Umgebung zu messen. Der Sensor wandelt Schallwellen (akustische Energie) in ein elektrisches Signal um.
Beide Sensoren (s. Abb. 2) liefern einen analogen Wert zwischen 0 und 3,3 V und somit einen Digitalwert zwischen 0 und 4095.
from machine import Pin, ADC
ambientLight = ADC(34)
soundLevel = ADC(35)
while True:
wert2 = ambientLight.read() # 0–4095
wert3 = soundLevel.read() # 0–4095
print(f"Helligkeit: {wert2:4d}")
print(f"Laermpegel: {wert3:4d}")
time.sleep(0.2)
Taster
Light and Sound Umgebungslicht und Lärmpegel mit dem ADC
messwerte={
"poti": poti.read(),
"helligkeit": ambientLight.read(),
...
}
Der Abstandssendsor OCP162H0180 der Firma Wenglor arbeitet mit hochauflösenden CMOS-Zeile und DSP-Technologie und ermittelt den Abstand über eine Winkelmessung.
Du arbeitest als Junior-Entwickler/Entwicklerin in einem Projektteam der Firma Hochland Käse in Heimenkirch. Bei der Abfüllung von Schmelzkäse soll die Temperatur exakt überwacht werden um eine gleichmäßige Füllmenge zu errreichen.
Der Temperatursensor FFXT009 der Firma Wenglor wird für präzise Überwachung von Flüssigkeitstemperaturen in Rohrleitungssystemen eingesetzt. Er hat einen Arbeitsbereich von 20 bis 140 °C und eine analogen Ausgangsspannung von 0 bis 10 V.
Deine Aufgabe ist es, ein kleines Warnsystem zur Temperaturüberwachung entwickeln. Das System soll:
Hardwareaufbau
Die LED ist an Pin 27, der Summer an Pin 16 angeschlossen. Der Sensor wird über einen Spannungsteiler inklusive Schutzbeschaltung an den Pin 4 angeschlossen.
Folgender Beispiel-Code ist bereits vorhanden:
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
from time import sleep
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = SSD1306_I2C(128, 64, i2c)
temperatur = 20
while True:
oled.fill(0)
oled.text(f"Temperatur: {temperatur}", 0, 0)
oled.show()
sleep(1)
3.1 Um die Spannung auf 3,3 V am Eingang zu begrenzen, willst du einen Spannungsteiler einsetzen, mit Z-Diode und Kondensator einsetzen.
3.1.1 Zeichne ...
Die Lösung sollte folgendermaßen aussehen:
Sensor 0–10 V
│
│
R1
│
├────────────────────────── GPIO 4 (ESP32)
│ │ │
R2 100 nF Z-Diode 3,5V
│ │ │
GND GND GND
3.1.2 Begründe den Einsatz der Z-Diode und deren Wert.
Wähle zwei Antworten.
3.1.2 Begründe wieso es sinnvoll ist für die Z-Diode einen niedrigeren Wert als 3,6 V, aber höher als 3,3 V zu nehmen. Wähle zwei Antworten.
3.1.3 Wähle die korrekte Formel zur Dimensionierung des Spannungsteilers. Wähle eine Antwort.
3.1.4 Dein Kollege schlägt $R_2 = 10~k\Omega$. Dimensioniere $R1$
Wähle eine Antwort.
3.2 Du möchtest die rote LED, den Buzzer und den Sensor in das Programm einbinden.
3.2.1 Wähle den Quelltext aus, der die LED und Buzzer korrekt einbindet. Wähle zwei Antworten.
led = Pin(16, mode=Pin.OUT)led = Pin(27, mode=Pin.OUT)buzzer = Pin(16, mode=Pin.OUT)buzzer = Pin(16, mode=Pin.IN)3.2.2 Dein Kollege schlägt folgende fehlerhafte Codezeile zum Einbinden des Sensors vor vor: sensor = Pin(4, mode=Pin.IN). Erkenne den Fehler. Wähle eine Antwort.
3.3 Dein Chef fragt Dich wie man die Auflösung und den Spannungsbereich ändern kann?
3.3.1 Programmiere testweise den Sensor mit einer Auflösung von 9 Bit. Wähle zwei Antworten.
sensor.width(ADC.WIDTH_9BIT)sensor.width(ADC.WIDTH_BIT9)width(ADC.WIDTH_09BIT)sensor(ADC.WIDTH_09BIT)3.3.2 Stelle testweise einen Spannungsbereich von 0 bis 1 V ein. Wähle eine Antwort.
sensor.atten(ADC.ATTN_6DB)sensor.atten(ADC.ATTN_2_5DB)sensor.atten(ADC.ATTN_0DB)sensor.atten(ADC.ATTN_11DB)3.4 Entwickle ein Programm zur Steuerung
Hinweis: Die Auflösung soll 12 Bit betragen und der Spannungsbereich 0 bis 3,3 V.
Die Lösung sollte folgendermaßen aussehen:
led = Pin(27, Pin.OUT)
buzzer = Pin(16, Pin.OUT)
adc = ADC(4)
while True:
wert = sensor.read()
spannung = (wert/ 4095) * 3.3
temperatur = 20.0 + voltage * 12.0
#LED-Logik
if temperature >= 80: led.on()
else: led.off()
#Buzzer-Logik
if temperatur < 78 AND temperatur > 82:
buzzer.toggle()
oled.fill(0)
oled.text(f"Temperatur: {temperatur:.2f}", 0, 0)
oled.show()
sleep(0.5)
from machine import Pin, I2C, ADC |
importieren der Klassen Pin I2C und ADCaus dem Modul machine |
adc = ADC(2) |
ADC-Objekt mit Pin 2 erzeugen |
value = adc.read() |
Spannung am Pin wird gemessen und in einen digitalen Wert zwischen 0 und 4095 gewandelt |
value = adc.read_uv() |
Spannung am Pin wird gemessen und in einen digitalen Wert in Mikrovolt ausgegeben |
adc.atten(ADC.ATTN_11DB) |
Standard-Spannungsbereich wird auf 0 bis 3,3 V eingestellt |
adc.width(ADC.WIDTH_12BIT) |
Standardauflösung von 12 Bit wird eingestellt |