RTOS Over UART-Protokoll

Ich entwickle ein UART-Protokoll, um die Kommunikation zwischen zwei Boards (Master-Board und Slave-Board) sicherzustellen. Das Slave-Board enthält viele Sensoren und Aktoren und das Master-Board soll dieses Board durch eine Reihe von Befehlen wie GET_SENSOR_VALUEund SET_MOTOR_SPEEDusw. steuern ... Viele Funktionen sollen in meinem Projekt ausgeführt werden und eine permanente Kontrolle der Sensorwerte soll erfolgen (Beispiel: Master-Board soll erhalten Temperaturwert alle 5 Sekunden, es soll den Batteriestand alle 5 Sekunden abrufen, es soll die Belüftung aktivieren, wenn die Temperatur hoch ist ...). Alle Geräte sind mit der Slave-Platine (Sensoren und Aktoren) verbunden und die Hauptaufgabe der Master-Platine ist die Überwachung.

Ich habe einige Artikel über Spezifikationen und das Design eingebetteter Systeme gelesen und festgestellt, dass das erste, was Sie tun müssen, bevor Sie beginnen, den Kernel auszuwählen: RTOS oder GPOS (Bare Metal).

Meine Frage ist: Sollte ich in meinem Fall, wenn ich RTOS (im Masterboard) wähle, meine Anforderungen als separate Aufgaben/Funktionen implementieren?

  • temperature_task
  • Feuchtigkeitsaufgabe
  • Batterie_Aufgabe
  • motor_task
  • Belüftungsaufgabe

Wenn ja, unterstützt UART die Hochgeschwindigkeits-Kontextumschaltzeit? Beispiel:

00:00 temperature_task : GET_TEMPERATUREif temp>threshhold send START_VENTILATION
00:01 battery_task: GET_LEVELif level <threshhold send 00 TURN_OFF_SYSTEM
:02feuchtigkeitsaufgabe: GET_HUMIDITYif level <threshhold send DO_SOMETHING
00:03 temperature_task : GET_TEMPERATUREif temp>threshhold send START_VENTILATION
00:04 battery_task: GET_LEVELif level <threshhold send TURN_OFF_SYSTEM
00:05 feuchtigkeitsaufgabe: GET_HUMIDITYwenn level <threshhold sendDO_SOMETHING

es hängt davon ab ... Sie können alle Daten von verschiedenen Aufgaben abrufen, aber dann müssen Sie die Verwendung des UART auf irgendeine Weise blockieren, wenn eine andere Aufgabe die UART-Hardware verwendet (z. B. Mutex) ... ich würde es tun in die gleiche Aufgabe, wenn alle Daten separat abgerufen werden müssen, dann würde ich eine Zustandsmaschine implementieren .... über die Kontextumschaltung würde ich je nach Mikrocontroller entweder DMA zum Senden und Empfangen von Daten verwenden oder Unterbrechungen während der kurzen Zeit blockieren Rahmen es bekommt Daten ... Ich würde am Ende DMA verwenden, es ist viel einfacher
Beachten Sie, dass viele triviale Threads RAM mit einem eindeutigen Stack und Tracking-Daten für jeden verbrauchen. Wenn Sie nicht inkompatible Operationen auf einer kleineren Anzahl von Threads ausführen können, entweder durch einen leichteren Arbeitseinheitsmechanismus oder indem Sie sie selbst aneinanderreihen, sparen Sie sich das – haben Sie beispielsweise nur einen Ausführungsthread für alle Sensoren. Außerdem müssen Sie den UART so ziemlich einem Thread geben, der den Zugriff vermittelt. Andernfalls wird die Zeit, die zum Senden oder Empfangen benötigt wird, entweder ein fast unlösbares Durcheinander der Konsistenz verursachen oder dazu führen, dass Sie beim Warten auf Mutexe langsamer werden.
Sie begründen nicht die Notwendigkeit eines RTOS - ich würde angesichts Ihrer Problemstellung darauf verzichten. Wenn es nur aus Freude daran ist, dann gehen Sie auf jeden Fall, aber Ihre Frage sollte eine gewisse Begründung enthalten. Dies wird Ihnen helfen, Ihre eigentliche Frage nach Aufgaben und der Trennung von Anliegen zu verfeinern.

Antworten (2)

Ja, es ist im Allgemeinen eine GROSSE Idee, die Funktionalität auf diese Weise zu trennen, wenn ein RTOS im System ist. Es muss große Sorgfalt darauf verwendet werden, den gegenseitigen Ausschluss zwischen Aufgaben und gemeinsam genutzten Ressourcen wie gemeinsamem Speicher oder Peripheriegeräten sicherzustellen, um Wettlaufbedingungen und unvorhersehbares Verhalten zu vermeiden. Ein üblicher Ansatz für dieses Problem besteht darin, jedes Peripheriegerät hinter einer "Gatekeeper"-Aufgabe zu blockieren, die den ein- und ausgehenden Datenfluss verwaltet und typischerweise eine Rückruffunktion an den Anrufer ausgibt, wenn die erwarteten Daten empfangen wurden. Lesen Sie diesen Artikel (Kapitel 7 geht speziell darauf ein) aus der FreeRTOS-Dokumentation. Abgesehen davon kann der Bare-Metal-Ansatz vollkommen ausreichend sein, während eine engere Kopplung zwischen funktionalen Softwaremodulen besteht.

Wenn Sie eine gemeinsam genutzte Schnittstelle sperren müssen, um eine widersprüchliche Nutzung durch verschiedene Aufgaben zu vermeiden, welchen Nutzen haben Sie dann tatsächlich, wenn Sie für jede Sensoraufgabe einen separaten Stack bezahlen? Sie fügen nur eine Menge Overhead hinzu, um die serielle Ausführung neu zu erstellen, nur mit mehr Komplexität und weniger Determinismus. Aufgaben sind sinnvoll, wenn Sie einen komplexen laufenden Betrieb haben, der andere nur selten stört; und wenn Sie es nicht ohne weiteres als ereignisgesteuerte Zustandsmaschine umgestalten können.
Einverstanden, Sie sollten immer in der Lage sein, die Softwarekomplexität an die Anwendung anzupassen und immer die erste Wahl zu sein, aber wenn (unvermeidlich) neue Funktionen hinzugefügt oder das Verhalten geändert werden müssen, bietet sich der separate Task-Ansatz für ein modulareres Design an und schnelle Entwicklung. Aber Sie haben Recht damit, dass eine Menge Overhead eingeführt wird, um deterministisches Verhalten sicherzustellen.

Normalerweise ist UART bidirektional (RX + TX-Draht), sodass Sie senden/empfangen können, ohne umschalten zu müssen.

Ich habe keine (Arduino-)Erfahrung mit RTOS, aber das Aufteilen von Funktionalität in Funktionen ist immer eine gute Sache. In diesem vernünftig einfachen Fall benötigen Sie keine Tasks oder ein RTOS. Dies erschwert vor allem den UART-Zugriff und die notwendige gemeinsame Nutzung von Daten zwischen Tasks.

Zu Ihren "Timing" -Anforderungen: Eine Sekunde ist eine enorme Zeit, selbst für einen einfachen Mikrocontroller wie einen Arduino. Sie können wahrscheinlich beide Bare-Metal-Arduinos verwenden (es sei denn, Sie planen, komplizierte Berechnungen/Schemata zu verwenden), vorausgesetzt, Sie können alle Sensoren an einem Arduino (oder Mega?) Anbringen.

Wenn Sie dies fest machen (z. B. immer 20 Byte für die Aufnahme aller Sensorwerte), benötigen Sie kein Newline/Ende-of-Message-Byte.

Zum Protokoll: warum nicht alle x ms alle Daten von allen Sensoren als ein Paket an die Steuerung senden (Slave to Master). Und der Master kann bei Bedarf (on the fly für niedrige Latenz) kurze Nachrichten wie „System ausschalten“ oder bestimmte Befehle (einschließlich Parameter) senden.

Beispiel für Befehle vom Slave zum Master:

Byte   Meaning
0      Temp sensor
1      Humidity level
2      Battery level (?)
3      ... other sensors

Beispiel für Befehle vom Master:

Byte 0    Byte 1
Command   Parameter    Meaning
  0         n.a.      Turn off system 
  1         n.a.      Turn on system
  2         0-255     Move servo to loc x (as example)

usw.

Aufgaben unterscheiden sich stark von Funktionen. Funktionen kosten so gut wie nichts, weil der Compiler dort einbinden kann, wo es Sinn macht. Im Gegensatz dazu sind Tasks speicherintensiv - typischerweise sind sie unabhängige Threads, die jeweils ihren eigenen Stack benötigen, manchmal sogar größer als ein Thread, der mit einem "Prozess" eines Desktop-Betriebssystems vergleichbar ist.
Abgesehen von diesem Fehler scheint dies die gestellte Frage überhaupt nicht zu beantworten.
@ChrisStratton Ich habe nicht über Aufgaben gesprochen, sondern über Funktionen. Ich werde meine Antwort jedoch ändern, um sie klarer zu machen. Ich denke, es beantwortet die Frage zumindest teilweise (welches Protokoll verwendet werden könnte), dies ist für Aufgaben unabhängig (eine Aufgabe genügt).