Waage mit Äpfeln

ESP | Analogwerte messen und auswerten mit MicroPython


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.

Funktionsweise des Analog-Digital-Wandlers und das Wägeverfahren

Funktionsweise des Analog-Digital-Wandlers mit Sample-and-Hold-Schaltkreis
Abb. 1 Funktionsweise des Analog-Digital-Wandlers mit Sample-and-Hold-Schaltkreis.
Funktionsweise

Die Funktionsweise wird in Abb. 1 gezeigt. Der ADC verfügt über zwei interne ADC-Moule:

ADC1

  • Kanäle: 8 (Pin 32–39)
  • Auflösung: 12 Bit (0–4095)
  • Spannungsbereich: 0–3,3 V (abhängig von der Dämpfung)
  • Verwendung: Frei nutzbar für analoge Sensoren
  • Beispiel: Potentiometer, Helligkeit und Lärmpegel

ADC2

  • Kanäle: 10 (Pin 0, 2, 4, 12-15 und 25-27)
  • Auflösung: 12 Bit
  • Spannungsbereich: 0–3,3 V
  • Wichtig: Wird von Wi-Fi genutzt – reduzierte Geschwindigkeit
Sample-and-Hold-Schaltkreis

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.

ADC-Logik

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)
Spannungs­bereich Dämp­fung 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)
Auf­lösung Digital­werte 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.

Sukzessive Approximation - Wägeverfahren
Balkenwaage mit Äpfeln
Abb. 2 Sukzessive Approximation am Beispiel des Wägeverfahrens.

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:

Wägeverfahren
  • Start mit der halben Auflösung als Vergleichswert (2048).
  • Ist die Eingangsspannung kleiner, wird der Vergleichswert halbiert und subtrahiert, sonst addiert.
  • Nach spätestens 12 Vergleichen (12 Bit) steht der digitale Wert fest.

Analogwerte messen und auswerten Auslesen des Digitalwertes

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.

$$U_{in\:mV} = wert \cdot \frac{3300}{4095}$$

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

Potentiometer, Helligkeit und Lärmpegel

Taster am Pin 17 und Poti am Pin 2
Abb. 3 Taster am Pin 17 und Poti am Pin 2.
Potentiometer

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)
Helligkeit und Lärmpegel
Umgebungslichtsensor am Pin 34 und Lärmpegelsensor am Pin 35
Abb. 4 Umgebungslichtsensor am Pin 34 und Lärmpegelsensor am Pin 35.

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 Laut­stärke bzw. den Schall­druck­pegel 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)

Arbeitsauftrag 1 reading sensor data

Taster

  1. Erstelle den Ordner 06-ADC.
  2. Erstelle die Datei potentiometer-basic.py und gib den passenden Code ein, so dass der Wert des Potis als Digital- und Spannungswert ausgegeben wird.
  3. Kannst Du den Poti auch so programmieren, dass dieser die Helligkeit der LED steuert?

Light and Sound Umgebungslicht und Lärmpegel mit dem ADC

  1. Erstelle die Datei light-basic.py und gib den passenden Code zur Anzeige des Unmgebungslichtwertes ein.
  2. Gib den Wert am OLED-Display und in Thonny aus.
  3. Erstelle die Datei sound-basic.py zur Ausgabe des Lärmpegels.
  4. Wird der Lärmpegel mehr als 5 s überschritten, soll die rote LED leuchten.


Arbeitsauftrag 2 ADC mit Abstands­sensor

Abstandssendsor OCP162H0180 der Firma Wenglor
Abb. 5 Abstandssendsor OCP162H0180 der Firma Wenglor.

Der Abstandssendsor OCP162H0180 der Firma Wenglor arbeitet mit hochauflösenden CMOS-Zeile und DSP-Technologie und ermittelt den Abstand über eine Winkelmessung.

  1. Ermittle den Arbeitsbereich und den Messbereich des Sensors.
  2. Ermittle die analoge Ausgangsspannung des Sensors
  3. Dimensioniere einen Spannungsteiler, so dass die Ausgangsspannung in einem Bereich von 0-3,3 V liegt.
  4. Welches elektronische Bauelement setzt man in der Praxis ein um den Mikrocontroller­eingangs­pin vor Übersspannungen zu schützen.
  5. Leite die Formel für die Berechnung des Abstandes für deinen Sensor her.
  6. Programmiere die Abstandsanzeige auf dem OLED-Display.

🎯 Arbeitsauftrag 3 Temperatur Warnsystem

Situationsbeschreibung

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:

  • Den Temperaturwert auf zwei Nachkommastellen am OLED-Display anzeigen.
  • Eine rote LED einschalten, sobald die Zieltemperatur von 80 °C erreicht wird.
  • Einen Buzzer ein akustisches Warnsignal ausgeben lassen, wenn die Temperatur um mehr als 2 °C abweicht.

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.

Temperatursensor FFXT009 der Firma Wenglor
Abb. 6 Temperatursensor FFXT009 der Firma Wenglor mit einem Arbeitsbereich von 20 bis 140 °C.

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

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 ...

  • den Spannungsteiler
  • mit Z-Diode und
  • Kondensator.
  • Gib geeignete Werte für den Kondensator und Z-Diode an.

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.

  1. Sie schützt vor Überspannungen
  2. Der ESP verträgt maximal 3,3 V am Eingangspin
  3. Die Z-Diode unterdrückt Rauschen.
  4. Der ESP verträgt maximal 3,6 V am Eingangspin


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.

  1. Z-Dioden leiten bei hohen Temperaturen schlechter
  2. Z-Dioden begrenzen nicht ideal
  3. Z-Dioden sollten auch unter 3,3 V arbeiten
  4. Z-Dioden haben eine Toleranz von typisch: ±5 %



3.1.3 Wähle die korrekte Formel zur Dimensionierung des Spannungsteilers. Wähle eine Antwort.

  1. $U_{ein} = U_{aus} \cdot (R_1+R_2)/R_2$
  2. $U_{aus} = U_{ein} \cdot R_1/(R_1+R_2)$
  3. $U_{aus} = U_{ein} \cdot R_2/(R_1+R_2)$
  4. $U_{aus} = U_{ein}/R_2 \cdot (R_1+R_2)$


3.1.4 Dein Kollege schlägt $R_2 = 10~k\Omega$. Dimensioniere $R1$
Wähle eine Antwort.

  1. $R_1 = 2 \cdot R_2 = 20~k\Omega$
  2. $R_1 = 1/2 \cdot R_2 = 5~k\Omega$
  3. $R_1 = 1/3 \cdot R_2 = 3,33~k\Omega$
  4. $R_1 = 2/4 \cdot R_2 = 6,67~k\Omega$


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.

  1. led = Pin(16, mode=Pin.OUT)
  2. led = Pin(27, mode=Pin.OUT)
  3. buzzer = Pin(16, mode=Pin.OUT)
  4. 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.

  1. Die Pin-Nummer ist fehlerhaft
  2. Die Codezeile ist gar nicht fehlerhaft
  3. Es wird kein Objekt der Klasse ADC erzeugt
  4. Der Buzzer wird eingeschaltet

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.

  1. sensor.width(ADC.WIDTH_9BIT)
  2. sensor.width(ADC.WIDTH_BIT9)
  3. width(ADC.WIDTH_09BIT)
  4. sensor(ADC.WIDTH_09BIT)


3.3.2 Stelle testweise einen Spannungsbereich von 0 bis 1 V ein. Wähle eine Antwort.

  1. sensor.atten(ADC.ATTN_6DB)
  2. sensor.atten(ADC.ATTN_2_5DB)
  3. sensor.atten(ADC.ATTN_0DB)
  4. sensor.atten(ADC.ATTN_11DB)

3.4 Entwickle ein Programm zur Steuerung

  • der Status-LED,
  • des Buzzertons und
  • die Ausgabe der aktuellen Temperatur auf dem Display.

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)

Wichtige Funktionen zum Ansteuern von Sensoren



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