Beckhoff#TwinCAT3 TF6310でComputer Link Clientを立ち上げToyopuc NANO PLCと通信しよう

今回の記事ではBeckhoff TwinCAT3でTF6310を使用しComputer Link Clientを立ち上げ、JTEKTのToyopuc PLCに読み書き操作します。

さ、FAを楽しもう。

前書き

いつも私の技術ブログとYouTubeチャンネルをご覧いただき、心より感謝申し上げます。また、いまFullさん(full@桜 八重 (@fulhause) / X)と共に毎週水曜日の夜にお届けしている「高橋クリス」ラジオ番組を運営しています。

技術は独り占めせず、届けるもの

私たちは工場の生産技術や制御に関する技術情報を、ブログや動画などで無料公開しています。「知識は誰でもアクセスできるべき」という信念のもと、現場で役立つ具体的なノウハウやトラブル事例などを発信してきました。すべて無料で続けているのは、「知らなかったせいで困る人」を少しでも減らしたいからです。

また、もしあなたの現場で…

  • 「このPLCとデバイスの組み合わせ、ちゃんと動くのかな?」
  • 「EtherCAT通信でうまくいかない部分を検証してほしい」
  • 「新しいリモートI/Oを試したいけど社内に検証環境がない」

など、困っている構成や試してみたいアイデアがあれば、ぜひお知らせください。機器の貸出や構成の共有が可能であれば、検証し、記事や動画で発信します(ご希望に応じて匿名対応も可能です)。

支援のかたち

現在、私達の活動はほぼ無償で続けており、記事や動画の制作には、時間と検証環境の整備が必要です。この活動を継続的にコンテンツを提供するためには、皆様の温かいご支援が大変重要です。

メンバーシップ(ラジオの応援)

Fullさんとのラジオをより充実させるための支援プランです。

https://note.com/fulhause/membership/join

Amazonギフトリスト

コンテンツ制作に必要な機材・書籍をリストにしています。

https://www.amazon.co.jp/hz/wishlist/ls/H7W3RRD7C5QG?ref_=wl_share

Patreon(ブログ・動画活動への応援)

月額での小さなご支援が、記事の執筆・検証環境の充実につながります。

https://www.patreon.com/user?u=84249391

Paypal

小さな支援が大きな力になります。

https://paypal.me/soup01threes?country.x=JP&locale.x=ja_JP

知ってたら助かること、届けたいだけです

あなたの応援が、知識の共有をもっと自由で持続可能なものにしてくれます。これからもどうぞよろしくお願いします。

soup01threes*gmail.com

https://x.com/3threes2

技術はひとりじゃもったいない。

Reference Link

Beckhoff#TwinCAT3 TF6310でSLMP Clientを立ち上げ三菱PLCと通信しよう
Dobot#Part4_Real-time feedback portとBeckhoff TwinCAT3 TF6310通信しよう
Beckhoff#TwinCAT TF6310_Build a TCP Client

Computer Link?

Computer Link(コンピュータリンク)は、TOYOPUC-Nano の通信機能のひとつで、Ethernet経由でPCや上位装置とデータをやり取りするための標準プロトコルです。

  • PLC内部データ(リレー・レジスタなど)をPCなどの上位装置から直接読み書きするための通信方式
  • 通信は TCP/IP または UDP/IP を使って行われます
  • 本体のPORTもしくは2ETモジュールからアクセスできます。
  • TOYOPUC-Nano側では特別なラダーやシーケンスプログラムを作る必要がありません。

通信データの構造(Frame Format)

Ethernet 経由で送受信されるパケットは以下の階層構造を持ちます。Ethernet/IP/UDPヘッダは通信スタック側で自動的に付加されるため、上位アプリケーションで扱うのは主に TOYOPUC Dataフィールド です。ここに コマンド・転送番号・アドレス・データ が格納されます。

  • Ethernet Header (MAC情報)
  • IP Header (送信元/宛先IP)
  • TCP / UDP Header (Port情報)
  • TOYOPUC Data (Computer Link部分)
  • Ethernet FCS(CRC)

Data の詳細構成

TOYOPUC Dataは「コマンド」または「レスポンス」の形式を取ります。流れとしては;

  1. PC → PLC : Command (CMDコード + アドレス情報 + データ)
  2. CPUローカルポートもしくは2ET : 解析しCPUへアクセス
  3. PLC → PC : Response (RC + 要求データ)

フィールド名

バイト数

内容

FT (Frame Type)

2 B

常に固定値(通信識別:例 0x00 0x00)

転送番号(Transfer No.)

2 B

コマンドとレスポンスの対応を識別。LL(下位)/LH(上位)で構成

CMD(Command Code)

1 B

実行する命令を指定(例:読み出し・書き込みなど)

Command Field Data

可変

対象アドレス・点数・データ値などを格納

Response Code (RC)

1 B

レスポンス時のみ使用。00h = 正常、他値はエラーコード

Computer Link アドレス指定表

Computer Link 方式では、TOYOPUCの内部データを「領域記号+番号」で指定します。

マニュアルでは各メモリ領域に対応するワード/バイト/ビット/プログラム番号が定義されています。

ID

名称

指定可能範囲

Word Address

Byte Address

Bit Address

K

Keeping Relay(保持リレー)

K000–K2FF

0020–004F

0040–009F

0200–04FF

V

Specific Relay(特殊リレー)

V000–V0FF

0050–005F

00A0–00BF

0500–05FF

T/C

Timer / Counter

T,C000–1FF

0060–007F

00C0–00FF

0600–07FF

L

Link Relay(リンクリレー)

L000–L7FF

0080–00FF

0100–01FF

0800–0FFF

X/Y

I/O Relay

X,Y000–7FF

0100–017F

0200–02FF

1000–17FF

M

Internal Relay(内部リレー)

M000–M7FF

0180–01FF

0300–03FF

1800–1FFF

S

Specific Register(特殊レジスタ)

S0000–03FF

0200–05FF

0400–0BFF

N

T/C Recent Value(現在値)

N0000–01FF

0600–07FF

0C00–0FFF

R

Link Register(リンクレジスタ)

R0000–07FF

0800–0FFF

1000–1FFF

D

Data Register(データレジスタ)

D0000–2FFF

1000–3FFF

2000–7FFF

B

File Register(ファイルレジスタ)

B0000–1FFF

6000–7FFF

C000–FFFF

EK

Expansion Keep Relay(拡張保持リレー)

EK000–FFF

0100–01FF

0200–03FF

1000–1FFF

こちらはFrame例です。

Implementation

それでは、実際プログラムと通信設定などを始めましょう。

Toyopuc Side

最初にToyopuc側を設定します。

Project→Parameter→Link Parameterをクリックします。

Detailをクリックします。

Detail network settingをクリックします。

Connectionにアプリケーションを合わせて設定しましょう。

今回はOpen Protocol”TCP Destination-Specified Passive Open”を選択し(つまりどんなIPアドレスにも接続できる)、Own Node Port No.をPort番号設定します。

Beckhoff Side

次はTwinCAT側を設定します。

TF6310

もしSocket通信のFAが0x06のエラーが発生した場合、実際TF6310を実施するTwinCAT環境にTF6310をインストールしたかを確認してください。

PLC Side

PLCを追加するためにPLC→Add New Itemします。

Standard PLC PLC Projectをクリックし、Addで追加します。

DUT

次は構造体を作成します。

eTOYOPUCAddressList

こちらの列挙タイプではToyopuc PLC にComputer Link経由でアクセスするデバイスのタイプを指定します。

{attribute ‘qualified_only’}
{attribute ‘strict’}
TYPE eTOYOPUCAddressList :
(
P1K
,P2K
,P3K
,P1V
,P2V
,P3V
,P1L
,P2L
,P3L
,P1XY
,P2XY
,P3XY
,P1Y
,P2Y
,P3Y
,P1M
,P2M
,P3M
,P1S
,P2S
,P3S
,P1N
,P2N
,P3N
,P1R
,P2R
,P3R
,P1D
,P2D
,P3D
,P1B
,P2B
,P3B
,SS
,N
,RR
,D
,B
,EK
,EV
//,ETC:=21
,EL
,EXY
,EM
,ES
,EN
,H
,U
,GXY
,GM
,EB0000To7FFF
,EB8000ToFFFF
,EB10000To17FFF
,EB18000To1FFFF
)
;
END_TYPE

eTOYOPUCAddressRange

こちらの列挙タイプではToyopuc PLCの各デバイスにアクセスできる下限と上限をリミットします。

{attribute ‘qualified_only’}
{attribute ‘strict’}
TYPE eTOYOPUCAddressRange :
(
PxKUpper:=16#4F
,PxKLower:=16#20
,PxVUpper:=16#5F
,PxVLower:=16#50
,PxLUpper:=16#7F
,PxLLower:=16#60
,PxXYUpper:=16#17F
,PxXYLower:=16#100
,PxMUpper:=16#1FF
,PxMLower:=16#180
,PxSUpper:=16#5FF
,PxSLower:=16#200
,PxNUpper:=16#7FF
,PxNLower:=16#600
,PxRUpper:=16#FFF
,PxRLower:=16#800
,PxDUpper:=16#3FFF
,PxDLower:=16#1000
,PxBUpper:=16#7FFF
,PxBLower:=16#6000
,EKUpper:=16#1FF
,EKLower:=16#100
,EVUpper:=16#2FF
,EVLower:=16#200
,ETCUpper:=16#37F
,ETCLower:=16#300
,ELUpper:=16#57F
,ELLower:=16#380
,EXYUpper:=16#5FF
,EXYLower:=16#580
,EMUpper:=16#7FF
,EMLower:=16#600
,ESUpper:=16#FFF
,ESLower:=16#800
,ENUpper:=16#17FF
,ENLower:=16#1000
,HUpper:=16#1FFF
,HLower:=16#1800
,UUpper:=16#7FFF
,ULower:=16#0000
,GXYUpper:=16#0FFF
,GXYLower:=16#0000
,GMUpper:=16#1FFF
,GMLower:=16#1000
,EB0000To7FFFUpper:=16#0FFF
,EB0000To7FFFLower:=16#0000
,EB8000ToFFFFUpper:=16#7FFF
,EB8000ToFFFFLower:=16#0000
,EB10000To17FFFUpper:=16#7FFF
,EB10000To17FFFLower:=16#0000
,EB18000To1FFFFUpper:=16#7FFF
,EB18000To1FFFFLower:=16#0000
)UINT:=EKLower;
END_TYPE

eTOYOPUCCommands

こちらはToyopuc PLCに発行するコマンドです。今回の記事ではコマンド94と95のみ検証します。

{attribute ‘qualified_only’}
{attribute ‘strict’}
TYPE eTOYOPUCCommands :
(
Read := 16#94
,Write:=16#95
)BYTE:=Read;
END_TYPE

stTOYOPUCCommParameters

こちらは通信FBに渡すためのデータ・タイプで、ToyopucのIPアドレスやPortなどを指定できます。

TYPE stTOYOPUCCommParameters :
STRUCT
strIPAddress :STRING:=’192.168.0.133′;
wport :WORD:=6000;

eStartReadDevices :eTOYOPUCAddressList;
wStartReadAddress :WORD;
wTotalReadAddress :WORD;
wReadPort :WORD:=6000;

eStartWriteDevices :eTOYOPUCAddressList;
wStartWriteAddress :WORD;
wTotalWriteAddress :WORD;
wWritePort :WORD:=6001;

wFunctionPort :WORD:=6002;

wResetCommandBitPos :WORD; //To Toyopuc
wStartCommandBitPos :WORD; //from Toyopuc

xWriteEnable :BOOL;

iAccessBitPosition :INT:=0;

END_STRUCT
END_TYPE

FC

今度はFCを作成します。

fcTOYOPUCCheckDevicesRange

こちらのFCはstTOYOPUCCommParametersタイプに設定したアドレス範囲が有効かどうかチェックします。

VAR

関数の入力パラメータはアクセスするToyopuc PLCのデバイスタイプ・そして先頭アドレスとレジスタ数であり、それに対してデータのバイト数・設定有効かどうかなどを出力します。

FUNCTION fcTOYOPUCCheckDevicesRange : WORD
VAR_INPUT
eAddressList:eTOYOPUCAddressList;
iStartAddress:UINT;
iTotolDevices:UINT;
END_VAR

VAR_OUTPUT
wWordAddress:WORD;
xSettingVaild:BOOL;
wTotalBytes :WORD;

END_VAR
VAR
wtempStartAddress
,wtempEndAddress:UINT;

END_VAR

Program

こちらはCASE文を使っていて、デバイスの種類により比較する変数がかわります。もし設定が有効であれば、xSettingVaildをTRUEにします。

xSettingVaild:=FALSE;
wTotalBytes:=iTotolDevices*2;

CASE eAddressList OF

eTOYOPUCAddressList.P1K
,eTOYOPUCAddressList.P2K
,eTOYOPUCAddressList.P3K
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxKLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxKLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxKUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxKLower);

eTOYOPUCAddressList.P1V
,eTOYOPUCAddressList.P2V
,eTOYOPUCAddressList.P3V
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxVLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxVLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxVUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxVLower);

eTOYOPUCAddressList.P1L
,eTOYOPUCAddressList.P2L
,eTOYOPUCAddressList.P3L
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxLLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxLLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxLUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxLLower);

eTOYOPUCAddressList.P1XY
,eTOYOPUCAddressList.P2XY
,eTOYOPUCAddressList.P3XY
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxXYLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxXYLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxXYUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxXYLower);

eTOYOPUCAddressList.P1M
,eTOYOPUCAddressList.P2M
,eTOYOPUCAddressList.P3M
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxMLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxMLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxMUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxMLower);

eTOYOPUCAddressList.P1S
,eTOYOPUCAddressList.P2S
,eTOYOPUCAddressList.P3S
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxSLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxSLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxSUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxSLower);

eTOYOPUCAddressList.P1N
,eTOYOPUCAddressList.P2N
,eTOYOPUCAddressList.P3N
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxNLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxNLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxNUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxNLower);

eTOYOPUCAddressList.P1R
,eTOYOPUCAddressList.P2R
,eTOYOPUCAddressList.P3R
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxRLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxRLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxRUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxRLower);

eTOYOPUCAddressList.P1D
,eTOYOPUCAddressList.P2D
,eTOYOPUCAddressList.P3D
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxDLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxDLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxDUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxDLower);

eTOYOPUCAddressList.P1B
,eTOYOPUCAddressList.P2B
,eTOYOPUCAddressList.P3B
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxBLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.PxBLower AND wtempEndAddress <= eTOYOPUCAddressRange.PxBUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.PxBLower);

eTOYOPUCAddressList.EK
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EKLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.EKLower AND wtempEndAddress <= eTOYOPUCAddressRange.EKUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EKLower);

eTOYOPUCAddressList.EV
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EVLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.EVLower AND wtempEndAddress <= eTOYOPUCAddressRange.EVUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EVLower);

eTOYOPUCAddressList.EL
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EKLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.ELLower AND wtempEndAddress <= eTOYOPUCAddressRange.ELUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ELLower);

eTOYOPUCAddressList.EXY
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EXYLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.EXYLower AND wtempEndAddress <= eTOYOPUCAddressRange.EXYUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EXYLower);

eTOYOPUCAddressList.EM
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EMLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.EmLower AND wtempEndAddress <= eTOYOPUCAddressRange.EMUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EMLower);

eTOYOPUCAddressList.ES
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ESLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.ESLower AND wtempEndAddress <= eTOYOPUCAddressRange.ESUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ESLower);

eTOYOPUCAddressList.EN
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ENLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.ENLower AND wtempEndAddress <= eTOYOPUCAddressRange.ENUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ENLower);

eTOYOPUCAddressList.H
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.HLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.HLower AND wtempEndAddress <= eTOYOPUCAddressRange.HUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.HLower);

eTOYOPUCAddressList.U
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ULower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.ULower AND wtempEndAddress <= eTOYOPUCAddressRange.UUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.ULower);

eTOYOPUCAddressList.GXY
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.GXYLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.GXYLower AND wtempEndAddress <= eTOYOPUCAddressRange.GXYUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.GXYLower);

eTOYOPUCAddressList.GM
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.GMLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.GMLower AND wtempEndAddress <= eTOYOPUCAddressRange.GMUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.GMLower);

//Expansion File Register
eTOYOPUCAddressList.EB0000To7FFF
,eTOYOPUCAddressList.EB8000ToFFFF
,eTOYOPUCAddressList.EB10000To17FFF
,eTOYOPUCAddressList.EB18000To1FFFF
:
wtempStartAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EB0000To7FFFLower);
wtempEndAddress:=wtempStartAddress+iTotolDevices;
IF wtempStartAddress>=eTOYOPUCAddressRange.EB0000To7FFFLower AND wtempEndAddress <= eTOYOPUCAddressRange.EB0000To7FFFUpper THEN
xSettingVaild:=TRUE;
END_IF
wWordAddress:=iStartAddress+TO_UINT(eTOYOPUCAddressRange.EB0000To7FFFLower);
END_CASE

fcTOYOPUCGetAddressList

こちらの関数はToyopucにアクセスするデバイスタイプに沿ってコードを返します。

VAR

関数の入力ではこれからアクセスするデバイスの種類になります。

FUNCTION fcTOYOPUCGetAddressList : BYTE
VAR_INPUT
eAddressList:eTOYOPUCAddressList;
END_VAR
VAR
END_VAR

Program

こちらのプログラムはCASE文を使用し、アクセスするデバイスタイプによってコードを返します。

fcTOYOPUCGetAddressList:=255;

CASE eAddressList OF

eTOYOPUCAddressList.P1K
,eTOYOPUCAddressList.P1V
,eTOYOPUCAddressList.P1L
,eTOYOPUCAddressList.P1XY
,eTOYOPUCAddressList.P1M
,eTOYOPUCAddressList.P1D
:
fcTOYOPUCGetAddressList:=16#01;

eTOYOPUCAddressList.P2K
,eTOYOPUCAddressList.P2V
,eTOYOPUCAddressList.P2L
,eTOYOPUCAddressList.P2XY
,eTOYOPUCAddressList.P2M
,eTOYOPUCAddressList.P2D
:
fcTOYOPUCGetAddressList:=16#02;

eTOYOPUCAddressList.P3K
,eTOYOPUCAddressList.P3V
,eTOYOPUCAddressList.P3L
,eTOYOPUCAddressList.P3XY
,eTOYOPUCAddressList.P3M
,eTOYOPUCAddressList.P3D
:
fcTOYOPUCGetAddressList:=16#03;

eTOYOPUCAddressList.EK
,eTOYOPUCAddressList.EV
,eTOYOPUCAddressList.EL
,eTOYOPUCAddressList.EXY
,eTOYOPUCAddressList.EM
,eTOYOPUCAddressList.ES
,eTOYOPUCAddressList.EN
,eTOYOPUCAddressList.H
:
fcTOYOPUCGetAddressList:=16#0;

eTOYOPUCAddressList.U
:
fcTOYOPUCGetAddressList:=16#8;

eTOYOPUCAddressList.GM
,eTOYOPUCAddressList.GXY
:
fcTOYOPUCGetAddressList:=16#7;

eTOYOPUCAddressList.EB0000To7FFF:
fcTOYOPUCGetAddressList:=16#9;

eTOYOPUCAddressList.EB8000ToFFFF:
fcTOYOPUCGetAddressList:=16#A;

eTOYOPUCAddressList.EB10000To17FFF:
fcTOYOPUCGetAddressList:=16#B;

eTOYOPUCAddressList.EB18000To1FFFF:
fcTOYOPUCGetAddressList:=16#C;
END_CASE


FB

fbTOYOPUCComupterLinkRead

FUNCTION_BLOCK fbTOYOPUCComupterLinkRead
VAR_INPUT
xStart :BOOL;
xReset :BOOL:=TRUE;
END_VAR
VAR_OUTPUT
wErrorCode :WORD;
END_VAR
VAR_IN_OUT
stTOYOPUCCommParameters:stTOYOPUCCommParameters;
arrWord :ARRAY[0..49]OF WORD;
END_VAR
VAR

istep :INT;
fbTON :TON;
arrSendData:ARRAY[0..199]OF BYTE;
arrRevData:ARRAY[0..199]OF BYTE;

xSettingVaild:BOOL;
wTotalBytes:WORD;
wWordAddress:WORD;
diFlags:DINT;
xiResult :__XINT;

fbTon2:TON;
fbClientServrConnection :FB_ClientServerConnection;
fbSocketSend :FB_SocketSend;
fbSocketReceive :FB_SocketReceive;

xEnable :BOOL;

END_VAR





//Reference to Manaul 2ET TUU-6949

fbTON.PT:=T#1S;

CASE istep OF

0: //Flag Init
xReset:=0;
xEnable:=FALSE;
xiResult:=0;
wErrorCode:=0;
fbSocketReceive.bExecute:=FALSE;
fbSocketSend.bExecute:=FALSE;
IF xStart AND NOT fbSocketReceive.bBusy AND NOT fbSocketSend.bBusy THEN
istep:=3;
END_IF;

3: //Buffer Init
MEMSET(
destAddr:=ADR(arrSendData)
,fillByte:=0
,n:=SIZEOF(arrSendData)
);
MEMSET(
destAddr:=ADR(arrRevData)
,fillByte:=0
,n:=SIZEOF(arrRevData)
);
istep:=5;
istep:=5;
5: //Build the Frame
//Frame Example
//00 00 06 00 94 01 00 20 02 00
//00 00 06 00 94 07 00 10 01 00
//b0 b1 b2 b3 b4 b5 b6 b7 b8 b9
arrSendData[0]:=16#00; //AlwaysON
arrSendData[1]:=16#00; //AlwaysON
arrSendData[2]:=16#06; //LL,Lower Transfer Number
arrSendData[3]:=16#00; //LH,Higher Transfer Number
arrSendData[4]:=16#94; //Command – pleaes reference to Manual P.55
arrSendData[5]:=fcTOYOPUCGetAddressList( //Get the Address Code
stTOYOPUCCommParameters.eStartReadDevices
);
fcTOYOPUCCheckDevicesRange( //Check the user Parameters
eAddressList:=stTOYOPUCCommParameters.eStartReadDevices
,iStartAddress:=stTOYOPUCCommParameters.wStartReadAddress
,iTotolDevices:=stTOYOPUCCommParameters.wTotalReadAddress
,xSettingVaild=>xSettingVaild
,wTotalBytes=>wTotalBytes
,wWordAddress=>wWordAddress
);
MEMCPY(
destAddr:=ADR(arrSendData[6])
,srcAddr:=ADR(wWordAddress)
,n:=SIZEOF(wWordAddress)
);
MEMCPY(//Lower WordNo.
destAddr:=ADR(arrSendData[8])
,srcAddr:=ADR(stTOYOPUCCommParameters.wTotalReadAddress)
,n:=SIZEOF(stTOYOPUCCommParameters.wTotalReadAddress)
);
IF xSettingVaild THEN //Check the user parameter is ok or not
istep:=10;
ELSE
istep:=295;
END_IF;
10:
xEnable:=TRUE;
IF fbClientServrConnection.eState = E_SocketConnectionState.eSOCKET_CONNECTED THEN
istep:=20;
END_IF
20:
istep:=30;
30:
fbSocketSend.bExecute:=TRUE;
IF fbSocketSend.bBusy THEN
fbSocketSend.bExecute:=FALSE;
istep:=40;
END_IF
40:
fbSocketReceive.bExecute:=TRUE;
IF fbSocketReceive.bBusy THEN
istep:=45;
END_IF
45:
fbTON(IN:=TRUE,PT:=T#0.5S);
IF fbTON.Q THEN
istep:=3;
fbTON(IN:=FALSE);
fbSocketReceive.bExecute:=FALSE;
END_IF
IF fbSocketReceive.nRecBytes > 0 AND NOT fbSocketReceive.bError THEN
MEMCPY(
destAddr:=ADR(arrWord[0])
,srcAddr:=ADR(arrRevData[5])
,n:=30
);
istep:=50;
END_IF
50:

fbSocketReceive.bExecute:=FALSE;
istep:=3;
END_CASE


fbClientServrConnection(
sRemoteHost:=stTOYOPUCCommParameters.strIPAddress
,nRemotePort:=stTOYOPUCCommParameters.wReadPort
,bEnable:=xEnable
);
fbSocketSend(
hSocket:=fbClientServrConnection.hSocket
,cbLen:=10
,pSrc:=ADR(arrSendData)
);
fbSocketReceive(
hSocket:=fbClientServrConnection.hSocket
,cbLen:=SIZEOF(arrRevData)
,pDest:=ADR(arrRevData)
);

FB

次はToyopuc PLCと通信するFBを作成します。

fbTOYOPUCComupterLinkWrite

こちらのFBはBeckhoff→Toyopuc NANOに任意のデバイス・先頭・そして最大50個を一気に書き込みできます。

VAR

こちらはFBのInterfaceです。

  • xStart:通信開始
  • xReset:自動リセット
  • wErrorCode:エラー発生したときのSTEP番号
  • stTOYOPUCCommParameters:通信パラメータ(ToyopucのIPアドレス・デバイスそのほか)
  • arrWord;書き込むデータ。配列の長さを増やせれば、その分書き込めるデータ量も増やせます。

FUNCTION_BLOCK fbTOYOPUCComupterLinkWrite
VAR_INPUT
xStart :BOOL;
xReset:BOOL;
END_VAR
VAR_OUTPUT
strCurrentDateTime:STRING;
wErrorCode :WORD;
END_VAR
VAR_IN_OUT
stTOYOPUCCommParameters:stTOYOPUCCommParameters;
arrWord :ARRAY[0..49]OF WORD;
END_VAR

VAR
istep :INT;
fbTON :TON;
arrSendData:ARRAY[0..199]OF BYTE;
arrRevData:ARRAY[0..199]OF BYTE;

xSettingVaild:BOOL;
wTotalBytes:WORD;
wWordAddress:WORD;
diFlags:DINT;
xiResult :__XINT;
fbTon2:TON;
wTotalBytes2:WORD;

fbClientServrConnection :FB_ClientServerConnection;
fbSocketSend :FB_SocketSend;
fbSocketReceive :FB_SocketReceive;

xEnable :BOOL;
END_VAR

Program

こちらはFBの本体です。

  • Step0=FBを初期化する
  • Step3=通信開始の前にBufferリセットする。
  • Step5=Computer LinkのFrameを生成する
  • Step10=Toyopuc PLCとSocket 通信の接続する
  • Step30=Toyopuc PLCに書き込みのFrameを送信する
  • Step40=Toyopuc PLCの受信データ待ち、そしてデータ転送
  • Step50=Step3にLoop Backする

fbTON.PT:=T#1S;

CASE istep OF

0:
xReset:=0;
xiResult:=0;
xEnable:=FALSE;
fbSocketReceive.bExecute:=FALSE;
fbSocketSend.bExecute:=FALSE;
IF xStart AND NOT fbSocketReceive.bBusy AND NOT fbSocketSend.bBusy THEN
istep:=3;
END_IF;

3:
MEMSET(
destAddr:=ADR(arrSendData)
,fillByte:=0
,n:=SIZEOF(arrSendData)
);
MEMSET(
destAddr:=ADR(arrRevData)
,fillByte:=0
,n:=SIZEOF(arrRevData)
);
istep:=5;
5:

//Frame Example
//00 00 06 00 95 08 00 10 0A 5B XX XX
fcTOYOPUCCheckDevicesRange(
eAddressList:=stTOYOPUCCommParameters.eStartWriteDevices
,iStartAddress:=stTOYOPUCCommParameters.wStartWriteAddress
,iTotolDevices:=stTOYOPUCCommParameters.wTotalWriteAddress
,xSettingVaild=>xSettingVaild
,wTotalBytes=>wTotalBytes
,wWordAddress=>wWordAddress
);
arrSendData[0]:=16#00; //AlwaysON
arrSendData[1]:=16#00; //AlwaysON
wTotalBytes2:=wTotalBytes+4;
MEMCPY(
destAddr:=ADR(arrSendData[2])
,srcAddr:=ADR(wTotalBytes2)
,n:=SIZEOF(wTotalBytes2)
);

arrSendData[4]:=16#95; //Command – pleaes reference to Manual P.55
arrSendData[5]:=fcTOYOPUCGetAddressList(
stTOYOPUCCommParameters.eStartWriteDevices
);

MEMCPY(
destAddr:=ADR(arrSendData[6])
,srcAddr:=ADR(wWordAddress)
,n:=SIZEOF(wWordAddress)
);

MEMCPY(
destAddr:=ADR(arrSendData[8])
,srcAddr:=ADR(arrWord)
,n:=wTotalBytes
);
IF xSettingVaild AND xStart THEN
istep:=10;
END_IF;

10:
xEnable:=TRUE;
IF fbClientServrConnection.eState = E_SocketConnectionState.eSOCKET_CONNECTED THEN
istep:=20;
END_IF
20:
istep:=30;
30:
fbSocketSend.bExecute:=TRUE;
IF fbSocketSend.bBusy THEN
fbSocketSend.bExecute:=FALSE;
istep:=40;
END_IF
40:
fbSocketReceive.bExecute:=TRUE;
IF fbSocketReceive.nRecBytes > 0 AND NOT fbSocketReceive.bError THEN
istep:=50;
END_IF
50:

fbSocketSend.bExecute:=FALSE;
istep:=3;

END_CASE;

fbClientServrConnection(
sRemoteHost:=stTOYOPUCCommParameters.strIPAddress
,nRemotePort:=stTOYOPUCCommParameters.wWritePort
,bEnable:=xEnable
);
fbSocketSend(
hSocket:=fbClientServrConnection.hSocket
,cbLen:=wTotalBytes2+4
,pSrc:=ADR(arrSendData)
);
fbSocketReceive(
hSocket:=fbClientServrConnection.hSocket
,cbLen:=SIZEOF(arrRevData)
,pDest:=ADR(arrRevData)
);

fbTOYOPUCComupterLinkRead

こちらのFBはBeckhoff→Toyopuc NANOに任意のデバイス・先頭・そして最大50個を一気に読み込むことができます。

VAR

こちらはFBのInterfaceです。

  • xStart:通信開始
  • xReset:自動リセット
  • wErrorCode:エラー発生したときのSTEP番号
  • stTOYOPUCCommParameters:通信パラメータ(ToyopucのIPアドレス・デバイスそのほか)
  • arrWord;書き込むデータ。配列の長さを増やせれば、その分読み込むデータ量も増やせます。

FUNCTION_BLOCK fbTOYOPUCComupterLinkRead
VAR_INPUT
xStart :BOOL;
xReset :BOOL:=TRUE;
END_VAR
VAR_OUTPUT
wErrorCode :WORD;
END_VAR
VAR_IN_OUT
stTOYOPUCCommParameters:stTOYOPUCCommParameters;
arrWord :ARRAY[0..49]OF WORD;
END_VAR
VAR

istep :INT;
fbTON :TON;
arrSendData:ARRAY[0..199]OF BYTE;
arrRevData:ARRAY[0..199]OF BYTE;

xSettingVaild:BOOL;
wTotalBytes:WORD;
wWordAddress:WORD;
diFlags:DINT;
xiResult :__XINT;

fbTon2:TON;
fbClientServrConnection :FB_ClientServerConnection;
fbSocketSend :FB_SocketSend;
fbSocketReceive :FB_SocketReceive;

xEnable :BOOL;

END_VAR

Program

こちらはFBの本体です。

  • Step0=FBを初期化する
  • Step3=通信開始の前にBufferリセットする。
  • Step5=Computer LinkのFrameを生成する
  • Step10=Toyopuc PLCとSocket 通信の接続する
  • Step30=Toyopuc PLCにデータ読み込むのFrameを送信する
  • Step40=Toyopuc PLCの受信データ待ち、そしてデータ転送
  • Step45=Toyopuc PLCから0.5s返答がなければ、強制的にStepを50にし、接続をクロスします。
  • Step50=Step3にLoop Backする

//Reference to Manaul 2ET TUU-6949

fbTON.PT:=T#1S;

CASE istep OF

0: //Flag Init
xReset:=0;
xEnable:=FALSE;
xiResult:=0;
wErrorCode:=0;
fbSocketReceive.bExecute:=FALSE;
fbSocketSend.bExecute:=FALSE;
IF xStart AND NOT fbSocketReceive.bBusy AND NOT fbSocketSend.bBusy THEN
istep:=3;
END_IF;

3: //Buffer Init
MEMSET(
destAddr:=ADR(arrSendData)
,fillByte:=0
,n:=SIZEOF(arrSendData)
);
MEMSET(
destAddr:=ADR(arrRevData)
,fillByte:=0
,n:=SIZEOF(arrRevData)
);
istep:=5;
istep:=5;
5: //Build the Frame
//Frame Example
//00 00 06 00 94 01 00 20 02 00
//00 00 06 00 94 07 00 10 01 00
//b0 b1 b2 b3 b4 b5 b6 b7 b8 b9
arrSendData[0]:=16#00; //AlwaysON
arrSendData[1]:=16#00; //AlwaysON
arrSendData[2]:=16#06; //LL,Lower Transfer Number
arrSendData[3]:=16#00; //LH,Higher Transfer Number
arrSendData[4]:=16#94; //Command – pleaes reference to Manual P.55
arrSendData[5]:=fcTOYOPUCGetAddressList( //Get the Address Code
stTOYOPUCCommParameters.eStartReadDevices
);
fcTOYOPUCCheckDevicesRange( //Check the user Parameters
eAddressList:=stTOYOPUCCommParameters.eStartReadDevices
,iStartAddress:=stTOYOPUCCommParameters.wStartReadAddress
,iTotolDevices:=stTOYOPUCCommParameters.wTotalReadAddress
,xSettingVaild=>xSettingVaild
,wTotalBytes=>wTotalBytes
,wWordAddress=>wWordAddress
);
MEMCPY(
destAddr:=ADR(arrSendData[6])
,srcAddr:=ADR(wWordAddress)
,n:=SIZEOF(wWordAddress)
);
MEMCPY(//Lower WordNo.
destAddr:=ADR(arrSendData[8])
,srcAddr:=ADR(stTOYOPUCCommParameters.wTotalReadAddress)
,n:=SIZEOF(stTOYOPUCCommParameters.wTotalReadAddress)
);
IF xSettingVaild THEN //Check the user parameter is ok or not
istep:=10;
ELSE
istep:=295;
END_IF;
10:
xEnable:=TRUE;
IF fbClientServrConnection.eState = E_SocketConnectionState.eSOCKET_CONNECTED THEN
istep:=20;
END_IF
20:
istep:=30;
30:
fbSocketSend.bExecute:=TRUE;
IF fbSocketSend.bBusy THEN
fbSocketSend.bExecute:=FALSE;
istep:=40;
END_IF
40:
fbSocketReceive.bExecute:=TRUE;
IF fbSocketReceive.bBusy THEN
istep:=45;
END_IF
45:
fbTON(IN:=TRUE,PT:=T#0.5S);
IF fbTON.Q THEN
istep:=3;
fbTON(IN:=FALSE);
fbSocketReceive.bExecute:=FALSE;
END_IF
IF fbSocketReceive.nRecBytes > 0 AND NOT fbSocketReceive.bError THEN
MEMCPY(
destAddr:=ADR(arrWord[0])
,srcAddr:=ADR(arrRevData[5])
,n:=30
);
istep:=50;
END_IF
50:

fbSocketReceive.bExecute:=FALSE;
istep:=3;
END_CASE


fbClientServrConnection(
sRemoteHost:=stTOYOPUCCommParameters.strIPAddress
,nRemotePort:=stTOYOPUCCommParameters.wReadPort
,bEnable:=xEnable
);
fbSocketSend(
hSocket:=fbClientServrConnection.hSocket
,cbLen:=10
,pSrc:=ADR(arrSendData)
);
fbSocketReceive(
hSocket:=fbClientServrConnection.hSocket
,cbLen:=SIZEOF(arrRevData)
,pDest:=ADR(arrRevData)
);

MAIN

最後はメインプログラムです。

VAR

こちらは先ほど作成したFBのInstanceと読み書き用のパラメータ変数を定義します。

PROGRAM MAIN
VAR
fbWrite1:fbTOYOPUCComupterLinkWrite;
xWrite:BOOL;
arrWriteWord :ARRAY[0..49]OF WORD;

fbRead1:fbTOYOPUCComupterLinkRead;
xRead:BOOL;
arrReadWord :ARRAY[0..49]OF WORD;
END_VAR

VAR
stTOYOPUCCommParameters_w:stTOYOPUCCommParameters;
stTOYOPUCCommParameters_r:stTOYOPUCCommParameters;
END_VAR

Program

最後はプログラム中でInstance呼び出し、設定をアプリケーションに合わせてにしてください。

fbWrite1.xStart:=xWrite;
fbWrite1.xReset:=TRUE;

stTOYOPUCCommParameters_w.strIPAddress:=’192.168.0.100′;
stTOYOPUCCommParameters_w.wStartWriteAddress:=0;
stTOYOPUCCommParameters_w.wTotalWriteAddress:=10;
stTOYOPUCCommParameters_w.wWritePort:=49700;
stTOYOPUCCommParameters_w.eStartWriteDevices:=eTOYOPUCAddressList.GM;

fbWrite1(
stTOYOPUCCommParameters:=stTOYOPUCCommParameters_w
,arrWord:=arrWriteWord
);

fbRead1.xStart:=xRead;
fbRead1.xReset:=TRUE;

stTOYOPUCCommParameters_r.strIPAddress:=’192.168.0.100′;
stTOYOPUCCommParameters_r.wStartReadAddress:=0;
stTOYOPUCCommParameters_r.wTotalReadAddress:=5;
stTOYOPUCCommParameters_r.wReadPort:=49802;
stTOYOPUCCommParameters_r.eStartReadDevices:=eTOYOPUCAddressList.GM;

fbRead1(
stTOYOPUCCommParameters:=stTOYOPUCCommParameters_r
,arrWord:=arrReadWord
);

Result

こちらのLinkから動作を確認してください。

Download

こちらのLinkからプロジェクトをDownloadしてください。

https://github.com/soup01Threes/TwinCAT3/blob/main/Example_Toyoyopuc_ComputerLink.tnzip

シェアする

  • このエントリーをはてなブックマークに追加

フォローする