PLC#ST(Structured Text)入門1

#ST(Structured Text)とは？

コントロールのプロセスがますます複雑になり、いまオートメーションシステムもより複雑なデータ処理機能・計算が必要になります。
ST(Structured Text)はそのためにデザインされた言語です。IEC61131-3によって設計され、PASCAL-baseの高級言語、プログラマーを簡易でタスクを完成させるのは目標です。Siemnesだけではなく、三菱・Omron・CodeSys様々なメーカーもあり、命令だけが違うの場合が多いです。

##Siemens With TIA
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/38500482-8f14-cb0e-5a8b-c54843887f0c.png)


##GXWorks2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/c20661ac-c7d3-53ff-e8e0-48095b7474ae.png)

##Simotion
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/0960a82e-7706-bfce-cd6a-5dd2426e6088.png)

Siemens社のSIMOTION STはさらにTechnologyコマンド作られ、SIMOTIONデバイス・モーションコントロールとTechnologyを簡単に制御することができます。(例えば位置決め・CAMなど…)

今回の入門編はSIMOTIONのSTのをBaseとして書いたものです。どうぞよろしくお願いします。

#前書き
まずSiemnesの気が失うほど1000ページくらいの英語ST言語取り扱い書があります。
このなかにいつも出てるの” Syntax diagram”があります。Siemensの取り扱い書がこのようなGraphでものことを説明するのが好きらしいけど、ちょっとわかりにくいですが。
ここでまず慣れておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/2a79eae2-05bc-f022-054b-55da6fabc885.png)
 1. Rule name：つまり該当する文法の名前 
 2. Option：あってもなくても大丈夫な宣言
 3. Iteration：Looping・繰り返しですね。
 4. Alternative：ORと同じだと思えば大丈夫です。

#ST Source の構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/8b85b279-dcbb-93c0-26a6-45ced7928abb.png)


ST Sourceは純文字でそして何か所の”Logicalセレクション”に分かれることができます。
ST Sourceにはメインのセレクションが以下になります：

- Unit Statement(Optional)
    - STの名前
- Interface section
    - 変数・構造体・プログラム(POU)の宣言
    - 他のST SourceからのImport 
- Implementation section
    - プログラムなどの本体にいる場所
    - 他のST SourceからのImport 
- POU (program organization unit)
    - 単体実行のプログラムソース(Program,Function,Function Block) 
- Declaration section
    - 数・構造体などの定義(Interface section、Implementation sectionも可能)
- Statement section
    - POUの中の実際プログラム

#基本文法
PASCAL-baseなので、書き方はそんなに難しくありません。
大事なのは”;”とか忘れなければ～笑。自分がいつも忘れます…あとSIMOTIONのEDITOR非常に…弱いです。
変数、関数のAuto-Fillがありません。

##変数名
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/e189109b-3346-8350-a8e8-646497aa4ab3.png)
このGraphだけみても、うん？のイメージしかきませんね。
私はまずこのGraphを2つ大きな枠に分けますね。
Identifierは、うん～つまり変数の名前の決まりルールですね。

- 枠1は変数の頭文字の宣言ルール。
- 枠2は変数の頭文字以外のルール
    1. 変数宣言します
    2. Letterだけか
    3.  ”_”にするか？ 
    4.  ”_”にしたら、そのあとはLetterか、数字か
    5. "_"にするか？、Optionだからしなくて大丈夫。
    6. もし"_"にしたら、次はLetterか、Digitをつける。
    7. まだ文字つけるか？
    8. 変数宣言終わり。

って感じです。
例として：
枠1：A、A_、_A、_9
枠2の５：A、_A、_9
枠2の６：A_1,_9A
枠2の７：まだ_、Letter、Digitつけるなら５にも戻る。
枠2の８：宣言終わり

A、A1、_A、_9、AB,ABC,_9A,_9_A...のような変数名は有効になります。

＊もちろん予約語は使ってはいけません。


##変数定義

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/cd0ebb28-465b-dddb-d996-929fe5bf60a4.png)
基本タイプはすこく簡単で、 変数の宣言のあとにデータタイプを定義するだけです。

```
MyReal:REAL;
MyBOOL:BOOL;
MyInt:INT:=100;
```

##UDT（User defined Type)
構造体は以下の3つのところで定義できます。

- Interface section
- Implementation section
- Program organization unit (POU)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/8ec6cc9d-e0b2-9e8e-4ebe-1a35b36d256b.png)

```
INTERFACE   
    TYPE  
        bRun            :BOOL;
        bCmdSet         :ARRAY[0..100]OF BOOL;
        sDrive          :STRUCT   
            ActSpeed    :REAL;
            SetSpeed    :REAL;
            ActPos      :REAL;
            SetPos      :REAL;   
        END_STRUCT    
    END_TYPE
    PROGRAM	pou1;
END_INTERFACE

IMPLEMENTATION
    VAR_GLOBAL
        Drive1Run          :bRun;
        Drive1             :sDrive;
    END_VAR

    PROGRAM pou1   
    	Drive1.SetSpeed		:=100.0;
    	Drive1.SetPos		:=50.0;
    END_PROGRAM
END_IMPLEMENTATION
    
```

##配列

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/b45b0fc8-8282-99c2-9d2b-42387f69354d.png)

```
MyVar1:ARRAY[0..10]OF INT;
MyRealArray:ARRAY[0..999]OF REAL;
```


##CONSTANT宣言


###VAR CONSTANT

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/b8c479f9-d9b1-26b7-c87d-b5afaf4b9d1d.png)

```
VAR CONSTANT

    PI              :REAL:=3.1415;
    BuzzerONTime    :TIME:=TIME#1h1m1s;
    Message         :STRING[40]:='Something Wrong..';
    TwoPI           :REAL:=PI*2;

END_VAR
```

###VAR GLOBAL CONSTANT
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/fd34b6f0-ef03-e681-3b65-02790c9b1302.png)

```
VAR_GLOBAL CONSTANT

    RefSpeed    :REAL:=1500.0;
    RefCurrent  :REAL:=14.5;

END_VAR
```

#Statements
ここで3種類の基本機能を説明します。

##値を与える(Value assignment)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/3beb4f34-a908-fab2-5eed-9b14b08ce2f9.png)

```
//Real
r32Temp:=0.0;
r32Temp:=3.3;

//String
str40   :='Hello World!';
str40_1 :=str40;

byteValue:=str40[5];
str40[20]:=byteValue;

MyArray1:=MyArray2;
MyArray1[i]:=10;
MyArray[5]:=23;

struct1.element1:=TRUE;
struct1.element2:=3.92;
```

##コントロール(Control Statement)

###IF

もし～ならこれをする、そうじゃなければこうする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/f774cd39-dbb3-44a3-1d1b-267d2712eb68.png)

```

IF r32Temp > 0.0 THEN
    
    str40:='r32Temp is >0';
    
ELSIF r32temp = 0.0 THEN

    str40:='r32Temp is 0';

ELSE
    
    str40:='r32Temp is <0';

END_IF;

```

###Case

IF文は複雑の条件を組み合わせて条件分け事できますが、もし1つの変数に対してこの値からこの処理、
あの値から別の処理のであればCASEを使ってたほうがわかりやすいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/3efd8219-9e6a-e7d1-de55-6c935443553d.png)

####Valus List 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/f089a175-0ef0-22c9-1ecd-3aa1d453b34d.png)

```
CASE i16Value OF
    1:
        speedSetPoint:=300.0;
    2:
        speedSetPoint:=600.0;
    3..10:
        speedSetPoint:=1500;
        
    ELSE
        speedSetPoint:=0.0;
        
        ;
END_CASE;
```

###FOR Loop
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/e8345f22-1284-3264-3cb3-8318add17f10.png)

```
FOR i16Value:=0 TO 10 DO
    //
    boolList[i16Value]:=FALSE;
    
END_FOR ;

FOR i16Value:=0 TO 2 DO
    //
    boolList[i16Value]:=FALSE;
    
END_FOR ;

FOR i16Value:=10 TO -2 DO
    //
    boolList[i16Value]:=FALSE;
    
END_FOR ;
```
###WHILE Loop

条件立つまでずっとLOOPINGします。
注意するのはLOOPING始まる前に条件をチェックする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/1e7a3e76-a221-cf37-4846-bcd7dfb811ca.png)

```
WHILE i16Value <=10 DO
    boolList[i16Value]:=TRUE;
    i16Value:=i16Value+1;
    
END_WHILE;
```

###REPEAT

WHILE LOOPと似てて同じく条件立つまでずっとLOOPINGします。
こっちはWHILE LOOPと違ってLOOPING一回終わってから条件をチェックする。
つまり最低限一回は実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/b149c505-878a-b25d-81fc-20f0a8f32ccc.png)

```
i16Value:=0;
REPEAT
    
    boolList[i16Value]:=FALSE;
    UNTIL i16Value=10
    
END_REPEAT;


FOR i16Value:=10 TO -2 DO
    //
    boolList[i16Value]:=FALSE;
    IF bStopSw THEN
        EXIT;
    END_IF;
    
END_FOR ;
```

###EXIT

LOOPINGが途中に終わりたいとき使います。

```
FOR i16Value:=10 TO -2 DO
    //
    boolList[i16Value]:=FALSE;
    IF bStopSw THEN
        EXIT;
    END_IF; 
END_FOR ;
```

###CONTINUE
LOOPINGの中にある条件立つとプログラム実行したくない、でもLOOPINGまだ続きたいのとき使います。

```
//if bStopSw is FALSE,i16sum=15
//if bStopSw is TRUE,i16sum=9

i16sum:=0;
FOR i:=0 TO 2 DO

    FOR j:=0 TO 1 DO
        i16sum:=i16sum+1;
        IF bStopSw THEN
            CONTINUE;
            i16sum:=i16sum+1;
        END_IF;
    END_FOR;
    i16sum:=i16sum+1;

END_FOR;
```
###RETURN

RETURNを使うことによって、LOOPINGから離れるだけではなく、このプログラムまで終了させます。
なので下の例だとRETURNの条件が成立するとi16sum:=1999;がもう実行しないままプログラムを終了する。
SiemensのSTL”BEU”と同じな考え方でいいだと思います。

```
FOR i16Value:=0 TO 10 DO
    //
    boolList[i16Value]:=FALSE;
    IF bStopSw THEN
        RETURN;
    END_IF;
    
    
END_FOR ;

//This statement will not be execute if bStopSw is TRUE
i16sum:=1999;
```

###WAITFORCONDITION

Motion Taskの中ににイベント待ちのとき使われています。条件がTRUEになるまでプログラム実行は猶予します。
注意するのはWITHのあとにあるExpressionは以下の２つ状態しかみないです：

- FALSEｰ>TRUE、いわゆる立ち上げ。つまり条件成立。
- FALSE、条件不成立。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/d64e4d05-25c7-5fee-2cc4-d5d406c807f1.png)

####Expression
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/c34e2078-8b7b-362e-a93a-1691d5d185df.png)


```
IMPLEMENTATION
    
            
    EXPRESSION  TriggerSensor
        TriggerSensor:=%I10.0;
    END_EXPRESSION  
        
    
    PROGRAM pou1
        
        WAITFORCONDITION TriggerSensor WITH TRUE DO
            
            %Q10.0:=TRUE;
            ;
        END_WAITFORCONDITION;
        
        ;
    END_PROGRAM
    
    
END_IMPLEMENTATION

```

###GOTO

一応、使えます。POUの中に好きな場所に飛べます。
ManualにもGOTOは特殊な場合だけ使ってください、と。(例えばTroubleshooting、構造プログラムには使うべきではない、と。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/eb0898b8-988f-c7bf-72a7-731889906c30.png)

##Comments
Line CommentとBlock Commentがあります。

- Line Comment
    -  //
-  Block Comment
    -  (**)
    
```
//This is a line comment
    a:=0;

(*
This is a Block comment
TEXTTEXTTEXTTEXTTEXT
*)
    b:=0
```

#実例
先の文章にはInterfaceとか、PROGRAMとか色々なわけわからない単語出てきますが、ここで一旦それらを無視しましょう。
それらの意味は次の入門2に説明したいと思います。

##TIA SIMOTION

まずTIAでD445を一つ追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/9a8d8a61-b511-2453-4bf2-71b102f33586.png)

Project>>Oepn SIMOTION Configurationします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/8ee47b94-b36c-2778-6bce-a80e9266bf8a.png)

PLC_1 >>PROGRAMS >>Insert ST source fileをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/5aef6085-147e-07c0-22b2-637ab8875ae6.png)

ST source の名前を入力しOKをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/27a91993-29ed-6e85-8e05-58523025b6f8.png)

このような画面が出てきます。
TIAとかGXWORKSとかは少し違いますので、ここで特に書きません。
では仮に、Program1つ、Function1つを書きましょう。
ProgramはMyPBとMyVariableという2つの変数があり、もしMyPBがONになったら、MyVariableに10を書き込みます。MyPBがOFFのであれば、MyVariableに0を書き込みます。簡単明瞭。
Functionは整数のパラメターがあり、Function内ではこの整数を実数に変換しそのあと二乗し*3.14として返しします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/034ccd23-7f4d-558b-a6e0-246c030f1b5e.png)

まずINTERFACEのところに、そのProgramとFunctionのを定義します。
ここでfcCalとmyPou1として定義します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/a21e770a-0de6-e882-af78-c3e914fb26db.png)

次はIMPLEMENTATIONのところにプログラム書きます。
これはfcCalの中身です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/a8db8006-d0a1-8b64-0367-5d4150541f20.png)

これはmyPou1です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154661/a76c18ac-4a56-02a5-4515-32a2a7c56fb5.png)

みんなはまだPROGRAM？FUNCTION？とか色々な疑問が出てくるかもしれませんが、次からそれらの考え方を書きたいと思います。では、お疲れ様ですー！

記事はここにものっています：
http://soup01.com/ja/2020/05/09/simotion-structuredtext-1/