RC PWM Receiver - Ein Mikrocontroller Projekt zur Auswertung und Weiterverarbeitung von RC-Empfänger Signalen am ESP32

Motivation

Klick mich

PWMReceiver in Testumgebung

Während der Umsetzung der für den Solö Ruff vorgesehenen Funktionen kam das neue nicht abwärtskompatible ESP32-IDF Framework heraus. Nach dem Update meiner SW-Entwicklungsumgebung funktionierte auch die von TheDIYGuy999 bereitgestellte Interrupt gesteuerte Messung der vom RC-Empfänger ausgegebenen PWM Signale nicht mehr in meinem Projekt. Da die PWM Signalauswertung aber eine fundamentale Basisfunktion für meine RC-ESP32 Projekte darstellt, ich eigentlich nicht so genau durchschaute wie diese über Interrupts gesteuerten Messungen funktionierten und demzufolge auch die Laufzeitbedingungen für mich unbekannt waren, habe ich das als Ansporn genommen, mit der IDF 5.4 meine eigene Umsetzung zu erarbeiten. Als Startpunkt diente der Programming Guide der RMT-API inklusive der Beispielimplementierungen für Infrarot-Sendeempfänger, deren Protokolle ja auch auf PWM-Signalen basieren.

Funktionsumfang des Receivers

Eine flexibel konfigurierbare und im Einsatz robust funktionierende Implementierung waren für mich wichtig. Daher lässt sich die Anzahl der auszuwertenden RC-Kanäle und deren Messbereiche in meiner Umsetzung anpassen. Auch ist eine Kompensation der Trimmung über den Sender und eine Invertierung des verarbeiteten Signales pro Kanal enthalten. Damit die Auswertung auf dem Wasser im Modell auch mit alten, nicht digitalen (und somit Störanfälligen) Sendern und Empfängern robust eingesetzt werden kann sind konfigurierbare Überwachungs-Funktionen für die Zykluszeit (Erkennung kein RC Signal) und für die Signalbandbreite (für eine Failsafe Funktion) enthalten. Ebenso können Schwellen für Signalsprünge angegeben werden, die dazu führen, dass die Bewegungsänderung im verarbeiteten Signal nicht umgesetzt wird (Streuungskompensation).

Schlussendlich sind auch noch individuell ein- und ausschaltbar eine Laufzeitmessung und serielle Ausgabenfunktionen für Konfiguration, Test und Fehlersuche mit dabei.

Technische Voraussetzungen, Beschränkungen und das Konzept

Im Allgemeinen werden die Signale der einzelnen RC-Kanäle in einem festen Schema alle z. B. 20ms nacheinander versendet und entsprechend am Empfänger zeitlich auch nacheinander ausgegeben. Die abfallende Flanke des PWM-Pulses des vorherigen Kanals und die aufsteigende Flanke des Pulses des nachfolgenden Kanals sind daher zeitlich sehr eng beieinander und wegen der veränderbaren Signallängen auch im Sendezyklus nicht festlegbar. Am ESP32 muss für jeden RC Kanal ein eigener GIO-Pin zur Messung der Pulslänge bereitgestellt werden. Die einzelnen Interrupts sind blockierend für Funktionen außerhalb der ISR (Interrupt Service Routine) und melden nur beim Auslösekriterium zurück.

Klick mich

Schematische Darstellung des PWMReceiver Konzeptes

Im ESP32 ist aber ein HW-Modul (RMT) integriert, das PWM Signale über die GIO-Pins lesen und schreiben kann. Dafür muss dem Modul erst mitgeteilt werden wo und was zu messen ist, die notwendigen ISR Ressourcen zugeordnet werden und die Rückgabe des Messergebnisses definiert sein. Für eine sequenzielle Abarbeitung über mehrere aufeinanderfolgende RC-Kanäle reicht die Zeitspanne zwischen PWM Signalende Kanal n und PWM-Signal Anfang Kanal n+1 nicht aus, wenn man aufeinanderfolgende Kanäle messen möchte. Daher muss für jeden zu messenden RC-Kanal ein RMT ISR Kanal allokiert und parallel für die nächste Messung scharf gemacht werden. Danach warten alle ISR Kanäle auf das Ende ihrer Messung und legen das Ergebnis ab. Mit jedem zu messenden Kanal sind wir also zwischen 0,9 und 2,1 Millisekunden in der blockierenden Interrupt-Routine, je nach Kreuzknüppelstellung der RC-Anlage. Bei der Auswertung von sagen wir mal 4 RC Kanälen summieren sich diese Signallängen auf 3,6 bis 8,4 ms, was knapp ein Viertel bis die Hälfte der gesamten zur Verfügung stehenden Zykluszeit von im Allgemeinen 20ms ist. Da signalmessen ja kein Selbstzweck ist und die restlichen SW-Funktionen auf dem ESP auch Laufzeit benötigen sollte man also immer einen Blick auf die Laufzeitreserve im Zyklus bei maximalen PWM Signallängen haben und möglichst nur aufeinanderfolgende RC Kanäle nutzen. Aus diesen grundlegenden Erwägungen ergibt sich der Ansatz des PWMReceiver mit seinen Funktionsblöcken ESP32 Ressourcen Zuordnung (im Setup) und dann in der Zyklusschleife:

  1. aktivieren der Messungen [ rmt ]
  2. warten auf Messergebnisse [ warten ]
  3. Messergebnisse lesen, auswerten, aufbereiten und zur Verfügung stellen [ messen + validieren ]

damit möglichst viel Microprozessor-Laufzeit im Zyklus am Stück für die Nutzung der ausgewerteten RC-Signale übrig bleibt, wie obiges Zyklusschema mit dem grün gefärbten Bereich zeigt.

Das Schema zeigt auch, daß die Laufzeitreserve nicht direkt gemessen werden kann, da Sie sich komplett in der Wartezeit der RMT-ISR Funktion versteckt und das System keine Info bereitstellt wann die erste Messung im Zyklus beginnt. Da aber das erste Messergebnis bekannt ist, kann auf den Punkt an dem die Interrupt Funktionen wieder aktiviert sein mussten zurückgerechnet werden. Aus dem selben Grund unterscheiden sich auch die Startpunkte des Zyklus des RC-Empfängers und der Zykluszeitmessung des PWMReceivers mit der entsprechenden Messungenauigkeitseinschränkung auf Basis der Kreuzknüppelbewegungen von einem Zyklus zum nächsten.

Umsetzung in Software

Auf meinem PC nutze ich die Arduino IDE mit der Erweiterung zur Unterstützung der ESP32 Mikrocontroller von ESPRESSIF für meine Projekte. Die Softwarefunktionen sind recht modular und flexibel gestaltet. Jede Funktionskomponente befindet sich in einer eigenen ino Datei, die über die Arduino IDE mitgeladen wird. Auch lassen sich viele Funktionalitäten über Konstanten im Definitionsbereich der Dateien konfigurieren. Ebenso befinden sich die Definitionen der für die Funktionen benötigten GPIO Pins in diesen Funktions-Dateien und müssen ggf. angepasst werden.

RCReceiver

In der RCReceiver.ino sind die für Arduino Projekte übliche setup und loop Funktionen enthalten. Im Setupbereich werden die Konfigurationen für die RC Kanalmessungen setup_PwmChannels() und für den MultiSwich setup_MultiSwitch() aufgerufen. Final wir noch der Task für den zweiten Prozessor des ESP32 über setup_Core0() definiert.

Klick mich

Ausgabe von Debugdaten bei Restart nach Fehler

In der Hauptschleife loop() wird über den Aufruf von runPwmReceiver() die RC PWM Messung koordiniert und die Hauptschleife so in die RC-Zykluszeit gezwungen. Wenn valide Messergebnisse vorliegen wird über run_MultiSwitch auf Statusänderungen des Multiswitch geprüft, andernfalls geht der Multiswitch in Failsafe bis sich die Dinge bessern.

Auf die Ergebnisse der PWM Auswertung kann über die Definitionen der RC Inputs in der RCReceiver.h zugegriffen werden. Ich habe mal RC Kanal 1 als globale Variable RC_Rudder definiert. Auf Kanal 2 liegt bei mir der MultiSwitch, der über die globale Variable RC_MultiSwitch ausgewertet wird. Auf die einzelnen Schalterstellungen kann über switchON[MS_FuncX] zugegriffen werden, wobei X für 1,2,3 oder 4 steht. RC Kanal 3 ist auch als globale Variable definiert (RC_Channel3), aber noch keiner Funktion zugeordnet und steht als Beispiel, wie bei Erweiterung der Kanalzahl zu verfahren ist. Als letzte globale Variable ist Kanal 4 als RC_Trottle hinterlegt. Alle Variablen sind Gleitkommazahlen im Wertebereich 1 bis -1 bei denen die Wertebereichsgrenzen den positiven und negativen Kreuzknüppelanschlag definieren. Die Kreuzknüppelruhestellung repräsentieren demzufolge den Wert 0.

Zurück in der RCReceiver.ino findet sich noch die TaskCore0() Funktion, die auf dem zweiten Prozessor unabhängig vom Laufzeitverhalten der loop abläuft. Hier können in der kontinuierlich laufenden for Schleife eigene Funktionen platziert werden. Bei meinem Solö Ruff Projekt lasse ich hier zum Beispiel Sensoren auswerten, ein kleines LCD Farbdisplay ansteuern und verschiedene Sounds ausgeben, die wiederum über den Multiswitch geschaltet werden. Funktionen, die im Laufzeitraster des RC-Zyklus durchlaufen werden sollen sind aber besser in der loop Funktion hinter den Multiswitch aufrufen plaziert. In meinem STRAWAP MVF 38 Renovierungsprojekt sind das zum Beispiel die Motoransteuerungen des DualDriver, eine RGB-LED und die Schaltfunktionen, die über den Multiswitch geschaltet werden. Bei der Entwicklung solcher Funktionen sollte man aber immer die Laufzeitreserve im RC-Zyklus im Blick behalten.

PWMReceiver

Die PWMReceiver.ino ist funktional der Dreh- und Angelpunkt dieses Projektes. Damit der Receiver weiß wie viele RC-Kanäle gemessen werden sollen und wie mit den Messergebnissen umgegangen werden soll muss er zuerst konfiguriert werden.

Konfiguration des PWMReceivers

Diese Konfiguration wird gleich am Anfang der ino Datei bei den Definitionen erledigt. Über pwm_channel_count muss die Anzahl der Kanäle und mit pwm_pins die Definition der dazugehörigen GPIO-Pins eingetragen werden.

Klick mich

Ausgabe von Debugdaten bei Kalibrierung

Die Feldvariablen pwm_min, _mid und _max müssen natürlich gleichviele Einträge wie die Anzahl zu messender RC-Kanäle haben. Diese Werte sind RC-System abhängig und können über die Nutzung der Debug Funktion mit CANNEL_CALIB ausgelesen und hier dann eingetragen werden. Sie stellen die Werte der Kreuzknüppelanschläge und der Kreuzknüppelneutralstellung dar und werden sowohl zu Signalaufbereitung als auch zur Signalüberwachung genutzt. Mit pwm_invert lässt sich jeder RC-Kanal invertieren und mit pwm_trim lässt sich festlegen ob für den RC-Kanal eine Feintrim Funktion berücksichtigt werden soll. Mit pwm_bound_min und _max sollten die spezifizierten Signalgrenzen des RC-Systems eingetragen werden. Sie sollten generell weiter gespannt sein als die Werte in pwm_min und _max weil darüber hart in den Failsafe geschaltet wird. Über BC_threshold[] wird die Anzahl von invaliden Signalzyklen definiert, bevor das System in failsafe geht. Der Schwellwert ist Kanal individuell gestaltet, damit für Schaltkanäle (und Multiswitches) längere Zyklen vorgegeben werden können als für Proportionalkanäle, da Schaltfunktionen meist weniger zeitkritisch sind. Wir reden bei der dargestellten Konfiguration also von 200 ms für den Multiswitch zu 100 ms für die restlichen RC-Kanäle. Final können mit RCcycleMin und RCcycleMax die Abschaltgrößen für die RC-Zyklusüberwachung verändert werden. Auch hier sollte es eine Anpassung an die realen Gegebenheiten geben.

Setup des PWMReceivers

Die ISR und RMT Ressourcenallokation findet in der setup_PwmChannels Funktion satt. Zuerst werden die Strukturen der Konfigurationen der "Messkanäle" (channel_cfg) und eines Messergebnisrückgabespeicherbereiches (receive_queue) definiert und in einer Schleif pro RC-Kanal dem GPIO-Pin und den RMT-Resourcen zugeordnet. Am Ende der Schleife werden die Interrupts für die ersten Messungen aktiviert (rmt_enable). Es braucht dabei nur einen Rückgabespeicherbereich, da die Ergebnisse ja sequenziell kommen und so immer derselbe Bereich genutzt werden kann. Wenn die CANNEL_CALIB Funktion aktiv ist wird noch über CheckCentre() auf Basis der konfigurierten pwm_min und _max Werte pro RC-Kanal der Mittelpunkt berechnet und gegen den eingetragenen Wert verglichen und das Ergebnis einmalig ausgegeben.

kontinuierliches messen ...

Über die Funktion runPWMReceiver() wird das kontinuierliche Auswerten der RC-Kanäle im RC-Zyklus koordiniert und bei Fehlern einen dazu passenden Status rückgemeldet. Dieser steckt am Ende in der globalen Variable validPWM, die nur wahr und falsch kennt. In der am Anfang der Funktion aufgerufenen Unterfunktion read_PwmChannels() wird mit den Messvorbereitungen gleich in einer Schleife über alle zu messenden RC-Kanäle (Anzahl in der schon bekannten pwm_channel_count) begonnen. Mit den Funktionsaufrufen rmt_rx_register_event_callbacks werden die RMT-Ressourcen (re)aktiviert und dann über rmt_receive der definierte Interrupt scharf geschaltet. Nun ist alles bereit zum messen der ersten Flanke des ersten zu messenden RC-Kanals. Hier ist auch der Zeitpunkt im RC-Zyklus an dem die Messung der Laufzeitreserve über das abspeichern des Zeitstempels in StartRead angestoßen wird. Es folgt in der read_PwmChannels() nun eine weitere Schleife über alle Kanäle in der auf die Auslösung der Interrupts (callback) über einen Aufruf von xQueueReceive gewartet wird. Ist dieser erfolgreich wird das Messergebnis in die Feldvariable pwmSigRaw[] für den entsprechenden Kanal geschrieben. Falls in der vorkonfigurierten Zeit kein callback erfolgt, wird die RMT-Ressource dieses Messkanales zur Fehlervermeidung im nächsten Zyklus über rmt_disable frei gegeben und über rmt_enable wieder re-aktiviert. Über pdMS_TO_TICKS() wird diese Wartezeit in Millisekunden auf einen erfogreichen callback definiert. Ich gebe dem System mit 100 ms somit 5 RC-Zyklen pro zu messenden RC-Kanal Zeit ein PWM-Signal zu erkennen. Diese Grösse kann angepasst werden, wenn das System schneller reagieren soll, da z.B. mehr Kanäle gemessen werden.
Damit sind die ISR-RMT Messungen für den aktuellen RC-Zyklus schon abgeschlossen, was mit setzen von pwmReadDone kommuniziert wird. Zu diesem Zeitpunkt findet auch die Zeitmessung für die RC-Zykluszeit RC_cycle statt. Es folgt nun noch die Validierung der Messergebnisse wieder über eine Schleife aller zu messenden RC-Kanäle. Die gültigen und normierten Messergebnisse werden über die Rückgabewerte des NormSignal() Funktionsaufrufes in die Feldvariable pwmRCin[] geschrieben. Wenn der Receiver im Kalibrierungsmodus ist werden hier auch noch die aktuellen Messwerte an den seriellen Monitor übergeben.

... und validieren des PWMReceiver

Die Messwertevalidierung besteht aus 3 Phasen. Zuerst wird in der ersten Schleife in NormSignal() geprüft, ob diese sich im Bereich zwischen den konfigurierten pwm_min und pwm_max Werten ihres RC-Kanals befinden. Ist dies der Fall wird auf den Wertebereich von -1 bis 1 genormt (unter Berücksichtigung der Invertierungsfunktion), der gültige Wert für zukünftige Rettungsmaßnahmen in lastPulseGood[] zwischengespeicher, die Fehlererkennungshysterese lastGood[] zurückgesetzt und die Funktion mit normierten Rückgabewert verlassen. So schnell kann das im fehlerfreien Normalfall gehen.

Wenn der Wert aber nicht zwischen den pwm_min und pwm_max Bereich ist wird in Phase 2 in der restlichen Funktion geprüft ob der aktuel zu validierende RC-Kanal über pwm_trim[] mit der Feintrim-Funktion konfiguriert ist und ob der Wert noch in den Grenzen des RC-Systems liegt (pwm_bound_min, pwm_bound_max). Falls das gültig ist werden die pwm_min[], pwm_mid[] und pwm_max[] um den Deltawert zum Anschlag verändert und der aktuelle Messwert über den Funktionsaufruf TrimSignal() auf 1 oder -1 normiert. Somit ist der Wert auch valide und kann wie in Phase 1 zurückgegeben werden.

Wenn der Messwert aber außerhalb der spezifizierten Werte liegt geht es in Phase 3 um reale Fehlerbehandlung. Da meine Modelbauprojekte nicht mit Lichtgeschwindigkeit unterwegs sind traue ich dem System zu, bei den ersten Fehlerwerten nicht sofort mit failsafe zu reagieren, sondern zuerst noch mit dem letzten gültigen Wert weiter zu arbeiten. Im else Zweig wird daher erstmal geprüft, ob die Anzahl der nacheinander folgenden RC-Zyklen mit fehlerlhaften PWM-Werten höher ist als der konfigurierte Schwellwert BC_threshold[]. Wenn das nicht der Fall ist wird über den Serielen Monitor die Rettung kommuniziert, der Fehlerzähler lastGood[] hochgezählt und er letzte gültige Messwert normiert und zurückgegeben.

Wird der Schwellwert BC_threshold[] allerdings überschritten ist alles zu spät und die NormSignal() gibt über einen positiven failed_now an die runPwmReceiver() den Fehlerstatus zurück. In der runPWMReceiver() wird die pwmReadDone grundsätzlich für den nächsten RC-Zyklus vorbereitet und wenn die Messwerte an sich valide waren die letzte Überprüfung über den RCpwmScattering() Funktionsaufruf angestoßen.

Klick mich

Ausgabe von Debugdaten bei Scattering

Bei alten analogen RC Systemen können große Signalsprünge von einem zum anderen RC-Zyklus vorkommen, die sich auch bei der Auswertung über einen ESP32 als sehr störend herausstellen können. Das kommt besonders bei Störungen auf der Funkstrecke, oder bei niedriger Senderspannung vor. Große Signalsprünge kommen natürlich auch bei schneller Bewegung der Kreuzknüppel des Senders vor, daher ist der Schwellwert th_scat zur Erkennung auf die eigenen Bedürfnisse anzupassen.

Die RCpwmScattering() Funktion läuft ab dem zweiten Durchlauf immer in den else Zweig, da der erste Durchlauf zur sprungfreien Erstellung der pwmLast[] Werte benötigt wird. Ab da wird das Messwertdelta zum letzten RC-Zyklus berechnet und mit dem th_ scat Schwellwert vergleicht und bei Überschreitung der Feldfehlerzähler RCpwmCount[] hoch gezählt. Auch hier wird ein konfigurierbarer Schwellwert SC_threshold[] genutzt um über ein positiven Rückgabewert den Fehlerstatus zu kommunizieren. Wenn kein zu hohes Delta vorliegt wird der Feldfehlerzähler RCpwmCount[] wieder bis auf 0 dekrementiert.

Schlußendlich wird auch noch geprüft ob es auf mehr als einem RC-Kanal hohe Deltas gibt, dann wird nach dem überschreiten des Schwellwert SC_chold der failsafe angestoßen.

Wenn es keine nichtkorrigierbaren Signalsprünge gab werden die nun für den laufenden RC-Zyklus gültigen Messwerte über die MapRCtoFunction() auf die global verfügbaren Variablen für die Weiterverwendung kopiert und es geht im Programmfluss zurück in die runPwmReciever().

Klick mich

Ausgabe von Debugdaten bei Restart nach Fehler

Dort steht nach der Prüfung der RC-Zykluszeit gegen die konfigurierbaren Schwellwerte RCcycleMin und RCcycleMax noch die Abarbeitung des Zustandsautomaten an, über den die Übergänge von einem Zustand zum anderen geregelt sind. Über die booleschen Variablen failed_before und failed_now wird geprüft ob das System gerade fehlerhaft geworden ist und/oder ob es davor fehlerhaft war. Je nach Situation werden dann der Fehlerzähler panic oder der Latenzzähler count_good hochgezählt, wobei im Fehlerfall bei panic < 0 sofort in den failsafe gegangen wird und die Schwelle 10 nur als Ausgabeminderer für langanhaltende Fehlersituationen steht (RC State: RC Lost in der DEBUG_SM Ausgabe). Beim Wieder Auf Start Latenzzähler count_good wird gegen den konfigurierbaren Schwellwert th_good geprüft und es werden zwei zusätzliche RC-Zyklen mit validen Messergebnissen benötigt (RC State: Wait und RC State: Start in der DEBUG_SM Ausgabe) bis das System wieder am Laufen ist (RC State: Run in der DEBUG_SM Ausgabe), wie auch in den Screenshots zu sehen ist.

Nach dem Durchlaufen des Zustandsautomaten kommen noch die Ausgabe der Zykluszeitmessung und der Laufzeitreserve im DEBUG_SM Fall. Um auch im Fehlerfall untypische failsafe Werte sicher im System zu verbreiten wird schlussendlich die MapRCtoFailsafe() aufgerufen, in der man diese platzieren kann.

Um das Konzept der funktionalen Konfiguration in der selben ino Dateien nicht zu durchbrechen ist auch noch die Kleinstfunktion getChAmmount() vorhanden, über die man die Anzahl der zu messenden RC-Kanäle abfragen und so in anderen Funktionen nutzen kann.

MultiSwitch Decoder

In der Multiswitch.ino haben sich die Funktionen für den Dekoder seit der ersten Implementierung für den Strawap recht wenig verändert. Wie auch dort verweise ich auf die ursprüngliche Umsetzung des Yet another Multi Switch - YaMS von Dirk Wiedemann.

Konfiguration und Kalibrierung des Multiswitch Decoders
Klick mich

Ausgabe von Debugdaten des Multischwicht

Klick mich

Schaltplan Multiswitch Encoder

Auch beim Multiswitch Decoder gilt es erst mal die Feldvariable MS_threshold an die eigenen Gegebenheiten des Multiswitch Encoders anzupassen und die generisch berechneten Schwellen in der Liste zu ersetzen. Nachdem die Kalibrierung des PWMReceivers erledigt ist, empfiehlt es sich alle DEBUG Definitionen in der PWMReceiver.ino zu deaktivieren und die DEBUG_MS in der Multiswitch.ino muss aktiviert werden.

Im Betrieb sollte man bei der kontinuierlichen Ausgabe zuerst mal nur auf die Werte von MSch: schauen und sich für alle 16 möglichen Schalterstellungen den stabilisierten, normierten Messwert notieren. Damit können dann die Schwellen in MS_threshold vom Wert genau mittig zwischen die gemessenen Werte der Schallterstellungen gelegt werden. Danach wird der Test mit der eigenen Konfiguration nochmals durchgeführt. Sind dabei nun auch die restlichen Ausgaben stimmig zu den Schalterstellungen kann die Kalibrierung als abgeschlossen angesehen werden.

Beim obigen Test wird aufgefallen sein, dass der Multiswitch Decoder etwas träge schaltet und über eine Hysterese die Übergänge koordiniert. Diese lässt sich mit dem Schwellwert MSswitchNow bei Bedarf anpassen. Anpassungen sind auch nötig, falls der Multiswitch direkt über GIO-Pins Schaltvorgänge vornehmen soll. Diese sind im Code hinterlegt, auskommentiert und müssten bei Bedarf für die realen Gegebenheiten bestückt werden.

Setup des Multiswitch Decoders

Wie obig erwähnt sind die GIO-Pin Zuweisungen auskommentiert, womit die setup_MultiSwitch() Funktion inhaltsleer ist, da es sonst nichts gibt, was beim Startup für den Decoder zu erledigen ist. Es sind über die Definition der globalen Feldvariable switchOn[] grundsätzlich beim Startup des ESP32 alle Schalter erstmal auf aus konfiguriert. Für eine failsafe Situation könnte das anders aussehen, daher gibt es die Funktion close_MultiSwitch() in der dies über alle 4 Schalter wieder erledigt wird.

kontinuierliches schalten ...

In der nach dem Startup kontinuirlich im RC-Zyklus laufende Funktion run_MultiSwitch() wird zuerst in einer For-Schleife dem genormten aktuellen Messwert des Multiswitch RC-Kanales einer der 16 möglichen Schalterzuständen zugeordnet (S_State). Dieser wird mit dem zwischengespeicherten Zustand des letzten Zyklus (last_state) verglichen. Eine Zustandsänderung wird über die If-Abfragen nur zugelassen, wenn die Hysterese über mehrere Zyklen hochzählen konnte und ihren Schwellwert MSswitchNow überschreitet, was bei der hinterlegten Schwellwertgrösse nach 0,4 Sekunden der Fall ist. Im restlichen Bereich der Funktion wird der Zustand ausgewertet und die Schalterstellungen in switchOn[] zugewiesen. Bei Bedarf kann dieser auch an konfigurierte GIO-Pins über die auskommentierten digitalWrite() Funktionsaufrufe weitergegeben werden.

Damit ist die run_MultiSwitch() durchlaufen und es geht in der Hauptschleife mit dem nächsten RC-Zyklus weiter.

Download:   RCReceiver_V01_2.zip (16Kbyte)