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

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

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

![table_union_example.png](https://qiita-image-store.s3.amazonaws.com/0/234220/e3bbd635-fb3e-1934-484b-c336cc789848.png)

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

```c++: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  |

```C++
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には共用体がないので，同じようなことをしたい場合は次のようにすると構造体のメンバはメモリが共有される．

```c#: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;
    }
```

```VB: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
```

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

```C#: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(): 大文字小文字の判別なしで，文字列が一致しているか判定します．

```c++: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埋め
```

#参考文献
- 共用体その２
 - http://www.geocities.co.jp/SiliconValley-Bay/7437/c/union2.htm
- dobon.net 16進数、8進数、2進数の文字列を整数に変換する　整数を16進数、8進数、2進数の文字列に変換する
 - https://dobon.net/vb/dotnet/programing/converthex.html
- Microsoft Documentation .Net
 - https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized.bitvector32?redirectedfrom=MSDN&view=netframework-4.7.2
- atmarkit 数値を右詰めや0埋めで文字列化するには？［C#、VB］
 - http://www.atmarkit.co.jp/ait/articles/0401/30/news069.html