CodeSys#Function Blockを作る

# Version
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/97038f2a-1e61-f9fb-a79e-9381bf89fca1.png)

#Function Blockとは？
ここでまたCodeSysのOnline Helpを見てみましょう。

>A function block is a POU that yields one or more values when executed.

Function Blockは実行すると多数の値を生むものです。

>The values of the output variables and the internal variables remain unchanged after execution until the next execution. This means that the function block does not necessarily return the same output values for multiple calls with the same input variables.

Function Blockの出力変数・内部変数の値は実行してから次のCycleまでキープすることができます。つまり、Function Block複数回に呼び出しされても、たとえ入力変数が同じなものだとしても必ず同じな出力になるとは限らないです。

>You can access only input and output variables of a function block from outside the function block instance, not the internal variables.

あなたがFunction Blockの変数をアクセスするには入力と出力だけになります。内部変数はアクセスしないように。

>Access to a function block instance is restricted to the POU in which the instance is declared, unless you have declared the instance globally.

Function Blockのインスタンスは呼び出しされたPOUのの中だけになります。グローバルに宣言することも可能です。

##呼び出しの方法
instance : function block;

```
MyFnction:FB1;
```

##変数をアクセス方法

instance . variable

```
MyFunction.iInputs
```

##Input・Outputの割り付け方
Inputなら:=
Outputなら=>

```
FB1_1(in:=myInput,Out=>myOut);
```

#実装
##Function Block作成
Application>Add Object>POU

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/c7a1161d-b367-49b9-019c-a82b4dde0e9e.png)

Function Blockの名前決めて、“Function Block”を選んでOK。
Extends、Implementsなどは別で説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/5903b98b-478f-74e9-544b-7d1e632a4972.png)

画面は基本Program・Functionと一緒です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/a324d4ae-dc0b-51f4-93be-f42a23c47073.png)

##プログラム

- Input
    - iStart2Count:Trueの立ち上げでCounter+1する
    - iReset:Trueの時間が1s以上だとCounter=0する
    - iCountUpSetting:Counterの設定値
- Output:
    - qCount: いま内部Counterの値
    - qCountIsReached: Counter値>CountUp設定のとき、True


変数は以下のように定義します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/39d9fb52-bb4e-06db-5ec2-00b089940d43.png)

###NTW1：
R_TRIGは立ち上げを検知するFunction Blockです。
ここはStartのポタンを押したことを検知します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/8683566b-e85c-7e0d-8df3-2506ee16726c.png)

###NTW2：
TONはDelay On Timerですね。1秒以上ONになるとリセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/fc880d29-d8af-5579-991e-dc759c98f596.png)

###NTW3：
Countボタン押したらCounter+1します。	
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/aa60e26f-630c-a55a-b52b-e213117cb202.png)

###NTW4
Resetだったら０を入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/5b8663fa-7c1f-51f2-78fb-8ffdb30e9e3e.png)

###NTW5/6
現在のCount数とCount状態を出力するだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/bf3f629e-18bb-58fe-1bb8-9b6d976ab8e9.png)

##呼び出し
Function Blockの説明はまだ覚えています？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/f01edd27-f8e3-35cd-9dd3-44dbf0571c94.png)

>Function Blockの出力変数・内部変数の値は実行してから次のCycleまでキープすることができます。

つまり、それら値のをキープするにはメモリ領域が必要です。
そのメモリ領域はインスタンスです。
まずインスタンスを作成し与えます。
![mygif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/c4f99097-3b84-5ae7-42ba-6cf1d01cb6b2.gif)

変数を定義しますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/8209c850-c021-5ecd-1bb0-15eae01b0914.png)

次はそれそれの変数をInput/Outputに割り付けます。

>あなたがFunction Blockの変数をアクセスするには入力と出力だけになります。

###方法１
直接その“Pin”に変数を割り付ける。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/308ef685-6411-ca00-0bf8-f1cf58ccd63c.png)

###方法２
別のネットワークでそれそれのInput、Outputを<instance> . <variable>
のようにアクセスする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/b6ec736b-dc75-10eb-4ba3-461dea6bd938.png)

>内部変数はアクセスしないように。

たとえ自分が直接インスタンスの内部変数アクセスしようとしたらどうになる？
Siemens,Melsはそのようなアクセスやろうと思えばできますが、CodeSysはどうやらそれを自動変数入力のところ出てこないですね。(一応無理やり名前入れてコンパイルしてもエラーない)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/ba14037f-0999-c519-a824-45e4a78f97c8.png)

#画面作成
ADDしたら＋１、Resetは０に戻す、現在Count表示されており、Count設定もあり、Counterが設定より大きならランプが光るって感じですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/55d5f0f1-e0bd-6ba6-6b71-9da5d02c5377.png)

##モーメンタリースイッチ
調べるには５分かかった…
ボタンを選んで、プロパティのところにInput configuration>Tap>Variableを変数割り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/d7b75714-fab7-dc2a-cfc8-c83d2ead1454.png)

#実装
こんな感じになりますね。
![functionblock1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/9d84a292-024e-4940-3d20-492ba4cb59d9.gif)

#ひとこと

Function BlockにInput・Outputを割付るときに、方法２があるって見せましたね。

1. Function Blockの“Pin”のところに直接変数と紐つける。
2. Function BlockのINPUT・OUTPUTを呼び出す前・後に紐付けます。

どっちのほうがよいでしょう？
私からはこうみます。
もしそのFunction BlockのTrigger条件などそんな複雑でなければ方法１のほうがプログラムが見やすいだと思います。全てどんなものが入るか、どんなものが出るか一気にみえるから。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/aa26db7a-4c59-6935-40ec-cfc69f3017a3.png)

逆にもしプログラムのTrigger条件はかなり複雑なら、方法２のほうが逆に見やすいと思いますし、プログラムの組み方がもっとやりやすくなります。
例えばこんのようなロジックをInputのリセットに取り込むになると、結構見にくいになりますよね。もう１つに変数追加してこのロジックの結果にふって、FunctionBlockの入力として入れてもよいです。あくまでも好みです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/9ad70548-9176-56cf-11fe-4ae4d2968b99.png)

余談ですが、
ラダーにこのようなロジックを組むときどう操作方法すれば作れるかちょっと迷ってた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/69ea516a-3a05-5541-fb50-cb76573a568b.png)

実際はこんな感じです作りますね。
![functionblock2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/22fdcbf1-a9e4-d373-b5cf-7de3c8af76f5.gif)


#Function・Function Blockの違い

Pythonからみるとdef とClassの違い、だといっています。でもお客さんにラダーしかやったことない人が多くて、いままでずっと三菱のラダー(ベタ書きで、ラベルなしアドレス使用)のスタイルで歩いてきたので、そもそも保持しない？する？だけでも説明がかなり時間かかります。
ここで新しいFunctionとFunction Blockを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/ac0270ad-1001-cb09-ea87-2eab3d88f460.png)

中身はまったく一緒で、INPUTがTrueだと＋１する。

```Name:FB1_1
FUNCTION_BLOCK FB1_1
VAR_INPUT
	iCount:BOOL;
END_VAR
VAR_OUTPUT
	qCount:int;
END_VAR
VAR
	Count:INT;
END_VAR

IF iCount THEN
	Count:=Count+1;
END_IF

qCount:=Count;
```

```Name:FC1
FUNCTION FC1:INT 
VAR_INPUT
	iPlus:BOOL;
END_VAR


VAR
	count:INT;
END_VAR

IF iPlus THEN
	count:=count+1;
END_IF

FC1:=count;

```

結果はどうになるでしょう？
FCのほうが常に１で、FBの方が数字がどんどん上がっています。
それはまさにHelpの“FCが演算結果が次のサイクルまで持たない”と“FBが次のCycleでも演算結果が持つ”ってことです。

![functionblock3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/23d36818-4a14-87f3-f177-f86de2cfa1ef.gif)

以上ですーお疲れ様です。