Help us understand the problem. What is going on with this article?

組み込みで知っていると便利な表現集

組み込み系で知っていると便利,または自分がよく使う表現をまとめます.

共用体を使ったレジスタ表現

デバイスとシリアル通信する際は1バイトが基本で,例えばDWORDのような4バイトのデータを送信する際には1バイトずつに分割して送信します.また,受信する際には1バイトずつ送られてくるので,4バイトの型にまとめる必要があります.
その時に便利なのが共用体です.共用体のメンバはメモリを共有しているので,送信したいデータをDWORD型の変数に代入してから,送信するデータ配列の中に共用体内のバイト型の変数を使って格納していきます.

table_union_example.png

共用体を使うと,この表のようにメモリが共有されます.

REGS.h
#include <windows.h>

union _REGS{
  struct XREGS{
    BYTE b0;
    BYTE b1;
    BYTE b2;
    BYTE b3;
  }x;
  struct HREGS{
    USHORT al;
    USHORT ah;
  }h;
  int value;
};

さらに細かく区切りたい場合はビットフィールドを使います.
例えばレジスタの配置が下のような場合,ビットの配置とメンバの容量を対応させるにはビットフィールドを使うと各メンバが何ビットの容量を使うか指定することができます.

15 14 13 12 11 10 9 8
0 0 0 0 0 0 0 function1
7 6 5 4 3 2 1 0
0 0 ch ch 0 mode1 mode1 mode1
union _REGS {
  WORD wData;
  struct _SEL {
   WORD Mode1         : 3; // モード選択
   WORD Dmy1          : 1; // 予約(0)
   WORD SelectCh      : 2; // チャンネル選択
   WORD Dmy2          : 2; // 予約(0)
   WORD Function1     : 1; // 機能ON/OFF設定
   WORD Dmy3          : 7; // 予約(0)
  }bf;
};

C#やVBには共用体がないので,同じようなことをしたい場合は次のようにすると構造体のメンバはメモリが共有される.

sample.cs
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit)]
    public struct SignedInt32{
        [FieldOffset(0)] public uint value;

        [FieldOffset(0)] public ushort al;
        [FieldOffset(2)] public ushort ah;

        [FieldOffset(0)] public byte b0;
        [FieldOffset(1)] public byte b1;
        [FieldOffset(2)] public byte b2;
        [FieldOffset(3)] public byte b3;
    }
sample.vb
Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Explicit)>
Public Structure SignedInt32
    <FieldOffset(0)> Public value As UInteger

    <FieldOffset(0)> Public al As UShort
    <FieldOffset(2)> Public ah As UShort

    <FieldOffset(0)> Public b0 As Byte
    <FieldOffset(1)> Public b1 As Byte
    <FieldOffset(2)> Public b2 As Byte
    <FieldOffset(3)> Public b3 As Byte
End Structure

ビットフィールドを使う場合は

BitField_Sample.cs
using System.Collections.Specialized;

    public struct _Sel {
   public int  Mode1;     // モード選択
   public int  Dmy1;      // 予約(0)
   public int  SelectCh;  // チャンネル選択
   public int  Dmy2;      // 予約(0)
   public int  Function1; // 機能ON/OFF設定
   public int  Dmy3;      // 予約(0)
  }


//()内の数値はその区間が使用するビット数
//二つ目以降はビット数とそのセクションが始まる直前のセクションを書く

  public static BitVector32.Section Mode1     = BitVector32.CreateSection(5);
  public static BitVector32.Section Dmy1      = BitVector32.CreateSection(1, Mode1); 
  public static BitVector32.Section SelectCh  = BitVector32.CreateSection(3, Dmy1);  
  public static BitVector32.Section Dmy2      = BitVector32.CreateSection(1, SelectCh);
  public static BitVector32.Section Function1 = BitVector32.CreateSection(1,Dmy3);
  public static BitVector32.Section Dmy3      = BitVector32.CreateSection(7,Fuction1);

// ビットフィールドに構造体をセットする場合

public void SetConfig(ref _Sel sel){
  BitVector32 bv = new BitVector32();

  bv[Mode1]     = sel.Mode1;
  bv[SelectCh]  = sel.SelectCh;
  bv[Function1] = sel.Function1;

  WriteDevice(bv.Data);
}

// ビットフィールドから構造体へセットする場合

public void GetConfig(ref _Sel sel)
{
  int data = 0;
  ReadDevice(ref data);

//インスタンスを作るときに数値を入れるとそのビットフィールドが持つ数値を設定できる.
//bv.Dataのアクセサはgetだけなのでインスタンス生成時に引数として入れる必要がある

  BitVector32 bv = new BitVector32(data);

 sel.Mode1     = bv[Mode1];
  sel.SelectCh  = bv[SelectCh];
  sel.Function1 = bv[Function1];
}

コマンドを入力して操作する

簡単なプログラムで動作確認をする場合,コマンドを入力して操作ができるようにするとチェックがしやすくなります.

  1. get_s(): コンソール画面の文字列を取得します.
  2. _stricmp(): 大文字小文字の判別なしで,文字列が一致しているか判定します.
sample.cpp
system("pause");

while(1){
// キー入力
  gets_s(szkey);

  // キーと関数の対応を表示する
  if (_stricmp(szkey, "h") == 0) {
    DisplayFuncKey();
  }
  // ステータスを表示する
  else if (_stricmp(szkey, "sts") == 0) {
    DisplayStatus();
  }
  // プログラム終了
  else if (_stricmp(szkey, "end") == 0) {
    break;
  }
  // 無効なコマンド
  else {
    printf("無効なコマンドです.\n");
  }

  Sleep(1);
}

文字列を16進数に変換する場合,または16進数表記で文字列を書く

文字列→16進数

int num16 = Convert.ToInt32("0xFFFF", 16);
int num16 = int.Parse("FFFF", System.Globalization.NumberStyles.HexNumber);

Convertの時には0xを付けた表記でもOKだが,int.Parseの場合はできない.

数値→16進数表記

int num = 65535;
string str = Convert.ToString(num, 16);
string str = num.ToString("X");

桁数を指定する場合は,

string str = num.ToString("0:X8");//8桁0埋め

参考文献

Shons_a
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away