工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial Internet of Things >> 埋め込み

組み込みCプログラミング言語を学ぶ:Unionデータオブジェクトを理解する

埋め込みC言語のユニオンと呼ばれるデータオブジェクトについて学習します。

埋め込みC言語のユニオンと呼ばれるデータオブジェクトについて学びます。

組み込みCの構造体と共用体の違い

このシリーズの前回の記事では、埋め込みCの構造により、さまざまなデータ型の変数をグループ化し、それらを単一のデータオブジェクトとして処理できることを説明しました。

構造に加えて、C言語は、さまざまなデータ型を単一のデータオブジェクトとしてグループ化できるユニオンと呼ばれる別のデータ構造をサポートします。この記事では、組合に関するいくつかの基本的な情報を提供します。まず、ユニオンを宣言する導入例を見てから、このデータオブジェクトの重要なアプリケーションを調べます。

導入例

和集合を宣言することは、構造体を宣言することによく似ています。キーワード「struct」を「union」に置き換えるだけです。次のサンプルコードについて考えてみます。

 ユニオンテスト{uint8_tc; uint32_t i;};  

これは、1バイトを占める「c」と4バイトを占める「i」の2つのメンバーを持つテンプレートを指定します。

これで、このユニオンテンプレートの変数を作成できます:

  union test u1;  

メンバー演算子(。)を使用して、「u1」ユニオンのメンバーにアクセスできます。たとえば、次のコードは、上記のユニオンの2番目のメンバーに10を割り当て、「c」の値を「m」変数(uint8_t型である必要があります)にコピーします。

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

「u1」変数を格納するためにどのくらいのメモリスペースが割り当てられますか?構造体のサイズは少なくともそのメンバーのサイズの合計と同じ大きさですが、共用体のサイズはその最大変数のサイズと同じです。ユニオンに割り当てられたメモリスペースは、すべてのユニオンメンバー間で共有されます。上記の例では、「u1」のサイズはuint32_tのサイズ、つまり4バイトに等しくなります。このメモリ空間は「i」と「c」の間で共有されます。したがって、これら2つのメンバーの一方に値を割り当てると、もう一方のメンバーの値が変更されます。

「同じメモリスペースを使用して複数の変数を格納することのポイントは何ですか?この機能のアプリケーションはありますか?」と疑問に思われるかもしれません。この問題については、次のセクションで説明します。

共有メモリスペースが必要ですか?

ユニオンが有用なデータオブジェクトになり得る例を見てみましょう。以下の図1に示すように、システム内に相互に通信する必要のある2つのデバイスがあると想定します。

図1

「デバイスA」は、ステータス、速度、および位置情報を「デバイスB」に送信する必要があります。ステータス情報は、バッテリーの充電量、動作モード、および周囲温度を示す3つの変数で構成されます。位置は、x軸とy軸の位置を示す2つの変数で表されます。最後に、速度は単一の変数で表されます。これらの変数のサイズが次の表に示すとおりであると想定します。

変数名 サイズ(バイト) 説明
パワー 1 バッテリー充電
op_mode 1 操作モード
temp 1 温度
x_pos 2 X位置
y_pos 2 Y位置
vel 2 速度

「デバイスB」が常にこの情報のすべてを保持する必要がある場合は、これらすべての変数を構造に格納して、構造を「デバイスB」に送信できます。構造体のサイズは、少なくともこれらの変数のサイズの合計と同じ大きさ、つまり9バイトになります。

したがって、「デバイスA」が「デバイスB」と通信するたびに、2つのデバイス間の通信リンクを介して9バイトのデータフレームを転送する必要があります。図2は、「デバイスA」が通信リンクを通過する必要のある変数とデータフレームを格納するために使用する構造を示しています。

図2

ただし、ステータス情報を送信する必要があるのはたまにしかない別のシナリオを考えてみましょう。また、特定の時間に位置と速度の両方の情報を持っている必要はないとします。つまり、位置のみを送信する場合もあれば、速度のみを送信する場合もあり、ステータス情報のみを送信する場合もあります。この状況では、情報を9バイト構造で保存し、通信リンクを介して転送することはお勧めできません。

ステータス情報は3バイトのみで表すことができます。位置と速度については、それぞれ4バイトと2バイトしか必要ありません。したがって、「デバイスA」が1回の転送で送信する必要がある最大バイト数は4であり、したがって、この情報を格納するために必要なメモリは4バイトだけです。この4バイトのメモリスペースは、3つのメッセージタイプ間で共有されます(図3を参照)。

さらに、通信リンクを通過するデータフレームの長さが9バイトから4バイトに短縮されていることに注意してください。

図3

要約すると、プログラムに相互に排他的な変数がある場合、それらをメモリの共有領域に格納して、貴重なメモリスペースを保持できます。これは、特にメモリに制約のある組み込みシステムのコンテキストで重要になる可能性があります。このような場合、ユニオンを使用して必要な共有メモリスペースを作成できます。

上記の例は、ユニオンを使用して相互に排他的な変数を処理することも、通信帯域幅の節約に役立つことを示しています。通信帯域幅の節約は、メモリの節約よりも重要な場合があります。

メッセージパケットにユニオンを使用する

上記の例の変数を格納するためにユニオンを使用する方法を見てみましょう。ステータス、位置、速度の3つの異なるメッセージタイプがありました。ステータスメッセージと位置メッセージの変数の構造を作成できます(これらのメッセージの変数がグループ化され、単一のデータオブジェクトとして操作されるようにします)。

次の構造がこの目的に役立ちます:

  struct {uint8_t power; unit8_t op_mode; uint8_t temp;} status; struct {uint16_t x_pos; unit16_ty_pos;}位置;  

これで、これらの構造体を「vel」変数と一緒にユニオンに入れることができます。

  union {struct {uint8_t power; unit8_t op_mode; uint8_t temp;} status; struct {uint16_t x_pos; unit16_ty_pos;}位置; uint16_t vel;} msg_union;  

上記のコードは、ユニオンテンプレートを指定し、このテンプレートの変数(「msg_union」という名前)を作成します。このユニオン内には、2つの構造(「status」と「position」)と2バイトの変数(「vel」)があります。このユニオンのサイズは、最大のメンバーのサイズ、つまり4バイトのメモリを占有する「位置」構造に等しくなります。このメモリスペースは、「status」、「position」、および「vel」変数間で共有されます。

ユニオンアクティブメンバーを追跡する方法

上記のユニオンの共有メモリスペースを使用して、変数を格納できます。ただし、1つの質問が残っています。受信者は、送信されたメッセージのタイプをどのように判断する必要がありますか。受信者は、受信した情報を正常に解釈できるように、メッセージタイプを認識する必要があります。たとえば、「位置」メッセージを送信する場合、受信したデータの4バイトすべてが重要ですが、「速度」メッセージの場合、受信したバイトのうち2バイトのみを使用する必要があります。

この問題を解決するには、ユニオンを、メッセージタイプ(または最後に書き込まれたユニオンメンバー)を示す別の変数「msg_type」に関連付ける必要があります。ユニオンのアクティブなメンバーを示す離散値とペアになっているユニオンは、「識別されたユニオン」または「タグ付きユニオン」と呼ばれます。

「msg_type」変数のデータ型に関しては、C言語の列挙型データ型を使用してシンボリック定数を作成できます。ただし、できるだけ単純にするために、文字を使用してメッセージタイプを指定します。

  struct {uint8_t msg_type; union {struct {uint8_t power; unit8_t op_mode; uint8_t temp;} status; struct {uint16_t x_pos; unit16_ty_pos;}位置; uint16_t vel;} msg_union;}メッセージ;  

「msg_type」変数には、「ステータス」メッセージの「s」、「位置」メッセージの「p」、「速度」メッセージの「v」の3つの可能な値を考慮することができます。これで、「message」構造を「Device B」に送信し、「msg_type」変数の値をメッセージタイプのインジケーターとして使用できます。たとえば、受信した「msg_type」の値が「p」の場合、「デバイスB」は、共有メモリスペースに2つの2バイト変数が含まれていることを認識します。

「msg_type」変数を転送する必要があるため、通信リンクを介して送信されるデータフレームに別のバイトを追加する必要があることに注意してください。また、このソリューションでは、受信者はどのような種類のメッセージが着信しているかを事前に知る必要がないことにも注意してください。

代替ソリューション:動的メモリ割り当て

ユニオンを使用すると、共有メモリ領域を宣言して、メモリスペースと通信帯域幅の両方を節約できることがわかりました。ただし、上記の例のように、相互に排他的な変数を格納する別の方法があります。この2番目のソリューションは、動的メモリ割り当てを使用して、各メッセージタイプの変数を格納します。

繰り返しになりますが、通信リンクの送信側と受信側の両方でメッセージタイプを指定するには、変数「msg_type」が必要です。たとえば、「デバイスA」が位置メッセージを送信する必要がある場合、「msg_type」を「p」に設定し、「x_pos」および「y_pos」変数を格納するために4バイトのメモリスペースを割り当てます。受信者は「msg_type」の値をチェックし、その値に応じて、着信データフレームを保存および解釈するための適切なメモリスペースを作成します。

動的メモリの使用は、メッセージタイプごとに十分なスペースを割り当てるため、メモリ使用量の点でより効率的になります。これは、ユニオンベースのソリューションには当てはまりませんでした。そこでは、3つのメッセージタイプすべてを格納するために4バイトの共有メモリがありましたが、「ステータス」メッセージと「速度」メッセージには、それぞれ3バイトと2バイトしか必要ありませんでした。ただし、動的メモリ割り当ては遅くなる可能性があり、プログラマーは割り当てられたメモリを解放するコードを含める必要があります。そのため、プログラマーは通常、ユニオンベースのソリューションを使用することを好みます。

次へ:ユニオンのアプリケーション

ユニオンの本来の目的は、相互に排他的な変数用の共有メモリ領域を作成することだったようです。ただし、ユニオンは、大きなデータオブジェクトからデータの小さな部分を抽出するためにも広く使用されています。

このシリーズの次の記事では、このユニオンのアプリケーションに焦点を当てます。これは、組み込みアプリケーションで特に重要になる可能性があります。

私の記事の完全なリストを表示するには、このページにアクセスしてください。


埋め込み

  1. 産業用モノのインターネットアプリケーションに最適なプログラミング言語
  2. マイクロプロセッサプログラミング
  3. 組み込みシステムプログラミングとその言語とは
  4. データをどうすればいいですか?!
  5. IoTの民主化
  6. 2021年に学ぶべき9つの新しいプログラミング言語
  7. C - 組合
  8. データセンターの未来
  9. IoTのクラウド
  10. コメント:ロボットプログラミングの方法を理解する
  11. 同じ産業言語を話す:コンプレッサーの一般的な測定単位を理解する