Transmitting structures to the PLC
Task
A structure is to be written into the PLC by Visual Basic. The elements in the structure have different data types.
Description
In order for the CPU running under Windows NT/2000 to be able to access the variables more quickly, Visual Basic (as well as other programming languages) arranges them in the main memory according to certain rules. This arrangement of variables is called alignment. This can mean that 'memory gaps' occur within a structure. Since Visual Basic and IEC1131-3 have different guidelines for the alignment, these must be filled by dummy variables.
Unfortunately, no general rule for the alignment can be defined under Visual Basic. There are however two Visual Basic functions which allow the memory assignments of a structure to be analyzed. They are the functions VarPtr() and LenB().
VarPtr() returns the address of a variable, LenB() the length in bytes that a variable (or a whole structure) occupies. The sample below illustrates the memory map of the structure in a form. This information can be used to determine where the structure has 'memory gaps'. In the sample program these are filled by the variables VarDummyX.
Attention: The function VarPtr() is only available from Visual Basic 5.
The following sketch shows the memory allocation graphically once more:
A rectangle means that the variable occupies one byte at this location. A cross represents the location of a byte that is not used by any variables. In the sample program the crosses are filled by dummy variables.
Structure declaration in Visual Basic
Type VBStruct
VarInteger As Integer
VarDummy1 As Integer
VarLong As Long
VarByte As Byte
VarDummy2 As Byte
VarDummy3 As Byte
VarDummy4 As Byte
VarDouble As Double
VarSingle As Single
End Type
Structure declaration in the PLC
After the structure in the Visual Basic program has been adapted to the alignment, the structure in the PLC program must also be supplemented:
TYPE PLCStruct
STRUCT
PLCVarInteger : INT;
PLCVarDummy1 : INT;
PLCVarLong : DINT;
PLCVarByte : SINT;
PLCVarDummy2 : SINT;
PLCVarDummy3 : SINT;
PLCVarDummy4 : SINT;
PLCVarDouble : LREAL;
PLCVarSingle : REAL;
END_STRUCT
END_TYPE
Visual Basic 6 program
Dim hVar As Long
Dim VBVar As VBStruct
'--- wird beim Starten aufgerufen ---
Private Sub Form_Load()
'--- Exception freigeben --- AdsOcx1.EnableErrorHandling = True
Call AdsOcx1.AdsCreateVarHandle("Main.PLCVar", hVar)
'--- Adressen der Variablen anzeigen ---
lblInteger.Caption = VarPtr(VBVar.VarInteger)
lblLong.Caption = VarPtr(VBVar.VarLong)
lblByte.Caption = VarPtr(VBVar.VarByte)
lblDouble.Caption = VarPtr(VBVar.VarDouble)
lblSingle.Caption = VarPtr(VBVar.VarSingle)
'--- Länge der Struktur anzeigen ---
lblVarLength.Caption = LenB(VBVar)
End Sub
'--- wird beim Beenden aufgerufen ---
Private Sub Form_Unload(Cancel As Integer)
Call AdsOcx1.AdsDeleteVarHandle(hVar)
End Sub
'--- wird vom Bediener aufgerufen ---
Private Sub cmd_write_Click()
Dim intIndex As Integer
'--- Struktur auffüllen ---
VBVar.VarInteger = CInt(txtInteger.Text)
VBVar.VarLong = CLng(txtLong.Text)
VBVar.VarByte = CByte(txtByte.Text)
VBVar.VarDouble = CDbl(txtDouble.Text)
VBVar.VarSingle = CSng(txtSingle.Text)
'--- Struktur in SPS schreiben ---
Call AdsOcx1.AdsSyncWriteIntegerVarReq(hVar, LenB(VBVar), VBVar.VarInteger)
End Sub
PLC program
PROGRAM MAIN
VAR
PLCVar : PLCStruct;
END_VAR
Optimizations
By a clever arrangement of the VBStruct member variables in the VB application the adding of the dummy bytes can be avoided. The following rule must be observed:
- Arrange the member variables in the VB structure according to the occupied memory size: first the largest and finally the smallest data types.
- The last bytes can (but do not have to) be padded to a full 4 bytes.
Optimized structure declaration in Visual Basic
Type VBStruct
VarDouble As Double ' 8 bytes
VarSingle As Single '+4 bytes
VarLong As Long '+4 byte
VarInteger As Integer '+2 bytes
VarByte As Byte '+1 byte '+1 hidden padding byte in memory
'=20 bytes (LenB result)
End Type
Optimized structure declaration in the PLC
TYPE PLCStruct
STRUCT
PLCVarDouble : LREAL;
PLCVarSingle : REAL;
PLCVarLong : DINT;
PLCVarInteger : INT;
PLCVarByte : SINT;
END_STRUCT
END_TYPE
Our optimized VB structure now starts with a double, accordingly the VB program must be changed:
'--- wird vom Bediener aufgerufen ---
Private Sub cmd_write_Click()
...
'--- Struktur in SPS schreiben ---
call AdsOcx1.AdsSyncWriteDoubleVarReq(hVar, Len(VBVar), VBVar.VarDouble)
End Sub
In addition to the changed method name, the data length to be written must be determined with the Len function and not with LenB. If you use LenB, the data will not be written to the PLC. The reason is that LenB returns a length = 20 bytes (including a padding byte in VB memory), but our structure in the PLC is only 19 bytes long.
Len vs. LenB
- With user-defined types, Len returns the size as it will be written to the file.
- With user-defined types, LenB returns the in-memory size, including any padding between elements.
Language / IDE | Unpack sample program |
---|---|
Visual Basic 6 |