前書き
前回はTF6620でTwinCATのI/O DevicesからSiemens のS7 CPUと通信してみました。今回はPart1にちょっと加味してPLC HMIと簡単なプログラムを追加し、もう少し仕上げようと思っています。その前に、まずもう少しTF6620のこと話ししましょう。
S7 CommunicationはSiemensのProtocolで、このProtocolを使ってS7 CPUのデータエリア(Input・Output・DBなど)を書き読むことができます。TF6620はS7300/400/1200/1500にもSupportして、TwinCAT I/O Devices・PLC Function Blocksの二種類も実装方法があります。Part1ではTwinCAT I/O Devicesのやり方を説明しましたね。
少し考えましたが、そのTF6620はSiemensがメイン制御をやってる装置と通信しデータやり取りがするとか、複数のS7 CPUからデータを取り、さらにCloudに上げたりとか。もちろん、そこでOPCUAやMQTTなど別のProtocolでも可能です!
ちなみに、こちらはPart1です:
Protocol から見ると、S7 CommunicationがS7 CPUと接続を作るもので、COTPやTPKTなど通信制御も仕組み入っています。
TwinCATから見ると、S7 Communication・COTP・TPKTなどの面倒なことを型付けてくれて、TCP・IPにはTF6631 TCP/UDP RTで仕事します。
最後PLCから見ると、TF6620にS7 Signle Request とS7 Cyclic Requestがあり、そのTCP/UDP RTにはS7 ConnectionのObjectになります。
*話が変わりますが、COTPはLayer4ではConnection(通信に先立って)やConnectless(そうではないType)の2種類があります。このようにProtocolでは相手にデータを確実に届くことを保証するためにデータの到着・順番・通信量の制御プログラムたくさん入っています。
例えばAがBにデータを送ります。データがちゃんと届いたら確認応答します。もしAが一定時間応答もらわないと再送するなどします。あとデータが順番到着ではないときにちゃんと順番整いてから上のLayerに転送するとか、受信側より早いSpeedデータを送らないようにするとかの制御もやっています。
反対に、CLTP(Connection Less Transport Protcol)はそういう制御はしません。データの信頼性・到着順番などは保証しません。
実装
話はここまでにしましょう。プログラムを作ります。
DUT
最初はDUTを作成します。これは自分がプログラム作るとき必ずやるStepです。S7 ConnectorにはState,Error,Resetがあり、S7 Single RequestにはReceiveCounter,ErrorID,WriteToS7Enable,SendRequestがあります。
DUT_Comm_S7
そっちらはS7 ConnectorとS7 RequestがあるStautsとControlになります。
TYPE DUT_Comm_S7 : STRUCT //Input Error AT %I* :BOOL; State AT %I* :BYTE; //Output Reset AT %Q* :BOOL; //Req Input ReceiveCounter AT %I* :BYTE; ErrorID AT %I* :WORD; //Req Output WriteToS7Enable AT %Q* :BOOL; SendRequest AT %Q* :BYTE; END_STRUCT END_TYPE |
DUT_Comm_S7_Object1
次は読み書き用のメモリエリアをDUTにします。前のプロジェクトで定義した変数覚えていますか?
Requestことに定義するのは面取なので、DUT_Comm_S7_Object1をDUT_Comm_S7からExtendsすると定義します。そうすると、新しいRequest作成するときはDUT_Comm_S7_Object2…にまたExtendsすればよいです。もちろん、DUT_Comm_S7の変数を持ったままで。
つまりこんな感じですね。
TYPE DUT_Comm_S7_Object1 EXTENDS DUT_Comm_S7 : STRUCT //Read From S7 rDB1_DBD0 AT %I* :DWORD; rDB10_DBD4 AT %I* :REAL; rDB11_DBX0_7 AT %I* :BOOL; //Write to S7 wDB20_DBD0 AT %Q* :REAL; wDB20_DBW4 AT %Q* :INT; wDB20_DB6_3 AT %Q* :BOOL; END_STRUCT END_TYPE |
FC
次はFunctionを作ります。今回は2つの簡単なFunctionがあって、ConnectorやRequestからもらったStatusをPLC HMIで文字表示させるように考えています。
FC_CheckS7ConnectorIsError
S7 ConnectorのStatusみて、もし16#F1から16#F5までならTrueを返しします。
FUNCTION FC_CheckS7ConnectorIsError : BOOL VAR_INPUT ID :BYTE; END_VAR FC_CheckS7ConnectorIsError:=FALSE; CASE id OF 16#F1,16#F2,16#F3,16#F4,16#F5: FC_CheckS7ConnectorIsError:=TRUE; END_CASE |
FC_GetS7ConnectorStatusText
この関数はConnectorStatusによって文字列を返し、その文字列を表示PLC HMIに表示させます。
FUNCTION FC_GetS7ConnectorStatusText : STRING VAR_INPUT ID :BYTE; END_VAR CASE ID OF 16#00: FC_GetS7ConnectorStatusText:=’idle’; 16#01: FC_GetS7ConnectorStatusText:=’Start’; 16#10: FC_GetS7ConnectorStatusText:=’TCP setup’; 16#11: FC_GetS7ConnectorStatusText:=’TCP setup wait for response’; 16#20: FC_GetS7ConnectorStatusText:=’COTP setup’; 16#21: FC_GetS7ConnectorStatusText:=’COTP setup wait for response’; 16#30: FC_GetS7ConnectorStatusText:=’S7 setup’; 16#31: FC_GetS7ConnectorStatusText:=’S7 setup wait for response’; 16#40: FC_GetS7ConnectorStatusText:=’is connected’; 16#F1: FC_GetS7ConnectorStatusText:=’TCP error’; 16#F2: FC_GetS7ConnectorStatusText:=’TCP setup error’; 16#F3: FC_GetS7ConnectorStatusText:=’TCP timeout’; 16#F4: FC_GetS7ConnectorStatusText:=’COTP setup error’; 16#F5: FC_GetS7ConnectorStatusText:=’S7 setup error’; 16#FF: FC_GetS7ConnectorStatusText:=’Reset’; END_CASE |
Function Block
今回の主役です。最初はもっとOOPのコンセプトいれて練習しようと思いますが、やっばりOne-Step One-Step大事ですね。まだなれてないところがあるので。一部だけOOPのコンセプトになります。
Function BlockやってることはHMIとFBの動作・表示をひもつけて、SendRequestのトリガー・変数転送などの機能だけもっています。
FB_Communication_S7
FUNCTION_BLOCK FB_Communication_S7 VAR // Connector:DUT_Comm_S7_Object1; //HMI hmiConnectorStatusText :STRING; hmiConnectorStatusError :BOOL; hmiConnectorReset :BOOL; hmiRequestReceiveCounter :BYTE; hmiRequestErrorID :WORD; hmiRequestWriteToS7Enable :BOOL; hmiRequestSendRequest :BOOL; hmiReadFromS7DB1DBD0 :DWORD; hmiReadFromS7DB10DBD4 :REAL; hmiReadFromS7DB11DB0_7 :BOOL; hmiWriteToS7DB20DBD0 :REAL; hmiWriteToS7DB20DBW4 :INT; hmiWriteToS7DB20DBX6_3 :BOOL; ReceiveConuterBackUp :byte; //Internal FB _R_TRIG :ARRAY[0..3]OF R_TRIG; _Ton :ARRAY[0..3]OF ton; END_VAR |
//Counter hmiRequestReceiveCounter:=Connector.ReceiveCounter; //Rest Connector.Reset:=hmiConnectorReset; //Request Connector.WriteToS7Enable:=hmiRequestWriteToS7Enable; _R_TRIG[0](CLK:=hmiRequestSendRequest); IF _R_TRIG[0].Q THEN Connector.wDB20_DBD0:=hmiWriteToS7DB20DBD0; Connector.wDB20_DBW4:=hmiWriteToS7DB20DBW4; Connector.wDB20_DB6_3:=hmiWriteToS7DB20DBX6_3; Connector.SendRequest:=Connector.SendRequest+1; //Read From S7 CPU hmiReadFromS7DB1DBD0:=Connector.rDB1_DBD0; hmiReadFromS7DB10DBD4:=Connector.rDB10_DBD4; hmiReadFromS7DB11DB0_7:=Connector.rDB11_DBX0_7; END_IF //Counter Checker IF hmiRequestReceiveCounter <> ReceiveConuterBackUp THEN ReceiveConuterBackUp:=hmiRequestReceiveCounter; END_IF; //hmi Dislpay hmiConnectorStatusText:=FC_GetS7ConnectorStatusText(Connector.State); hmiConnectorStatusError:=FC_CheckS7ConnectorIsError(Connector.State); hmiRequestReceiveCounter:=Connector.ReceiveCounter; hmiRequestErrorID:=Connector.ErrorID; |
POU
最後はもちろんMain ProgramからCallするのは忘れずに。
PROGRAM MAIN VAR S7:FB_Communication_S7; b:bool; END_VAR S7(); |
TwinCAT I/O Devices
一回プロジェクトをコンパイルし、エアーがあるかどうかを確認しましょう。
次はI/O Devicesの割付です。ここで一つの例で説明します。
Status>State>右クリック>Change Link..します。
コンパイルエラーなしなら、PLCのObjectが出てきます。そしてMAIN.S7.Connector.Stateを選びましょう。
他のI/O Devicesも同じように割り付けましょう。
PLC HMI
これは今回作った画面です。詳しい説明しませんが、多分Titleなどみたらなにやるのかわかると思います。
それで一回プロジェクトを再コンパイルしダウンロードしましょう。
テスト
Siemens側から適当な与えを入れます。
そしてTwinCAT側みると、ConnectorStatusもすでに”Is connected”になり、Request StatusにもTrueになってるエラーBitがないです。
次はhmiRequestWriteToS7Enableを押してTrueになり、
hmiRequestSendRequestをクリックしリクエストを送ります。
そうみますと、TwinCAT側Siemensの与えが来ています。
そしてSiemens側にTwinCATが書き込むの与えもちゃんと反映されています。
はーい、お疲れ様です。
以下はプロジェクトのダウンロードLinkです。
https://github.com/soup01Threes/TwinCAT3/blob/main/TwinCAT_Project_TF6620__2.zip