今回の記事ではTwinCAT内でPragmaを使用する基本的な考え方・文法を説明します。Pragmaをうまく使用することによりコードを生成するときよりFlexibleになります。
さ、始めよう!
pragma in TwinCAT?
Pragmaは、アプリケーションのソースコードにある特別な命令で、PrecompliationやComplieするとき様々な変数の属性に影響を与えます。例えば、Pragmaはコードを生成するときに以下の影響が発生するかもしれません。
- 変数の初期化
- 変数のMonitoring
- コード生成中にMessageの強制出力
- 変数をConditionによっての属性変化
注意するのはPragmasはST言語のみ対応できます。TC 3.1 Build 4024から、宣言部分でも実装部分でも条件付きのPragmasが使えるようになりますが、その条件付きPragmasは PLC プロジェクトではサポートされていますが、ライブラリではサポートされていません。つまりTC 3.1以前のVersionは、宣言部分を使っても意味がありません。
その条件付きPragmasは、宣言コードと実装コードのどちらをコンパイル時に使用するかを指定します。例えば、あるコンパイラ定義が定義されているか、ある値を持っているか、ある変数が宣言されているか、ある関数ブロックが存在するか、などに依存させることができます。
Implementation
これからPragramsの様々な使い方をExampleを通じて紹介します。
Example1 Operator
Example1ではpragmasの条件分岐文{IF defined ()}を使用し該当する条件がTRUE・FALSEを判定します。下記では、もしAddOperationが定義さかVar1を加算し、AddOperationが未定義であればVar1を0に書き込みます。
VAR Var1 :SINT; END_VAR {define AddOperation} {IF defined (AddOperation)} Var1 := Var1 + SINT#1; {ELSE} Var1 := 0; {END_IF} |
Result
AddOperationが定義されたので、Var1はサイクルで加算します。
判定条件をプロジェクトに定義されない条件に変えます。
Var1は加算できなくなり、常に0になります。
Example2 Define in VAR Area
次はVARの変数定義エリアでもしMyVarがPragmas内で定義されたらbOutputはProcess Outputとして宣言します。もしMyVarがPragmas内で定義されてないならbInputはProcess Inputとして宣言するようにします。そしてMyVAR文字列のDefault値もへします。
VAR {define MyVar} {IF defined (MyVar)} MyVar :STRING:=’MyVAR is defined’; {info ‘Process output is defined.’} bOutput AT %Q*:BOOL; {ELSE} MyVar :STRING:=’MyVAR is not defined.’; {info ‘Process input is defined.’} bInput AT %I*:BOOL; {END_IF;} END_VAR |
Result
MyVarが定義された場合bOutputというProcess Output変数が定義され、MyVar=MyVAR is defined という文字列が格納されました。
次はIF defined のところに別の変数を判定するように変更します。
今度MyVar値は”MyVAR is not defined”に変わり、bInputというProcess Input変数が定義するようになりました。
Example3 Check Global variable
Exmaple3ではGlobal 変数が定義されたかによって実行するコードを変えてみます。
下記ではもしmyGlobalVarという変数が定義されれば、myGlobalVarをTrueにします。
VAR Var1 :SINT; myGlobalVar:BOOL; END_VAR //define variable {IF defined (variable:myGlobalVar)} myGlobalVar:=TRUE; {END_IF} |
Result
Done!myGlobalVarがTrueになりました。
Example4 pou: <pou name>
今度はあるPouが存在してるかをCheckする文法を紹介します。True=該当する名前のPOU・FB・FCがプロジェクトに定義されました。そうではない場合はFalseになります。
もちろん、POUだけではなく、POUの中の特定のMethodなどもCheckできます。
“pou: <pou name>.<method name>” |
Example4ではプロジェクト内にPOU_TestというPouがあるかをCheckしてみます。
もしPOU_Testがプロジェクト内で定義されれば、POU_RunningがTrueになります。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; END_VAR // {IF defined (pou:POU_Test)} POU_Running:=TRUE; {ELSE} POU_Running:=FALSE; {END_IF} |
Result
Done!
Example5 Define LittleEndian
今度はTwinCAT3 Runtimeが稼働してるPCのCPUがLittleEndianかBighEndianかをCheckしてみます。CPUがBigEndianであれば、IsLittleEndianがFalseになります。
Exampl5ではいまTwinCAT Runtimeが稼働してるCPUのCPUがLittleEndianであればLittleEndianをTrueにしBigEndianをFalseにします。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; BigEndian,LittleEndian:BOOL; END_VAR //CPU Check {IF defined(IsLittleEndian)} LittleEndian:=TRUE; BigEndian:=FALSE; {ELSE} LittleEndian:=FALSE; BighEndian:=TRUE; {END_IF} |
Result
Done!それで自分のPCのCPUがLittleEndianであることがわかりました。
Example6 FPUSupported?
今度はTwinCAT Codeの生成機がFPU(Floating-point unit)で実数計算をしているかをCheckします。 それ以外の場合、TwinCATはFPU演算をエミュレートしますが、処理速度はかなり遅くなります。
Example6ではTwinCAT Runtimeが稼働してるPCがFPU対応していればFPUSupportedがTrueになります。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; BigEndian,LittleEndian:BOOL; FPUSupported:BOOL; END_VAR //FPU Supported {IF defined(IsFPUSupported)} FPUSupported:=TRUE; {ELSE} FPUSupported:=FALSE; {END_IF} |
Result
Done!いまTwinCAT Runtime稼働してるPCがFPU対応していますね。
Example7 RegisterSize?
実はPragmasを使ってCPUのRegisterサイズを確認できます。
hasvalue (RegisterSize, ‘<register size>’) |
<register size>はCPUのRegister Sizeになります(Bit)。
- 16 :186 and C16x,
- 64 :X86 64-bit
- 32 : X86
Exmaple7ではTwinCAT Runtimeが稼働してるPCのRegisterサイズをCheckし、
16Bitならr16=True、32Bitならr32=True、64Bitならr64=Trueになります。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; BigEndian,LittleEndian:BOOL; FPUSupported:BOOL; r16,r32,r64:BOOL; END_VAR // {IF hasvalue(RegisterSize,’16’)} r16:=TRUE; {ELSIF hasvalue(RegisterSize,’32’)} r32:=TRUE; {ELSIF hasvalue(RegisterSize,’64’)} r64:=TRUE; {END_IF} |
Result
Done!いまTwinCAT Runtimeが稼働してるPCが64Bitであることがわかります。
Example8
最後のExmapleではPOUの中に特定のAttributeあるかをCheckします。
Attributeに関してはまた別の記事で説明しますので、心配しないでください。
hasattribute (pou: <pou name>, ‘<attribute>’) |
もし該当するPOUにAttributeがあればTrueに成立します。
Example8ではPOU_TestにTestingというAttributeを追加します。
Example8ではPOU_TestにはTestingというAttributeがあるかをCheckし、結果をPOU_hasAttrに返します。そしてPOU_TestにTesting11というAttributeがないにより、hasattributeの機能を確認します。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; BigEndian,LittleEndian:BOOL; FPUSupported:BOOL; POU_hasAttr:BOOL; POU_hasAttr1:BOOL; r16,r32,r64:BOOL; END_VAR // {IF hasattribute(pou:POU_Test,’Testing’)} POU_hasAttr:=TRUE; {ELSE} POU_hasAttr:=FALSE; {END_IF} // {IF hasattribute(pou:POU_Test,’Testing11′)} POU_hasAttr1:=TRUE; {ELSE} POU_hasAttr1:=FALSE; {END_IF} |
Result
Done!POU_TestにはTestingというAttributeがあるので、当然POU_hasAttrがTrueになります。逆に、Testing11というAttributeがないので、POU_hasAttr1がFalseになります。
Example9 Check pragmas with value
次はPrgamasに変数が定義されたかを確認するだけではなく、どんな数値が設定されたかを判断するプログラムを作ってみます。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; BigEndian,LittleEndian:BOOL; FPUSupported:BOOL; POU_hasAttr:BOOL; POU_hasAttr1:BOOL; Counter:INT; r16,r32,r64:BOOL; Cond:BOOL; END_VAR // {define test ‘1’} {IF hasvalue(test,’1′)} Counter:=Counter+1; {ELSIF hasvalue(test,’2′)} Counter:=Counter+2; {END_IF} |
Result
Done!Counterはずっとサイクルで1を加算するので、hasvalue(test,’1’)が条件成立したことがわかります。
Example9 Condition
最後のExample9では複数のPragmas変数を使って条件比較する文法を紹介します。下記のコードでは、もしいまTwinCAT Runtimeが稼働してるPCが64Bit、なおかつFPU対応であればCond変数がTrueになります。
VAR Var1 :SINT; myGlobalVar:BOOL; POU_Running:BOOL; BigEndian,LittleEndian:BOOL; FPUSupported:BOOL; POU_hasAttr:BOOL; POU_hasAttr1:BOOL; Counter:INT; r16,r32,r64:BOOL; Cond:BOOL; END_VAR {IF hasvalue(RegisterSize,’64’) AND (defined(IsFPUSupported))} Cond:=TRUE; {ELSE} Cond:=FALSE; {END_IF} |
Result
Done!TwinCAT Runtimeが稼働してるPCは64BitなおかつFPU対応であることがわかりました。