CODESYSの共用体とビット指定

# はじめに
仕事でCODESYSを使うことになったので気づいたことのメモです。
MELSEC等の従来からあるPLCなら簡単なのですが、IEC61131-3準拠のCODESYSとかだとビット操作などが結構めんどいです。
(まあラダーも絶望的に書きづらいのでSTで書けという戦略なのでしょうか…MELSECがラダーをポコポコ書きやすすぎるという気もしますが)
ちなみにIEC61131-3は呼びにくい名前ですが「イレブンサーティワン」という呼び方もあるそうです。最近知りました。CODESYSがなんぞや見たいな説明はしません。もっと良い解説ページがあると思うから。
(めんどくさがりの言い訳)

ちなみにこれはCODESYSとOMRONのNX-EIC202(EtherNet/IP)と通信してる動画です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">CODESYS(Orange Pi R1 Plus LTSで実行)でEthernetIP使い方調べてたら夜になった。 <a href="https://t.co/SsbBw2f9MU">pic.twitter.com/SsbBw2f9MU</a></p>&mdash; よしのぶ (@fa_yoshinobu) <a href="https://twitter.com/fa_yoshinobu/status/1699090360847249765?ref_src=twsrc%5Etfw">September 5, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Orange Pi R1 Plus LTSという5000円くらいのSingle Board Computerです。
OSはArmbianを使用しています。

https://qiita.com/fa_yoshinobu/items/6b86ea0fe1bf7d506eba

https://qiita.com/fa_yoshinobu/items/bbdbdbaf8aca49f48e16

# 共用体(UNION)
ビット操作をしたい、こういう場合に使うのは共用体(UNION)です。共用体についての詳しい説明については省きますが、
要するに同じメモリ領域を2重で定義してWORDでアクセスしたりBITでアクセスしたりというものです。
MELSECだと[SET M0]だとBITで指定、[MOV K1 K4M0]だと桁指定でWORDで簡単にアクセスできるから楽なんですがねぇ～　はぁ…

## 失敗例
まずは失敗例です。なにが駄目なのか考えようのコーナー！
```plaintext
TYPE union_BIT16:
UNION
    nBit : ARRAY[0..15] OF BOOL;
    nByte : ARRAY[0..1] OF BYTE;
    nWord : ARRAY[0..0] OF WORD;
END_UNION
END_TYPE
```

```plaintext
TYPE union_BIT32:
UNION
    nBit : ARRAY[0..31] OF BOOL;
    nByte : ARRAY[0..3] OF BYTE;
    nWord : ARRAY[0..1] OF WORD;
	nDword : ARRAY[0..0] OF DWORD;
END_UNION
END_TYPE
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/b880e33d-48e3-34d1-a03f-b6ecde862059.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/96692afa-31f4-bd5f-7c6e-a983133f7bed.png)

data1はunion_BIT16として、data2はunion_BIT32としてグローバル変数として定義。

union_BIT32はこいういイメージですねDWORDの1つの箱をDWORD,WORD,BYTE,BITで好きなように配列としてアクセスしようとする計画です。では動かしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/18a0b7af-e2ff-c69d-47fa-b1d8bfe15cb0.png)

nBit[0] オレンジ を TRUEにすると、nByte[0]が1に、 nBit[1] 緑 を TRUEにすると、nByte[1]が1に…
おかしいですね…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/76e2cf46-85ec-77d8-4c37-fb197c595f03.png)

## BITとBOOLの違い。
BITとBOOLどちらもTRUE/FALSEしか状態が格納できません。
じゃあなんで2つもおなじ役目の物があるねんということですが以下が違いです。

・BITは配列が作れない、BOOLは配列が作れる。
・BITは1つでメモリを1BIT使用する、BOOLは1つで1BYTE使用する。
※これはCODESYSの場合であり他のPLCも同じとは限りません

という違いがあります。
じゃあBITの方がメモリ節約できるじゃんとなりますが、問題は読み書きに時間がかかります。
コンピュータから見るとアドレスの指定はBYTE単位の方が処理しやすいからです。
BOOLでないと配列にできないのはコンピュータが処理しやすいからですね。

ではデータのサイズを見てみましょう。
SIZEOFでは変数のサイズを見れます。バイトのサイズが出力される関数です。
data1はboolが16個あるから 1Byte * 16 = 16になります。
data2はboolが32個あるから 1Byte * 32 = 32になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/5290c3b4-c492-9e9d-6410-de9d77fdeb77.png)


## 正解例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/1dc8b81f-1266-07cd-cabe-d4e1221536e5.png)

```plaintext
TYPE struct_BIT16 :
STRUCT
	b00:BIT;
	b01:BIT;
	b02:BIT;
	b03:BIT;
	b04:BIT;
	b05:BIT;
	b06:BIT;
	b07:BIT;
	b08:BIT;
	b09:BIT;
	b0A:BIT;
	b0B:BIT;
	b0C:BIT;
	b0D:BIT;
	b0E:BIT;
	b0F:BIT;
END_STRUCT
END_TYPE
```

```plaintext
TYPE struct_BIT32 :
STRUCT
	b00:BIT;
	b01:BIT;
	b02:BIT;
	b03:BIT;
	b04:BIT;
	b05:BIT;
	b06:BIT;
	b07:BIT;
	b08:BIT;
	b09:BIT;
	b0A:BIT;
	b0B:BIT;
	b0C:BIT;
	b0D:BIT;
	b0E:BIT;
	b0F:BIT;
	b10:BIT;
	b11:BIT;
	b12:BIT;
	b13:BIT;
	b14:BIT;
	b15:BIT;
	b16:BIT;
	b17:BIT;
	b18:BIT;
	b19:BIT;
	b1A:BIT;
	b1B:BIT;
	b1C:BIT;
	b1D:BIT;
	b1E:BIT;
	b1F:BIT;
END_STRUCT
END_TYPE
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/8641eecc-6a18-adfd-982e-f925f3b03098.png)

```plaintext
TYPE union_BIT16:
UNION
    nBit :struct_BIT16;
    nByte : ARRAY[0..1] OF BYTE;
    nWord : ARRAY[0..0] OF WORD;
END_UNION
END_TYPE
```

```plaintext
TYPE union_BIT32:
UNION
    nBit :struct_BIT32;
    nByte : ARRAY[0..3] OF BYTE;
    nWord : ARRAY[0..1] OF WORD;
	nDword : ARRAY[0..0] OF DWORD;
END_UNION
END_TYPE

```

nBitのところが配列から構造体のstruct_BIT16/32になって構造体の中身はBITを16個,32個並べています。
ではこれで試してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/a9416a57-e756-e0dc-fadb-1707867f38ed.png)

下位2BITがONなので3,BYTE,WORD,DWORDに3が入りましたねめでたしめでたし。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/67e9086b-c89c-6977-76d1-dd698ec41832.png)

SIZEOFのデータサイズも正しいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/0040d1f6-031f-f620-18ce-5e69a9751759.png)

CODESYSのデータ型については以下に説明があります

https://content.helpme-codesys.com/en/CODESYS%20Development%20System/_cds_reference_datatypes.html

# 他のBIT指定方法。

CountはWORDで定義しています。ほしいビットを.1などをつけるだけで使えます。
MELSECとかと同じですね。WORDだと.0～.15が指定できます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/e3bd9821-7982-e020-a1b8-6b701d39280f.png)

CODESYSの説明ページ(Index access to bits integer variables)

https://content.helpme-codesys.com/en/CODESYS%20Development%20System/_cds_operands_variables_accessing_bits.html