Beispiel: Kommunikation BC/BX<->PC/CX (F_SwapRealEx)
Hier können Sie die kompletten Sourcen PC oder CX (x86) und BC (165) entpacken: DataExPC.zip und DataExBC.zip
Das Beispiel zeigt die Verwendung der F_SwapRealEx-Funktion. Laden Sie die PC (i386, pro-Datei) Applikation in das Laufzeitsystem eines Programmier-PCs (i386) und die BC (165) Applikation (165, pr6-Datei) in das Laufzeitsystem eines Bus-Controllers (z.B. BC9000).
Die PC Applikation liest/schreibt zyklisch eine Strukturvariable aus/in den Merkerbereich des BCs. Die Strukturvariable beinhaltet REAL-Elemente. Diese müssen vor der Verwendung auf dem PC oder vor dem Versand zum BC in das richtige Format konvertiert werden. Damit auf den BC über ADS zugegriffen werden kann muss dieser als Remote PC in die Liste der TwinCAT AMS Router-Verbindungen eingetragen werden (rechter Mausklick auf das TwinCAT-System Icon -> Eigenschaften -> AMS Router).
![]() | Der BC und PC hat ein unterschiedliches Datenalignment. Definieren Sie Strukturen mit 4- oder besser mit 8-Byte-Alignment, wenn Sie diese für den Datenaustausch BC <-> PC verwenden wollen. |
Die Strukturvariablendefinition auf beiden Systemen:
TYPE ST_FrameData :
STRUCT
(* 8 byte aligned structure, byte size := 152 byte
Define 8 Byte aligned structure to read/write BC (Bus Terminal Controller) data from x86, x64, 165 or ARM CPU platform.
TwinCAT 2 PC (x86) structures are 1 Byte - Aligned,
TwinCAT 2 BC (165) structures are 2 Byte (WORD) - Aligned,
TwinCAT 2 PC (ARM) structures are 4 Byte (DWORD) - Aligned,
TwinCAT 3 PC (x86, x64, ARM) structures are 8 Byte - Aligned *)
nFrameSize : DWORD; (* Frame byte size, member byte size := 4 byte *)
nTxFrames : DWORD; (* Tx frame number, member byte size := 4 byte *)
nRxFrames : DWORD; (* Rx frame number, member byte size := 4 byte *)
nCounter : DWORD; (* Number value, member byte size := 4 byte *)
fU : REAL; (* Floating point number, member byte size := 4 byte *)
fV : REAL; (* Floating point number, member byte size := 4 byte *)
fW : REAL; (* Floating point number, member byte size := 4 byte *)
aFloats : ARRAY[0..9] OF REAL; (* Array of floating point numbers, array byte size := 40 byte *)
sMsg : STRING; (* String variable, member byte size := 81 byte incl. string null delimiter *)
bEnable : BOOL; (* Boolean flag, member byte size := 1 byte *)
nRsv0 : BYTE; (* Reserved byte to meet the 8 byte alignment, member byte size := 1 byte *)
nCRC : BYTE; (* CRC checksum byte, member byte size := 1 byte *)
END_STRUCT
END_TYPE
PC oder CX (x86) Applikation:
Vor dem Download muss die AMS-NetID des BCs im Programmcode konfiguriert werden. Nach erfolgreichem Lesevorgang wird zuerst die Länge der Daten dann die eine einfache Checksumme überprüft. Danach werden die REAL-Elemente in das PC-Format konvertiert. Steigende Flanke an der bWrite-Variablen aktiviert den Lesebefehl und steigende Flanke an der bRead-Variablen aktiviert den Schreibbefehl.
PROGRAM MAIN
VAR
bWrite : BOOL;(* Rising edge writes data to the BC/BX (Bus Terminal Controller) *)
bRead : BOOL;(* Rising edge reads data from BC/BX (Bus Terminal Controller) *)
stTxFrame : ST_FrameData; (* Data transported from PC/CX (x86, ARM) to BC/BX (Bus Terminal Contoroller) *)
stRxFrame : ST_FrameData; (* Data transported from BC/BX (Bus Terminal Controller) to PC/CX (x86, ARM) *)
fbWrite : ADSWRITE := ( NETID := '172.17.61.50.1.1', PORT := 800, IDXGRP := 16#4020, IDXOFFS := 500, TMOUT := DEFAULT_ADS_TIMEOUT );
fbRead : ADSREAD := ( NETID := '172.17.61.50.1.1', PORT := 800, IDXGRP := 16#4020, IDXOFFS := 0, TMOUT := DEFAULT_ADS_TIMEOUT );
(* Temporary used variables *)
stTxToBC : ST_FrameData;
stRxFromBC : ST_FrameData;
i : INT;
nTxState : UDINT;
nRxState : UDINT;
nTxErrors : UDINT;
nRxErrors : UDINT;
END_VAR
(*##########################################################################################*)
CASE nTxState OF
0:
IF bWrite THEN(* Write BC/BX data *)
bWrite := FALSE;
(* Prepare/modify tx data *)
stTxFrame.nFrameSize := SIZEOF( stTxFrame );(* Set frame byte size *)
stTxFrame.nTxFrames := stTxFrame.nTxFrames + 1;(* Increment the send frame number *)
stTxFrame.nRxFrames := stRxFrame.nTxFrames;(* Report the received frame number *)
stTxFrame.bEnable := NOT stTxFrame.bEnable;(* Toggle bool flag *)
stTxFrame.nCounter := stTxFrame.nCounter + 1;(* Increment counter value *)
stTxFrame.sMsg := CONCAT( 'Message from PC/CX, counter: ', DWORD_TO_STRING( stTxFrame.nCounter ) );(* Create some string message *)
stTxFrame.fU := stTxFrame.fU + 1.2;(* Modify some floating point values *)
stTxFrame.fV := stTxFrame.fV + 3.4;
stTxFrame.fW := stTxFrame.fW + 5.6;
FOR i:= 0 TO 9 DO
stTxFrame.aFloats[i] := stTxFrame.aFloats[i] + i;
END_FOR
stTxFrame.nCRC := 0;
(* Create temporary copy of tx data *)
stTxToBC := stTxFrame;
(* Swap REAL variables to BC/BX (Bus Terminal Controller) format *)
F_SwapRealEx( stTxToBC .fU );
F_SwapRealEx( stTxToBC .fV );
F_SwapRealEx( stTxToBC .fW );
FOR i:= 0 TO 9 DO
F_SwapRealEx( stTxToBC .aFloats[i] );
END_FOR
(* Create CRC check number *)
stTxToBC .nCRC := F_CheckSum( ADR( stTxToBC ), SIZEOF( stTxToBC ) - 1 );
(* Send *)
fbWrite( WRITE := FALSE );
fbWrite( LEN := SIZEOF( stTxToBC ), SRCADDR := ADR( stTxToBC ), WRITE := TRUE );
nTxState := 1;
END_IF
1:(* Wait until ads write command not busy *)
fbWrite( WRITE := FALSE );
IF NOT fbWrite.BUSY THEN
IF NOT fbWrite.ERR THEN
nTxState := 0;
ELSE(* Ads error *)
nTxState := 100;
END_IF
END_IF
100: (* TODO: Error state, add error handling *)
nTxErrors := nTxErrors + 1;
nTxState := 0;
END_CASE
(*##########################################################################################*)
CASE nRxState OF
0:
IF bRead THEN(* Read BC/BX data *)
bRead := FALSE;
fbRead( READ := FALSE );
fbRead( LEN := SIZEOF( stRxFromBC ), DESTADDR := ADR( stRxFromBC ), READ := TRUE );
nRxState := 1;
END_IF
1:(* Wait until ads read command not busy *)
fbRead( READ := FALSE );
IF NOT fbRead.BUSY THEN
IF NOT fbRead.ERR THEN
(* Perform simple frame length check *)
IF stRxFromBC.nFrameSize = SIZEOF( stRxFromBC ) THEN (* Check frame length *)
(* Perform simple CRC check *)
IF stRxFromBC.nCRC = F_CheckSum( ADR( stRxFromBC ), SIZEOF( stRxFromBC ) - 1 ) THEN
(* Swap REAL variables to PC/CX (x86) format *)
F_SwapRealEx( stRxFromBC.fU );
F_SwapRealEx( stRxFromBC.fV );
F_SwapRealEx( stRxFromBC.fW );
FOR i:= 0 TO 9 DO
F_SwapRealEx( stRxFromBC.aFloats[i] );
END_FOR
stRxFrame := stRxFromBC;
nRxState := 0;
ELSE(* => Checksum error *)
nRxState := 100;
END_IF
ELSE(* => Invalid frame length *)
nRxState := 100;
END_IF
ELSE(* => Ads error *)
nRxState := 100;
END_IF
END_IF
100: (* TODO: Error state, add error handling *)
nRxErrors := nRxErrors + 1;
nRxState := 0;
END_CASE
BC (165) Applikation:
Nach jedem Schreibzugriff vom PC wird die Checksumme überprüft. Danach werden neue Zufallswerte generiert die zusätzlich mit einer einfachen Checksumme versehen werden.
PROGRAM MAIN
VAR
stRxFrame AT%MB500 : ST_FrameData;(* Data transported from PC/CX (x86, ARM) to BC/BX (Bus Terminal Controller) *)
stTxFrame AT%MB0 : ST_FrameData;(* Data transported from BC/BX (Bus Terminal Controller) to PC/CX (x86, ARM) *)
nReceivedFrame : UDINT;
i : INT;
nRxErrors : UDINT;
END_VAR
(* New frame from PC/CX received? *)
IF stRxFrame.nTxFrames <> nReceivedFrame THEN
(* Frame length OK? *)
IF stRxFrame.nFrameSize = SIZEOF( stRxFrame) THEN
(* Checksum OK? *)
IF stRxFrame.nCRC = F_CheckSum( ADR( stRxFrame), SIZEOF( stRxFrame) - 1 ) THEN (* => OK *)
(* Create/modify the tx data *)
stTxFrame.nFrameSize := SIZEOF( stTxFrame);(* Set frame byte size *)
stTxFrame.nTxFrames := stTxFrame.nTxFrames + 1;(* Increment the send frame number *)
stTxFrame.nRxFrames := stRxFrame.nTxFrames;(* Report the received frame number *)
stTxFrame.bEnable := NOT stRxFrame.bEnable;(* Toggle bool flag *)
stTxFrame.nCounter := stTxFrame.nCounter + 1;(* Send some counter value *)
stTxFrame.sMsg := CONCAT( 'Message from BC/BX, counter:', DWORD_TO_STRING( stTxFrame.nCounter ) );(* Create any string message *)
stTxFrame.fU := stRxFrame.fU + 10.0;(* Modify some floating point values *)
stTxFrame.fV := stRxFrame.fV + 100.0;
stTxFrame.fW := stRxFrame.fW + 1000.0;
FOR i:= 0 TO 9 DO
stTxFrame.aFloats[i] := stTxFrame.aFloats[i] + i + 3.141592;
END_FOR
stTxFrame.nCRC := F_CheckSum( ADR( stTxFrame), SIZEOF( stTxFrame) - 1 );(* Create checksum *)
ELSE(* => Checksum error *)
nRxErrors := nRxErrors + 1;
END_IF
ELSE(* => Invalid frame length *)
nRxErrors := nRxErrors + 1;
END_IF
nReceivedFrame := stRxFrame.nTxFrames;
END_IF