Regenmesser Basisversion - Teil 1 - AZ-Delivery

Dieser Beitrag ist auch als PDF-Dokument verfügbar.

 

Während für die Erfassung von Temperatur, Luftfeuchte, Luftdruck, Beleuchtungsstärke … eine ganze Reihe von Sensoren zur Verfügung stehen, müssen wir in die Werkzeugkiste greifen, um einen Sensor für Niederschläge zu bauen. Es geht einfach darum, relativ kleine Mengen von Flüssigkeiten zu erfassen, die noch dazu keinen kontinuierlichen Fluss darstellen, sondern, im wahrsten Sinn des Wortes, tröpfchenweise auftreten. Diese Tröpfchen gilt es zu sammeln. Wenn das Töpfchen mit Tröpfchen gefüllt ist, muss es automatisch geleert und dieser Vorgang registriert werden. Das Prinzip habe ich mir im Internet von kommerziellen Geräten abgeguckt. Eine Wippe mit zwei Schalen ist leicht drehbar gelagert und kippt, wenn eine bestimmte Füllmenge erreicht ist. Dieser Kippvorgang muss nun durch geeignete Sensoren erfasst werden. Wie das im Einzelnen gelaufen ist, Irrwege eingeschlossen, das erfahren Sie in den nächsten Episoden aus der Reihe

 

MicroPython auf dem ESP32 und ESP8266

 

heute [1] 

 

Der ESP32 als Regenmesser – Teil 1

In der heutigen Folge kümmern wir uns um die Mechanik des Projekts, schauen uns die Funktionsweise von Reedkontakten an und erstellen ein erstes kleines Testprogramm, das wir in den nächsten beiden Episoden gehörig ausbauen werden. Dazu greifen wir in die Trickkiste von MicroPython. Sie erfahren etwas über Interrupts, Kontaktprellen und wie man es programmtechnisch ausschalten kann. Zum Schluss werden wir die Dateien mit den Messwerten per FTP über Funk zum PC übertragen und greifen dabei auf die Technik des Threadings zurück.

 

Mechanik

Die Wippe

Der Sensor für die Messung der Regenmenge ist eine Wippe mit zwei Wannen.

 

Abbildung 1: Bodenteil der Apparatur

Hier ist die Wippe bereits im Bodenteil der Messröhre eingebaut. Ich habe dafür einen Deckel von einem 100-er PVC-Abwasserrohr hergenommen. Damit das Wasser abfließen kann, wurden zwei Öffnungen gesägt.

 

Abbildung 2: Schnittmuster Regenwippe

Abbildung 2 zeigt das Schnittmuster der Wippe, die aus 2mm-Plexiglas gefertigt wurde. Die 1:1-Vorlage in Form einer PDF-Datei, kann heruntergeladen werden. Zum Verkleben habe ich PLEXIGLAS®-Kleber "Acrifix 192" verwendet. Der ist fugenfüllend und härtet unter UV-Licht oder einfach Tageslicht aus. Die Vorlageteile habe ich mit einem wasserlöslichen Klebestift auf das Acrylglas geklebt. Nach dem Aussägen und Bohren kann man das Papier einfach wieder abziehen. Nicht vergessen, zu verklebende Stellen mit Aceton oder Isopropanol reinigen.

 

Die Position der Bohrung von 1,5mm für die Welle aus 1,4mm-Kupferdraht (die Welle soll keinen Rost ansetzen, also kein Eisen verwenden) entscheidet über die Kippfreudigkeit der Wippe. Die nimmt zu, je höher die Bohrung über Grund liegt. Ich benutze die obere Bohrung und komme auf ein Fassungsvermögen von ca. 2,4cm³, bis die Wippe kippt. Welche Regenmenge das auf die Fläche bezogen ausmacht, schauen wir uns später an.

 

Was kann man falsch machen? Die Auflösung der Volumenmessung wird besser, wenn die Wippe möglichst leicht ist. Man sollte also möglichst dünnes Material verwenden und so wenig Klebstoff wie möglich. Mein erster Versuch, die Wippe aus Weißblech oder Kupferblech herzustellen, war ein totaler Flopp. Das Volumen der Wannen reichte nicht aus, um die Wippe zum Kippen zu bringen, weil die Konstruktion viel zu schwer war.

 

Die Aufhängung der Wippe besteht auch aus Acrylglas. Die Seitenteile sind an die 6 mm dicke Bodenplatte geschraubt, damit man das Ding auch auseinandernehmen kann. Die Abmessungen können Sie der Abbildung 3 entnehmen.

 

Abbildung 3: Halterung der Wippe

 

Damit die Wippe nicht an den Seitenwänden scheuert, habe ich kleine Plexiglasscheibchen dazwischen gelegt.

 

Abbildung 4: Wippe von der Seite

 

Abbildung 5: Wippe, Ansicht aus Nord-Ost

 

Damit der Niederschlag gezielt in den Wannen landet, muss er über eine Fläche bekannter Größe gesammelt und via Trichter bis knapp oberhalb der Wippe geführt werden. Natürlich darf immer nur eine der beiden Hälften befüllt werden. Dazu sind drei Dinge zu beachten.

 

       Die Wannen müssen breit genug sein, damit nix danebengeht.

       Die Oberkante der Trennwand muss weit genug neben der Falllinie der Wassertropfen liegen.

       Und, weil große Trichter in der Regel auch dickere Auslaufröhren haben, musste ich mit der Spritztülle einer Silicon-Patrone für einen dünneren Auslauf sorgen. Die Tülle wurde einfach mit Silicon in den Trichter geklebt.

 

Ein 100-er-Abwasserrohr, das den Trichter trägt, wurde so abgelängt, dass der Trichter in die richtige Position gebracht werden kann. Abbildung 5 zeigt die drei Bestandteile der Mechanik.

 

Abbildung 6: Die mechanischen Teile des Regenmessers

 

So sieht das fertige Gerät aus. Die Öffnung im Rohr ermöglicht die Kontrolle beim genauen Ausrichten des Trichters. Gegebenenfalls kann man das herausgesägte Stück mit Scharnieren versehen und als Türchen verwenden.

 

Abbildung 7: Messstation zusammengebaut

 

Kippbewegung registrieren

Kommen wir zur Feststellung der Kippbewegung. Messungen mit einer Pipette haben ergeben, dass die Wippe bei leicht unterschiedlichen Füllmengen nach rechts und links kippt, 2,4cm³ und 2,5cm³. Dieser Umstand hat sich offenbar aus ungleichem Kleberauftrag oder durch andere Asymmetrien ergeben. Also mussten beide stabile Endlagen erfassbar sein. Anfangs hatte ich vor, einen Beschleunigungssensor vom Typ MPU6050 in Form eines GY 521-Moduls zu verwenden. Die benötigten vier Leitungen störten jedoch das Kippen der Wippe so stark, dass ich davon Abstand nehmen musste. Reflexlichtschranken waren mir zu klobig und so landete ich schließlich bei Reedkontakten.

 

Das sind kleine, magnetisch betätigte Schalter in einem Glasröhrchen von 2mm x 13mm. Das Gemeine an den Dingern sind die starren Anschlussdrähte. Ich habe vier Stück von den Kontakten gekillt, weil beim Verbiegen zu nahe am Glas dieses sofort splittert und so das Bauteil tötet.

 

Abbildung 8: Reed-Kontakt

 

Schließlich ist es gelungen, zwei von den Dingern an einer Seitenwand der Halterung mit Zwei-Komponenten-Knete zu befestigen. Schaut vogelwild aus, funktioniert aber gut. Die Ableitung befestigt man am besten in gleicher Weise.

 

Abbildung 9: Position der Kontakte und des Magneten

 

An die Wippe wird ein kleiner Neodym-Scheibenmagnet geklebt (Acrifix) und nach dieser Position die Kontakte ausgerichtet. Die Abbildung 10 verdeutlicht die Funktionsweise der Reed-Kontakte und erklärt, warum diese Bauform von Magnet nicht genau vor dem Kontakt sitzen darf.

 

Abbildung 10: Wirkungsweise eines Reed-Kontakts

 

Außerhalb von Magnetfeldern ist der Kontakt offen (1). Die Kontaktfedern sind aus einem ferromagnetischen Material, wohl Eisen oder einer entsprechenden Legierung. Die Pole eines Scheibenmagneten sitzen an den Schnittflächen. Nähert man den Reed-Kontakt an, wird der Eisendraht (unten) durch magnetische Influenz selbst zu einem Magneten (Südpol) und zieht die zweite Kontaktfeder an. Der Kontakt schließt (2).

 

Würde man den Scheibenmagneten mittig unter den Kontakt schieben, werden in den Federn gleichartige Pole influenziert. Weil die sich abstoßen, kann der Kontakt nicht schließen (3).

 

Kleine Stabmagneten kann man direkt parallel zum Kontakt legen, weil in den Kontaktfedern dann unterschiedliche Pole influenziert werden, schließt der Kontakt (4).

 

 

Hardware

Bei beiden Controllerfamilien, ESP32 und ESP8266, muss man sich erst einmal Gedanken zu den verwendbaren GPIO-Pins machen. Einige davon sind in den Boot-Prozess eingebunden und daher nicht uneingeschränkt einsetzbar. Ferner brauchen wir neben drei IRQ-Eingängen, einem Taster-Eingang und einem LED-Ausgang im Endausbau den I2C- und den SPI-Bus, die alleine schon 6 Pins belegen. Die Tabellen geben über die Verwendung der Pins Auskunft. Beim ESP8266 bleiben neben den Busleitungen nur 3 GPIO-Pins übrig, von denen D0 = GPIO16 nicht IRQ-fähig ist. Die "Kleinen" scheiden also für unser Projekt aus.

 

Aber auch beim ESP32 gibt es ein Problem. Pin 12 darf beim Booten nicht HIGH sein, weil der Controller sonst nicht hochfährt. Dummerweise ist dieser Anschluss aber die MISO-Leitung des SPI1-Busses und wird durch den Slave auf 3,3V gezogen. Somit ist SPI1 tabu. Also SPI2 oder Soft-SPI verwenden. Dazu kommen wir im nächsten Beitrag.

 

Kommen wir zu den Teilen, die für das Projekt gebraucht werden. In der Tabelle sind alle Bauteile aufgeführt, die im gesamten Projekt gebraucht werden. In dieser ersten Episode kommen die grau unterlegten erst einmal nicht zum Einsatz.

 

1

ESP32 Dev Kit C unverlötet oder

ESP32 Dev Kit C V4 unverlötet oder

ESP32 NodeMCU Module WLAN WiFi Development Board mit CP2102 oder

NodeMCU-ESP-32S-Kit oder

ESP32 Lolin LOLIN32 WiFi Bluetooth Dev Kit

1

10x N/O Reed Schalter Magnetische Schalter 2 * 14mm

1

Real Time Clock RTC DS3231 I2C Echtzeituhr

1

SPI Reader Micro Speicher SD TF Karte Memory Card Shield Modul

1

SD-Card zum Beispiel 8GB

1

GY-21 HTU21 Feuchtigkeit und Temperatur Sensor

1

MB-102 Breadboard Steckbrett mit 830 Kontakten 3er

1

0,96 Zoll OLED SSD1306 Display I2C 128 x 64 Pixel

1

LED

1

Widerstand 220Ω

2

Widerstand 10kΩ

1

KY-004 Taster Modul oder

Mikroschalter Taster Set - 180 Stück, Verschiedene Größen, Vielseitige Taster für Elektronik

optional

Logic Analyzer

Tabelle 3: Bauteile

 

Von den 10 Reed-Kontakten des Sets werden 2 Stück gebraucht (oder wie bei mir sechs).

 

Wie die Teile verbunden werden, verrät der Schaltplan der Abbildung 11.

 

Abbildung 11: Regenmesser - Schaltung

 

Die Software

Fürs Flashen und die Programmierung des ESP32:

Thonny oder

µPyCraft

 

 

Verwendete Firmware für einen ESP32:

MicropythonFirmware Download

 v1.19.1 (2022-06-18) .bin

 

 

Die MicroPython-Programme zum Projekt:

timeout.py Nichtblockierender Software-Timer

oled.py OLED-API

ssd1306.py OLED Treiber

regenmesser.py Demoprogramm

 

MicroPython - Sprache - Module und Programme

Zur Installation von Thonny finden Sie hier eine ausführliche Anleitung (english version). Darin gibt es auch eine Beschreibung, wie die Micropython-Firmware (Stand 18.06.2022) auf den ESP-Chip gebrannt wird.

 

MicroPython ist eine Interpretersprache. Der Hauptunterschied zur Arduino-IDE, wo Sie stets und ausschließlich ganze Programme flashen, ist der, dass Sie die MicroPython-Firmware nur einmal zu Beginn auf den ESP32 flashen müssen, damit der Controller MicroPython-Anweisungen versteht. Sie können dazu Thonny, µPyCraft oder esptool.py benutzen. Für Thonny habe ich den Vorgang hier beschrieben.

 

Sobald die Firmware geflasht ist, können Sie sich zwanglos mit Ihrem Controller im Zwiegespräch unterhalten, einzelne Befehle testen und sofort die Antwort sehen, ohne vorher ein ganzes Programm kompilieren und übertragen zu müssen. Genau das stört mich nämlich an der Arduino-IDE. Man spart einfach enorm Zeit, wenn man einfache Tests der Syntax und der Hardware bis hin zum Ausprobieren und Verfeinern von Funktionen und ganzen Programmteilen über die Kommandozeile vorab prüfen kann, bevor man ein Programm daraus strickt. Zu diesem Zweck erstelle ich auch gerne immer wieder kleine Testprogramme. Als eine Art Makro fassen sie wiederkehrende Befehle zusammen. Aus solchen Programmfragmenten entwickeln sich dann mitunter ganze Anwendungen.

 

Autostart

Soll das Programm autonom mit dem Einschalten des Controllers starten, kopieren Sie den Programmtext in eine neu angelegte Blankodatei. Speichern Sie diese Datei unter main.py im Workspace ab und laden Sie sie zum ESP-Chip hoch. Beim nächsten Reset oder Einschalten startet das Programm automatisch.

 

Programme testen

Manuell werden Programme aus dem aktuellen Editorfenster in der Thonny-IDE über die Taste F5 gestartet. Das geht schneller als der Mausklick auf den Startbutton, oder über das Menü Run. Lediglich die im Programm verwendeten Module müssen sich im Flash des ESP32 befinden.

Zwischendurch doch mal wieder Arduino-IDE?

Sollten Sie den Controller später wieder zusammen mit der Arduino-IDE verwenden wollen, flashen Sie das Programm einfach in gewohnter Weise. Allerdings hat der ESP32/ESP8266 dann vergessen, dass er jemals MicroPython gesprochen hat. Umgekehrt kann jeder Espressif-Chip, der ein kompiliertes Programm aus der Arduino-IDE oder die AT-Firmware oder LUA oder … enthält, problemlos mit der MicroPython-Firmware versehen werden. Der Vorgang ist immer so, wie hier beschrieben.

 

 

Ein erster Test

Am besten beginnen wir mit dem Hochladen der folgenden Dateien in den Flash des ESP32:

 

oled.py, ssd1306.py, ds3231.py und timeout.py

 

Wenn alles zusammengebaut ist, starten wir die ersten Tests. In REPL geben wir die folgenden Zeilen ein. Das Schöne an MicroPython ist, dass man die Wirkung von Befehlen von der Kommandozeile aus testen kann, bevor man sie in einem Programm einbaut. Genau das tun wir jetzt. Wir bringen die Wippe in die linke Position. Die Eingaben sind fett formatiert, die Antworten vom System kursiv.

 

>>> from machine import Pin

>>> reedR = Pin(16,Pin.IN)

>>> reedL = Pin(17,Pin.IN)

>>> reedR()

1

>>> reedL()

0

 

Nach dem Umklappen der Wippe:

 

>>> reedR()

0

>>> reedL()

1

 

Das funktioniert also schon mal. Bei der Abfrage der Pegel nutze ich die Eigenschaft von Pin-Objekten callable, also aufrufbar, zu sein. Das wird durch die Methode Pin.__call__() ermöglicht. Sie gehört zu den sogenannten Magic Methods und erlaubt den Aufruf des Objekts wie eine Funktion. Folgende Anweisungen sind daher synonym zu gebrauchen.

 

>>> reedR(1)

>>> reedR.value(1)

>>> reedR.on()

 

Oder

 

>>> reedR()

0

>>> reedR.value()

0

>>> reedR.on()

0

 

Nächster Test: I2C-Bus. Wir binden das Modul SoftI2C ein, instanziieren ein Objekt, i2c und schauen nach, wer auf dem Bus so vertreten ist.

 

>>> from machine import Pin, SoftI2C

>>> i2c=SoftI2C(scl=Pin(22),sda=Pin(21),freq=100000)

>>> i2c.scan()

[60, 87, 104]

 

Dass drei Peripheriegeräte-Adressen gefunden werden überrascht Sie jetzt sicher, wir haben doch nur zwei Module am Bus. Ja, aber – das DS3231-Modul hat neben dem RTC-Chip auch noch ein 32Kb = 8KB – EEPROM mit der Hardwareadresse 87 = 0x57 auf der Platine. Für uns interessant sind die 60 = 0x3C (OLED) und die 104 = 0x68 (DS3231). Das EEPROM könnte man zum Beispiel zum dauerhaften Speichern von Konfigurationsdaten nutzen. Funzt also auch.

 

Oled-Display: Bei der Instanziierung übergeben wir das I2C-Objekt und sagen der API, dass unser Display 64 Pixel hoch ist.

 

>>> d=OLED(i2c,heightw=64)

this is the constructor of OLED class

Size:128x64

>>> d.writeAt("Hallo Welt",3,0)

13

 

"Hallo Welt" wird in der Mitte der obersten Zeile ausgegeben. Der zurückgegebene Wert 13 ist die nächste freie Schreibposition in der Zeile.

 

Die RTC (Real Time Clock = Echtzeituhr) liegt auch am I2C-Bus. Dem Konstruktor des RTC-Objekts übergeben wir daher ebenfalls die I2C-Instanz. Dann stellen wir Datum und Uhrzeit ein und rufen die Zeit ab. Es ist ein Tupel mit den folgenden sieben Werten zu übergeben (Jahr, Monat, Tag, Wochentag, Stunde, Minute, Sekunde). Es lohnt sich auch, das sehr umfangreiche Modul ds3231.py näher in Augenschein zu nehmen.

 

>>> rtc=DS3231(i2c)

DS3231 bereit @ 0x4C

>>> rtc.DateTime((2024,6,14,5,14,19,30))

>>> rtc.Time()

[14, 19, 32]

 

Der ESP32 verfügt zwar auch über eine RTC, diese besitzt aber keinen Alarm-Timer. Um eine Wecker-Funktion zu bekommen, müssen wir auf den DS3231 zurückgreifen und – auf Programmunterbrechungen, Interrupts, kurz IRQs. Sie dienen dazu, ein externes Event an das laufende Programm zu melden und dessen Bedienung durch eine sofortige Programmunterbrechung anzufordern (Interrupt Request).

 

Die Kontakte der Wippe und die RTC können solche Ereignisse auslösen, indem der Pegel an einem GPIO-Pin wechselt (Pin Change IRQ). Wir müssen für jedes Ereignis einen GPIO-Eingang definieren. Der IRQ kann scharfgeschaltet werden, nachdem eine Behandlungsroutine (ISR = Interrupt Service Routine) definiert wurde. Im Parameter pin wird vom System das auslösende Pin-Objekt übergeben. Die Eingänge sind mit externen Pullups von 10kOhm beschaltet, weil die internen zu hochohmig sind. Die Flankensteilheit wird so verbessert – das hat mir das DSO (Digitale Speicher Oszilloskop) erzählt.

 

>>> reedR = Pin(16,Pin.IN)

>>> reedL = Pin(17,Pin.IN)

led=Pin(2,Pin.OUT,value=0)

 

>>> def pinIRQ(pin):

    global source

    if pin==reedL:

        source="L"

        led(0)

    elif pin==reedR:

        source="R"

        led(1)

 

>>> reedR.irq(handler=pinIRQ, trigger=Pin.IRQ_FALLING)

<IRQ>

>>> reedL.irq(handler=pinIRQ, trigger=Pin.IRQ_FALLING)

<IRQ>

 

Beim Scharfschalten wird die Referenz auf die ISR übergeben und als Trigger die fallende Flanke festgelegt.

 

Wird die Wippe jetzt von Hand gekippt, dann leuchtet beim Kippen nach rechts die LED auf und erlischt beim Kippen nach Links. – Gespenstisch, oder? – Es läuft doch kein Programm und die Kontakte sind ja auch nicht direkt mit dem Schaltkreis der LED verbunden. Die IRQs sind also auch dann aktiv, wenn kein eigenes Hauptprogramm läuft. Was jetzt unterbrochen wird ist REPL, die Read Eval Print Loop. Und so schalten wir die Magie wieder aus.

 

>>> reedL.irq(handler=None)

<IRQ>

>>> reedR.irq(handler=None)

<IRQ>

 

Wir werden das nutzen, um beim Verlassen des Programms aufzuräumen und eine saubere Stube zu hinterlassen. Diesen Vorgang können wir durch Drücken der Taste an GPIO4 auslösen – später, nicht jetzt.

 

Für den Heart Beat (Lebenszeichen) während des Laufs der Hauptschleife setzen wir die LED und einen nichtblockierenden Softwaretimer ein. Der läuft im Hintergrund ab, ohne dass der Schleifendurchlauf dadurch blockiert wird. Die Magie steckt hier in einer Closure. Das ist eine Funktion, die in einer umgebenden Funktionsdefinition gekapselt ist. Dadurch, dass die innere Funktion Variablen der umgebenden Funktion nutzt, bleiben sowohl die innere Funktion sowie die Variablen nach dem Verlassen der umgebenden Funktion am Leben. Normalerweise werden ja alle Innereien einer Funktion beim Verlassen derselben eingestampft. Oh mystisches MicroPython – Ommm!

 

Die umgebende Funktion heißt hier TimeOutMs(). Sie wohnt im Modul timeout.py, von wo wir sie importieren. In TimeOutMs() lebt die Funktion compare(), die sich das übergebene Argument 5000 und außerdem den aktuellen Stand des Timer-Ticks krallt. Solange die Differenz aus weiteren Zeitmarken und dem eingangs festgehaltenen Timer-Tick die 5000 nicht übersteigt, liefert die Funktion compare() den Wert False zurück, andernfalls True. TimeOutMs() liefert beim Beenden eine Referenz auf compare() zurück und macht die Closure somit unsterblich. Diese Referenz weisen wir dem Bezeichner jetztBlinken zu und können die Funktion compare() unter dem Pseudonym jetztBlinken jederzeit aufrufen.

 

>>> from timeout import TimeOutMs

>>> jetztBlinken=TimeOutMs(5000)

>>> jetztBlinken()

False

>>> jetztBlinken()

False

>>> jetztBlinken()

True

 

Nach Ablauf von fünf Sekunden bekommen wir als Ergebnis True. Die Funktionsdefinition ist recht mickerig, lohnt sich aber untersucht zu werden. Öffnen Sie dazu einfach die Datei timeout.py in einem Editorfenster.

 

 

Das Programm

Mit diesen Handversuchen haben wir im Prinzip bereits das gesamte Programm besprochen. Alle Elemente tauchen in vielleicht etwas geänderter Reihenfolge wieder auf, mit ein paar kleinen Zugaben, die kommentiert sind.

 

# regenmesser.py

 

from oled import OLED

from machine import Pin, SoftI2C

from time import sleep_us, sleep, sleep_ms

from ds3231 import DS3231

import sys

from timeout import TimeOutUs, TimeOutMs

 

# externe 10k-Pullups bringen steilere Flanken!

reedR = Pin(16,Pin.IN) # rechts prellt 75us

reedL = Pin(17,Pin.IN) # links kein Prellen

key=Pin(4,Pin.IN,Pin.PULL_UP) # Tasteneingang an GPIO4

                              # mit internem Pullupwiderstand

led=Pin(2,Pin.OUT,value=0)

 

i2c=SoftI2C(scl=Pin(22),sda=Pin(21),freq=100000)

i2cDevices=i2c.scan()

i2cNamen={ # Das Dictionary erleichtert die Identifikation

    0x57: "DS3231.EEPROM 32Kb",

    0x68: "DS3231.RTC",

    0x3C: "OLED",

    0x40: "SHT21",

    }

print("I2C-Devices @ ")

for i in i2cDevices:  # Nummer in Hexcode und Klartext wandeln

    print(hex(i),i2cNamen[i])

print()

 

d=OLED(i2c,heightw=64)

rtc=DS3231(i2c)

 

source="*"

 

# Inhalt der Kippschalen in ccm

cLinks = 2.4  # ccm

cRechts = 2.5

 

# Trichter Durchmesser d=10,9cm

area=(10.9/2)**2 * 3.1415  # Trichterfläche

bucketHour=0 # Der Sammeleimer

     

# IRQ-Service-Routine

def pinIRQ(pin):

    global source # Damit der neue Wert die ISR verlassen kann

    if pin==reedL:

        source="L"

    elif pin==reedR:

        source="R"

 

def shutdown(): # Funktion zum Aufraeumen beim Beenden

    reedL.irq(handler=None)

    reedR.irq(handler=None)

    print("von User abgebrochen")

   

# Pin Change IRQ scharfschalten

reedR.irq(handler=pinIRQ, trigger=Pin.IRQ_FALLING)

reedL.irq(handler=pinIRQ, trigger=Pin.IRQ_FALLING)

 

jetztBlinken=TimeOutMs(2000) # Das erste Blinken initiieren

 

while 1:  # Hauptschleife

    Y,M,D,_,h,m,s=rtc.DateTime() # Datum und Zeit holen

    if source=="L":

        source="#"  # Trigger zuruecksetzen

        bucketHour += cLinks  # aufsummieren

        print("Links", bucketHour,"+",h,":",m,":",s)

 

    elif source=="R":

        source="-"  # Trigger zuruecksetzen

        bucketHour += cRechts # aufsummieren

        print("rechts",bucketHour,"-",h,":",m,":",s)

 

    datum=f"{D:02}.{M:02}.{Y}" # Datums- und Zeit-String bauen

    zeit=f"{h:02}:{m:02}:{s:02}"

    niederschlag="\'\'\'\' {:.2f} mm".  /

    format(bucketHour/area*10) # dto. Niederschlag in mm

 

    d.clearAll(False)          # Display loeschen

    d.writeAt(datum,3,0,False)

    d.writeAt(zeit,4,1,False)

    d.writeAt(niederschlag,3,3)

   

    if jetztBlinken(): # Wenn Timer abgelaufen, kurz blitzen

        jetztBlinken=TimeOutMs(2000) # Ablauf neu setzen

        led(1) # LED an

        sleep_ms(5)

        led(0) # und wieder aus

       

    if key()==0: # Falls Taste key gedrueckt,

        sys.exit(shutdown()) # shutdown() aufrufen und Ende

 

Um Text mit Zahlen gemischt auszugeben, kann man vorteilhaft Formatstrings benutzen. Es gibt zwei Varianten, f-String und die Funktion format(). Die Notierungen sind ähnlich.

 

>>> D,M,Y = 14,6,2024

>>> f"{D:02}.{M:02}.{Y}"

'14.06.2024'

 

Das baut Tag und Monat zweistellig und die Jahreszahl in einen String ein, getrennt durch Punkte.

 

>>> "{:02}.{:02}.{}".format(D,M,Y)

'14.06.2024'

 

Diese Form liefert dasselbe Ergebnis. Die erste Variante ist für den Aufbau von HTML-Texten bestens geeignet. Die zweite Variante erlaubt das Unterbrechen der Zeile durch "\", wenn sie zu lang wird, wie oben im Listing. Die Formatanweisungen sind sehr vielfältig. Sie alle aufzuführen, würde mehrere Blogfolgen füllen.

 

Ein Wort noch zu den Displayausgaben. Änderungen für die Anzeige werden zunächst in einen Pufferspeicher im RAM geschrieben, der auch gleich an das Display geschickt wird, wenn man in der writeAT()- oder clearAll()-Anweisung das Argument False weglässt oder durch ein True ersetzt. Die Anzeige flackert dann aber, und das nervt. Deshalb lasse ich die neuen Pufferinhalte erst einmal komplett im RAM aufbauen und übertrage den gesamten Inhalt erst mit dem letzten Schreib-Befehl. Das nimmt dem Ganzen die Hektik.

 

Starten Sie nun das Programm und bewegen Sie die Wippe. Möglicherweise taucht mehrmals nacheinander die Ausgabe links oder rechts auf, auch wenn nur eine Kippbewegung ausgeführt wurde. Dieses Phänomen hatte ich bei meinem rechten Reed-Kontakt auch – Kontaktprellen beim Schließen. Wie man das programmtechnisch eliminieren kann und weitere Ergänzungen zum Projekt gibt es in der nächsten Folge.

 

Bis dann – bleiben Sie dran!

 

Esp-32Esp32Esp32-dev-kitGrundlagen softwareProjekte für fortgeschritteneSensoren

1 Kommentar

Francesco Cerquone

Francesco Cerquone

Salve. Mi chiedevo se per misurare in modo semplice la quantità di acqua caduta dal cielo non è meglio misurare il suo peso, anzichè il suo volume?
Per esempio un estensimetro o cella di carico come sensore del peso dell’acqua….

Kommentar hinterlassen

Alle Kommentare werden von einem Moderator vor der Veröffentlichung überprüft

Empfohlene Blogbeiträge

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery