Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial Internet of Things >> Eingebettet

Lernen Sie die eingebettete Programmiersprache C:Das Union Data Object verstehen

Informationen zu Datenobjekten namens Unions in der eingebetteten Sprache C.

Erfahren Sie mehr über Datenobjekte, die Unions in der eingebetteten Sprache C genannt werden.

Der Unterschied zwischen Struktur und Vereinigung in eingebettetem C

In einem früheren Artikel dieser Serie haben wir besprochen, dass Strukturen in eingebettetem C es uns ermöglichen, Variablen unterschiedlicher Datentypen zu gruppieren und sie als einzelnes Datenobjekt zu behandeln.

Neben Strukturen unterstützt die Sprache C ein weiteres Datenkonstrukt, eine sogenannte Union, die verschiedene Datentypen als ein einzelnes Datenobjekt gruppieren kann. Dieser Artikel enthält einige grundlegende Informationen über Gewerkschaften. Wir werfen zuerst einen Blick auf ein einführendes Beispiel für die Deklaration einer Union, dann untersuchen wir eine wichtige Anwendung dieses Datenobjekts.

Einführendes Beispiel

Das Deklarieren einer Union ist ähnlich wie das Deklarieren einer Struktur. Wir müssen nur das Schlüsselwort „struct“ durch „union“ ersetzen. Betrachten Sie den folgenden Beispielcode:

Gewerkschaftstest { uint8_t c; uint32_t i;}; 

Dies gibt eine Vorlage an, die zwei Mitglieder hat:„c“, das ein Byte benötigt, und „i“, das vier Byte belegt.

Jetzt können wir eine Variable dieser Union-Vorlage erstellen:

Gewerkschaftstest u1; 

Mit dem Member-Operator (.) können wir auf die Member der Union „u1“ zugreifen. Der folgende Code weist beispielsweise dem zweiten Element der obigen Union 10 zu und kopiert den Wert von „c“ in die Variable „m“ (die vom Typ uint8_t sein muss).

u1.i=10;m=u1.c; 

Wie viel Speicherplatz wird zugewiesen, um die Variable „u1“ zu speichern? Während die Größe einer Struktur mindestens so groß ist wie die Summe der Größen ihrer Mitglieder, entspricht die Größe einer Union der Größe ihrer größten Variablen. Der einer Gewerkschaft zugewiesene Speicherplatz wird von allen Gewerkschaftsmitgliedern geteilt. Im obigen Beispiel ist die Größe von „u1“ gleich der Größe von uint32_t, also vier Bytes. Dieser Speicherplatz wird zwischen „i“ und „c“ geteilt. Wenn Sie also einem dieser beiden Elemente einen Wert zuweisen, ändert sich der Wert des anderen Elements.

Sie fragen sich vielleicht:"Was bringt es, denselben Speicherplatz zum Speichern mehrerer Variablen zu verwenden? Gibt es eine Anwendung für diese Funktion?" Wir werden dieses Problem im nächsten Abschnitt untersuchen.

Brauchen wir gemeinsam genutzten Speicherplatz?

Schauen wir uns ein Beispiel an, in dem eine Union ein nützliches Datenobjekt sein kann. Nehmen Sie an, dass, wie in Abbildung 1 unten gezeigt, zwei Geräte in Ihrem System vorhanden sind, die miteinander kommunizieren müssen.

Abbildung 1

„Gerät A“ sollte Status-, Geschwindigkeits- und Positionsinformationen an „Gerät B“ senden. Die Statusinformationen bestehen aus drei Variablen, die den Batterieladezustand, die Betriebsart und die Umgebungstemperatur anzeigen. Die Position wird durch zwei Variablen dargestellt, die die Positionen der x- und y-Achse anzeigen. Schließlich wird die Geschwindigkeit durch eine einzelne Variable repräsentiert. Nehmen Sie an, dass die Größe dieser Variablen der folgenden Tabelle entspricht.

Variablenname Größe (Byte) Erklärung
Kraft 1 Akkuladung
op_mode 1 Betriebsmodus
temp 1 Temperatur
x_pos 2 X-Position
y_pos 2 Y-Position
vel 2 Geschwindigkeit

Wenn „Device B“ ständig alle diese Informationen haben muss, können wir all diese Variablen in einer Struktur speichern und die Struktur an „Device B“ senden. Die Strukturgröße ist mindestens so groß wie die Summe der Größe dieser Variablen, d. h. neun Bytes.

Jedes Mal, wenn „Gerät A“ mit „Gerät B“ spricht, muss es daher einen 9-Byte-Datenrahmen über die Kommunikationsverbindung zwischen den beiden Geräten übertragen. Abbildung 2 zeigt die Struktur, die "Gerät A" verwendet, um die Variablen und den Datenrahmen zu speichern, der über die Kommunikationsverbindung gesendet werden muss.

Abbildung 2

Betrachten wir jedoch ein anderes Szenario, bei dem wir die Statusinformationen nur gelegentlich senden müssen. Angenommen, es ist nicht erforderlich, zu einem bestimmten Zeitpunkt sowohl Positions- als auch Geschwindigkeitsinformationen zu haben. Mit anderen Worten, manchmal senden wir nur Position, manchmal nur Geschwindigkeit und manchmal nur Statusinformationen. In dieser Situation scheint es keine gute Idee zu sein, die Informationen in einer Neun-Byte-Struktur zu speichern und über die Kommunikationsverbindung zu übertragen.

Statusinformationen können nur durch drei Bytes dargestellt werden; für Position und Geschwindigkeit benötigen wir nur vier bzw. zwei Bytes. Daher beträgt die maximale Anzahl von Bytes, die „Gerät A“ in einer Übertragung senden muss, vier, und folglich benötigen wir nur vier Byte Speicher, um diese Informationen zu speichern. Dieser 4-Byte-Speicherplatz wird von unseren drei Nachrichtentypen geteilt (siehe Abbildung 3).

Beachten Sie außerdem, dass die Länge des durch die Kommunikationsverbindung geleiteten Datenrahmens von neun Byte auf vier Byte reduziert wird.

Abbildung 3

Zusammenfassend:Wenn unser Programm Variablen hat, die sich gegenseitig ausschließen, können wir sie in einem gemeinsam genutzten Speicherbereich speichern, um wertvollen Speicherplatz zu erhalten. Dies kann insbesondere im Zusammenhang mit speicherbeschränkten eingebetteten Systemen wichtig sein. In solchen Fällen können wir Unions verwenden, um den erforderlichen gemeinsamen Speicherplatz zu schaffen.

Das obige Beispiel zeigt, dass uns die Verwendung einer Union zur Behandlung sich gegenseitig ausschließender Variablen auch dabei helfen kann, Kommunikationsbandbreite zu sparen. Die Einsparung von Kommunikationsbandbreite ist manchmal noch wichtiger als die Einsparung von Speicher.

Verwendung von Unions für Nachrichtenpakete

Sehen wir uns an, wie wir eine Union zum Speichern der Variablen des obigen Beispiels verwenden können. Wir hatten drei verschiedene Nachrichtentypen:Status, Position und Geschwindigkeit. Wir können eine Struktur für die Variablen der Status- und Positionsnachrichten erstellen (so dass die Variablen dieser Nachrichten als ein einziges Datenobjekt gruppiert und manipuliert werden).

Dazu dienen folgende Strukturen:

struct { uint8_t power; unit8_t op_mode; uint8_t temp;} status;struct { uint16_t x_pos; unit16_t y_pos;} Position; 

Jetzt können wir diese Strukturen zusammen mit der Variablen „vel“ in eine Union einfügen:

union {struct { uint8_t power; unit8_t op_mode; uint8_t temp;} status;struct { uint16_t x_pos; unit16_t y_pos;} Position; uint16_t vel;} msg_union; 

Der obige Code spezifiziert eine Union-Vorlage und erstellt eine Variable dieser Vorlage (mit dem Namen „msg_union“). Innerhalb dieser Union gibt es zwei Strukturen („status“ und „position“) und eine 2-Byte-Variable („vel“). Die Größe dieser Union entspricht der Größe ihres größten Mitglieds, nämlich der „Position“-Struktur, die vier Byte Speicher belegt. Dieser Speicherplatz wird von den Variablen „status“, „position“ und „vel“ geteilt.

So behalten Sie den Überblick über das aktive Mitglied der Union

Wir können den gemeinsamen Speicherplatz der obigen Union verwenden, um unsere Variablen zu speichern; Es bleibt jedoch eine Frage:Wie soll der Empfänger feststellen, welche Art von Nachricht gesendet wurde? Der Empfänger muss den Nachrichtentyp erkennen, um die empfangenen Informationen erfolgreich interpretieren zu können. Wenn wir beispielsweise eine „Position“-Nachricht senden, sind alle vier Bytes der empfangenen Daten wichtig, aber für eine „Geschwindigkeits“-Nachricht sollten nur zwei der empfangenen Bytes verwendet werden.

Um dieses Problem zu lösen, müssen wir unserer Union eine andere Variable zuordnen, sagen wir „msg_type“, die den Nachrichtentyp (oder das Unionsmitglied, in das zuletzt geschrieben wurde) angibt. Eine Gewerkschaft gepaart mit einem diskreten Wert, der das aktive Mitglied der Gewerkschaft angibt, wird als „diskriminierte Gewerkschaft“ oder „getaggte Gewerkschaft“ bezeichnet.

Bezüglich des Datentyps für die Variable „msg_type“ können wir den Aufzählungsdatentyp der Sprache C verwenden, um symbolische Konstanten zu erstellen. Wir verwenden jedoch ein Zeichen, um den Nachrichtentyp anzugeben, um die Dinge so einfach wie möglich zu halten:

struct { uint8_t msg_type;union {struct { uint8_t power; unit8_t op_mode; uint8_t temp;} status;struct { uint16_t x_pos; unit16_t y_pos;} Position; uint16_t vel;} msg_union;} Nachricht; 

Wir können drei mögliche Werte für die Variable „msg_type“ in Betracht ziehen:„s“ für eine „Status“-Nachricht, „p“ für eine „Position“-Nachricht und „v“ für eine „Geschwindigkeits“-Nachricht. Jetzt können wir die Struktur „message“ an „Device B“ senden und den Wert der Variablen „msg_type“ als Indikator für den Nachrichtentyp verwenden. Wenn der Wert des empfangenen „msg_type“ beispielsweise „p“ ist, weiß „Gerät B“, dass der gemeinsam genutzte Speicherplatz zwei 2-Byte-Variablen enthält.

Beachten Sie, dass wir dem über die Kommunikationsverbindung gesendeten Datenrahmen ein weiteres Byte hinzufügen müssen, da wir die Variable „msg_type“ übertragen müssen. Beachten Sie auch, dass der Empfänger bei dieser Lösung nicht im Voraus wissen muss, welche Art von Nachricht eingeht.

Die alternative Lösung:Dynamische Speicherzuweisung

Wir haben gesehen, dass Unions es uns ermöglichen, einen gemeinsam genutzten Speicherbereich zu deklarieren, um sowohl Speicherplatz als auch Kommunikationsbandbreite zu sparen. Es gibt jedoch eine andere Möglichkeit, sich gegenseitig ausschließende Variablen zu speichern, wie die im obigen Beispiel. Diese zweite Lösung verwendet eine dynamische Speicherzuweisung, um die Variablen jedes Nachrichtentyps zu speichern.

Auch hier benötigen wir eine Variable „msg_type“, um den Nachrichtentyp sowohl auf der Sender- als auch auf der Empfängerseite der Kommunikationsverbindung anzugeben. Wenn „Gerät A“ beispielsweise eine Positionsnachricht senden muss, wird „msg_type“ auf „p“ gesetzt und vier Byte Speicherplatz zum Speichern der Variablen „x_pos“ und „y_pos“ zugewiesen. Der Empfänger überprüft den Wert von „msg_type“ und erstellt abhängig von seinem Wert den entsprechenden Speicherplatz zum Speichern und Interpretieren des eingehenden Datenrahmens.

Die Verwendung von dynamischem Speicher kann in Bezug auf die Speichernutzung effizienter sein, da wir jedem Nachrichtentyp gerade genug Speicherplatz zuweisen. Dies war bei der gewerkschaftlichen Lösung nicht der Fall. Dort hatten wir vier Bytes Shared Memory, um alle drei Nachrichtentypen zu speichern, obwohl die Nachrichten „Status“ und „Geschwindigkeit“ nur drei bzw. zwei Bytes benötigten. Die dynamische Speicherzuweisung kann jedoch langsamer sein, und der Programmierer muss Code einschließen, der den zugewiesenen Speicher freigibt. Aus diesem Grund bevorzugen Programmierer normalerweise die Union-basierte Lösung.

Nächstes Thema:Bewerbungen von Gewerkschaften

Es scheint, dass der ursprüngliche Zweck von Unions darin bestand, einen gemeinsamen Speicherbereich für sich gegenseitig ausschließende Variablen zu schaffen. Unions werden jedoch auch häufig verwendet, um kleinere Teile von Daten aus einem größeren Datenobjekt zu extrahieren.

Der nächste Artikel in dieser Serie konzentriert sich auf diese Anwendung von Unions, die bei eingebetteten Anwendungen besonders wichtig sein kann.

Um eine vollständige Liste meiner Artikel zu sehen, besuchen Sie bitte diese Seite.


Eingebettet

  1. Die beste Programmiersprache für industrielle Internet-of-Things-Anwendungen
  2. Mikroprozessorprogrammierung
  3. Was mache ich mit den Daten?!
  4. Demokratisierung des IoT
  5. 9 neue Programmiersprachen zum Erlernen im Jahr 2021
  6. C - Gewerkschaften
  7. Die Zukunft der Rechenzentren
  8. Die Cloud im IoT
  9. Kommentar:Die Methoden der Roboterprogrammierung verstehen
  10. Die gleiche industrielle Sprache sprechen:Die gängigen Maßeinheiten eines Kompressors verstehen