Delphi – exchange data with Siemens PLC
Other interesting possibilities for using LibNoDave library is NoDave component for Delphi API. The Unit NoDaveComponent implements the class TNoDave, which encapsulates the access to the libnodave.dll. With TNoDave and libnodave.dll it is very easy to read and write data from and to a S7 PLC. TNoDave uses a worker-thread for asynchronous connecting with the PLC.
This source files which are necessary to connect PLC:
- nodave.pas – that unit includes variables, conventions (where are name of function, name of file, where function is located and information on how it to use) and functions itself.
- nodavecomponent.pas – NoDave component.
- libnodave.dll – that is communication library itself.
Add nodave.pas file in the Delphi project and copy libnodave.dll file in the same directory. But nodavecomponent need to register. How to install a third-party Delphi component you can read in the site: Installing a single source Delphi component into an existing Package.
Structure of the application:
Source of the example of the Delphi application available for download.
After the first glance is useful. Separate a worker-thread for asynchronous connecting with the PLC. Make a list of the required data, enabling the driver and you have a date. But if necessary to read data from different locations and of different types, then may be useful to use the DLL directly.
Example of using LibNoDave library directly.
This source files which are necessary to connect PLC:
- nodave.pas
- libnodave.dll
Usage of the functions connect, disconnect, read and write data:
– Connection
procedure TMainForm.Connect; <pre>Var ComName:Array[0..20] of Char; Fds:_daveOSserialType; S:String; i:Integer; begin S:=Trim(IPAddress); For i:=1 To Length(S) Do ComName[i-1]:=S[i]; ComName[Length(S)]:=#0; fds.rfd:=openSocket(102,COMname); fds.wfd:=fds.rfd; verbinding := false; if (fds.rfd>0) then begin dcIn:=daveNewInterface(fds, 'IF1',0,ConnProtocol, MPISpeed); dcIn^.timeout:=IntfTimeout; if (daveInitAdapter(dcIn)=0) then begin dc :=daveNewConnection(dcIn,2, CPURack, CPUSlot); if (daveConnectPLC(dc)=0) then begin verbinding := true; end; end; end; end; procedure TMainForm.Disconnect; begin if connected then begin daveDisconnectPLC(dc); daveDisconnectAdapter(dcIn); connected := false; end; end;
– Write data to PLC
//Write S7 FLOAT procedure TMainForm.WriteDouble(varR:single); var Res:LongInt; VarD : longint; begin VarD := daveToPLCfloat(varR); res := daveWriteBytes(dc, daveDB, ValueAdresDb, ValueAdresNum, 4, @varD); end; //write DINT, DWORD, INT, WORD procedure TMainForm.WriteInt(varI : integer, type : boolean); var varW : integer; varC, varD : word; Res:LongInt; begin if type = true then begin varW := daveSwapIed_32(varI); res := daveWriteBytes(dc, daveDB, ValueAdresDb, ValueAdresNum, 4, @varW) end else begin varC := varI; varD := daveSwapIed_16(varC); res := daveWriteBytes(dc, daveDB, ValueAdresDb, ValueAdresNum, 2, @varD) end; end;
– Read data from PLC
procedure TMainForm.ReadData; var Res:LongInt; i : integer; value1 : Array[0..3] of double; Begin if verbinding then begin //Read 3x float values begin address DB110.DBD12 res := daveReadBytes(dc, daveDB, 110, 0, 12, NIL); For i := 0 to 2 do value[i] := daveGetFloat(dc); Label1.Caption := Format('%f', [value1[0]] ); Label2.Caption := Format('%f', [value1[1]] ); Label3.Caption := Format('%f', [value1[2]] ); //Read BYTE res := daveReadBytes(dc, daveFlags, 0, 24, 1, NIL); Label4.Caption := IntToStr(daveGetU8(dc)); //Read WORD res := daveReadBytes(dc, daveFlags, 0, 16, 2, NIL); Label5.Caption := IntToStr(daveGetU16(dc)); //Read DWORD res := daveReadBytes(dc, daveFlags, 0, 2, 4, NIL); Label6.Caption := IntToStr(daveGetU32(dc)); end end;
During development of PLC control software often requires testing operation of the PLC software. Therefore necessary to simulate operation of the equipment controlled by PLC.
The purpose of the example, simulate and visualize the operation of devices connected to the PLC. Source of the example:
The structure of Delphi example is very simple. First application reads communication settings, then connect to PLC via ISO on TCP protocol. If connection is successful, then timer periodically reads outputs data from PLC and update user interface of the application, makes manipulations with bits and writes inputs data to PLC.
Reading from PLC outputs, simulation, manipulation with bits and writing inputs to PLC.
Step 1. Reading digital outputs: With function DaveReadBytes(dc, daveOutputs, 0, 0, 4, nil) read data from outputs memory area of the PLC in the buffer as a sequence of bytes and with function “daveGetU8(dc)” read out of the buffer, the data with the byte format.
Step 2, 3 and 4: Manipulation with bits. For manipulation of bits use MatBit8.pas unit. With functions “SetBit(i)” or “ClrBit(i)” write “1″ or “0″ in the appropriate bit in the byte of the “inputDG” array of bytes depending on the bit in the byte of output array.
Step 5. Writing digital inputs: With function DaveWriteBytes(dc, daveOutputs, 0, 0, 4, @inputsDG) write sequence of bytes (4) to PLC.
Simulation analog values and writing to PLC analog inputs.
varW : integer;
varW := daveSwapIed_32(value);
res := daveWriteBytes(dc, daveInputs, 0, Address, 4, @varW);
Example of the full simulations of Waste Water Purification Installation of the oil company in Rotterdam. Simulation van motors, pumps, valves, process, level of the tanks, engine electric current and speed, flow control. Connection with two Siemens 317 PLCs.
Example of the full simulations of RSP Uniwax rotary printing machine of Vlisco company in Netherlands. Simulation of the HMI and inputs. Visualization of the outputs and control processes.
April 23, 2012 at 6:08 pm |
Hi Alex,
Congratulations on your projects.
I am testing your project Skidsim, but I get an error:
ScommDll.dll missing, and without this file can not continue.
What I can do? Can you help me?
Thank you very much and I hope your answer.
April 24, 2012 at 4:31 am |
Hi Luis,
Open page “Delphi, VB – SAIA PLC communication library” Download and install Scomm_SP1.4_130.zip library in the default directory “C:\Program Files\Saia-burgess\SAIA Communication Driver\1.4\”
Next: you have two options:
1. Open Delphi project options and set Output directory to “C:\Program Files\Saia-burgess\SAIA Communication Driver\1.4\”
2. Or open directory “C:\Program Files\Saia-burgess\SAIA Communication Driver\1.4\” and copy all DLLs to the directory where your exe file is situated.
Success.
April 24, 2012 at 2:33 pm |
Hi Alex,
Thank you very much for responding so quickly.
I have followed the steps as you have told me, but I have another error:
“Project raised exception class Exception SkidSim.exe with message ‘Can not open AVI”. Process stopped. Use Step or Run to continue. ”
The. AVI I can see well with Video Player. I think this error is problem of my computer. I’ll try the project on another computer.
Thank you very much and I’ll tell you how it went
April 24, 2012 at 5:28 pm |
Hi Luis,
No, problem is not with your computer, problem with location of the AVI file “Skid6.avi”. The location was identified as “common” directory in your computer, this file does not exist in this directory. Copy the file Skid6.avi to directory: “C: \ Program Files \ Common Files \ Skid \”
or change variable CommonDir := PrBufReg.ReadString(‘Dir’,’CommonDir’,’C:\Program Files\Common Files\Skid\’);
to
CommonDir := PrBufReg.ReadString(‘Dir’,’CommonDir’,’YOUR DIRECTORY’);
and copy a file Skid6.avi to the YOUR DIRECTORY.
Enjoy.
April 25, 2012 at 6:00 pm |
Now everything is fine and the application is running but I can not communicate with the PLC. I can not communicate with socker. I can not communicate with “PGU” (I guess “MPI”).
My configuration in PLC:
Rack = 0, slot = 2, Port = COM1, PLC Address = 2, Local = 0. IP = 192.168.1.50
My settings in Skid-Sim:
CPU Number = 2, S-Bus Station = 0, Port = COM2, Number of retry = 0, local = 0.
Many combinations I’ve tried but nothing.
With Simatic MPI and Ethernet works well.
I really just want a small example to communicate with Delphi S7 protocol “MPI”. Could you help me?
Thank you very much and hopefully you can help me.
April 25, 2012 at 7:14 pm |
Hello Luis,
I think you’re wrong example considered.
SAIA has two kinds of PLCs:
1. SAIA PCD. This PLC used PG5 software and for data exchange must use SAIA communication library. Skid example created for PCD PLC and not applicable for Siemens PLC. PCD PLC has SBUS Station, CPU Number… and not rack, slot, plc address….
2. SAIA – Siemens. This PLC using Siemens Step 7 software and for data exchange must use LibNoDave communication library.
For programming with LibNoDave driver you can use Delphi, Java or VB/C#.net programming languages. This PLC has rack, slot and not SBUS Station, CPU Number…
If you using Siemens or Saia-Siemens PLC then take a look for RSP Uniwax rotary printing machine example for Delphi programming language or short example above on this page.
Communication protocol with Siemens PLC:
1. MPI COM – easy for implementing, but MPI-COM adapter need.
2. MPI USB – difficult for implementing and very difficult with Microsoft USB. Need MPI-USB adapter.
3. ISO Ethernet – easy for implementing, but hardware need CP 343/443 card.
I recommended to you try ISO Ethernet:
In the PC(step 7) –> Brodcom 440x protocol with IP = 192.168.1.51.
In the PLC –> IP = 192.168.1.50
In the PC(Delphi apl.) –> Rack = 0, slot = 2, IP = 192.168.1.50, COM is not important.
Success.
April 27, 2012 at 2:17 pm |
Hi Alex,
The first thing I do is say thank you for your help and advice.
You have reason to use TCP-IP, I know that is the future but now I need to make a small application in MPI.
I´ll See the examples you tell me and I’ll tell you the results.
Once again thank you.
April 27, 2012 at 2:32 pm |
Hi Alex,
How I can I download the whole project “RSP Uniwax rotary?”. When you click, so you can only download the files one by one (and some can not be downloaded).
Thank you
April 28, 2012 at 12:21 am |
Hi Luis,
I have sources for download added.
Success.
April 28, 2012 at 2:45 pm
Hi Alex,
Again, thank you very much for everything.
The program download works perfectly.
With people like you is easier to learn …
Regards and thanks for your time and effort.
September 3, 2012 at 3:07 pm |
Hi Alex,
I like your page. I found a lot of usefull information, but I have problem running your program. At line
“fds.rfd:=openSocket(102,COMname);” I get result = 0 and connection to PLC is not made.
I have also tried the program which come with LibNoDave – NoDaveDemo.exe which connect to my PLC and I can read data.
Can you please give me some pointers what to look to overcome this problem. I use XE2 with Win7 and I try to connect to S7-300.
Thank you for your help.
Matija
September 20, 2012 at 10:12 pm |
Hi Matija,
I have zip file with source for Delphi 2005 added in the blog.
Take a look.
September 21, 2012 at 9:47 am
Hi Alex,
Thank you for your replay. Meanwhile I succesfully manage to connect to PLC.
I replace your code:
S:=Trim(IPAddress);
For i:=1 To Length(S) Do ComName[i-1]:=S[i];
ComName[Length(S)]:=#0;
fds.rfd:=openSocket(102,COMname);
with
var Address : AnsiString;
Address := IPNaslov + #0;
Fds.Rfd := OpenSocket(Port, @Address[1]);
and it works.
Regards Matija
September 21, 2012 at 10:01 am |
Hi Alex,
I have another question. Is it possible to read/write single bit into PLC. I see on your blog that libnodave has Readbits and Writebits, but all my attempts was unsuccessful. Right now I read byte, change bit and write back. Do you maybe have one real life example?
Regards,
Matija
September 22, 2012 at 9:23 am |
Hi Matija, Single bit into PLC is possible to read and write. I do not use Delphi anymore, because in many cases necessary, SimPLC instead of the real PLC. With Delphi advent of the Siemens S7 version 5.5 (SimPLC version 5.4) with the COM component SimPLC is not possible anymore.
This is an example write bit in the PLC with VB.Net. Delphi and VB.Net uses the same LibNoDave.DLL eventually.
Private Sub WriteInputConsole(ByVal InputNum As Byte, ByVal BitNum As Byte, ByVal Par As Boolean)
Dim Adr As Integer
Dim pData(1) As Byte
If Par Then
pData(0) = 255 ‘write 1
Else
pData(0) = 0 ‘write 0
End If
If Connection Then
Adr = InputNum * 8 + BitNum
res = dc.writeBits(libnodave.daveInputs, 0, Adr, 1, pData)
Else
MsgBox(“No connection with PLC!”)
End If
End Sub
OR res = dc.writeBits(libnodave.daveFlags, 0, Adr, 1, pData)
Regards,
Alex
October 24, 2012 at 11:28 am
Hi Alex,
Thank you for information. It was very usefull and now I manage to write single bit to PLC.
Here is code for Delphi (Libnodave)
Res := DaveWriteBits(DC, DaveDb, NrDB, (8 * StartByte + PosBit), 1, @DummyI);
The difference from WriteByte is Adr structure which I get it from your code. Thank you for help and support.
Kind Regards,
Matija
October 5, 2012 at 2:06 pm |
Dear Alex,
I’m really impressed from your work. I need some help/advise. I’m trying to use delphi component that is part of the project. My task is to read different values from different DBs with different structure. As a base I used the demo , but I got “false values” only I manage to succeed when I read one by one the values in sequence of of 100ms. Other time I manage when I read whole DB, but only one. If i change to next db then I got wrong values.
Can you help me?
February 28, 2013 at 4:53 pm |
Hi Sevdalin,
To read data from PLC you must know exactly contents of the data block and use appropriate functions for boolean, integer, double integer or real data.
December 14, 2012 at 10:03 am |
Hi Alex,
Im new to the communication of Delphi and Siemens PLC and I would like to know some opinion from you and you have lot of experience.
What is exactly the reason to use LibNoDave or any direct connection instead OPC? If im not wrong OPC is usefull when you have many applications conneting to same PLC, right? Otherwise Libnodave is the optimal solution also due to no costs compared with an OPC Server license?
Do you know is there are advantages fro 3rd party libraries instead libnodave? For example there is AGlink from Deltalogic, but their price is very high. Thx for any feedback
February 28, 2013 at 4:08 pm |
Hi Andre,
The reason is money, LibNoDave is free, no license, no support.
May 3, 2013 at 8:43 am |
Hi Alex, just one more question. I saw that you use an old version of LIBNODAVE.DLL (back from 2005), is there any particular reason?
October 30, 2013 at 8:31 pm |
Hi Andre, It was fortuitously.
July 13, 2013 at 2:11 pm |
Hi Alex,
I have one situation. I have two PLC connected between with MPI connection. I have NL 50-MPI (Konverter Ethernet TCP/IP to S7-MPI).
Can I connect to each one of them using ISO over TCP?
Port is differrent 1099 instead 102 and I don’t know where to select from which PLC I am addressing?
Thank you for your help, regards,
Matija
October 30, 2013 at 8:25 pm |
Hi Matija,
You can connect 2 or more PLC with different IP addresses from the same application.
Regards.
October 30, 2013 at 8:44 pm
Hi Alex,
Thank you for reply, your answer is correct, but in my situation where I have two PLC connected between with MPI connection, they don’t have IP addresses. On one of them I would like to use this NL 50-MPI (Converter Ethernet TCP/IP to S7-MPI). So this PLC will have IP address, but have to reach the second PLC over first using MPI connection?
Thank you for your help, regards,
Matija
November 6, 2013 at 10:24 pm |
Muy bueno, gracias…
May 25, 2014 at 5:55 pm |
How Can I Communicate with S5 ?
June 17, 2014 at 2:23 pm |
Hi, your code and the nodave.h are not Delphi Unicode compatible. You must replace any reference to char and pchar with AnsiChar and pAnsiChar in nodave.h.
Then this code can connect succesfully to a PLC (TCP/ISO):
function TestConnection:boolean;
var
fds: _daveOSserialType;
begin
result:=false;
fds.rfd:=openSocket(102, ‘192.168.1.100’);
fds.wfd:=fds.rfd;
if (fds.rfd<=0) then
raise Exception.Create('Opensocket failed!');
di :=daveNewInterface(fds, 'IF1',0,daveProtoISOTCP, daveSpeed187k);
di^.timeout:=5000000;
if (daveInitAdapter(di)0) then
raise exception.Create(‘Init Adapter failed!!’);
dc:=daveNewConnection(di, 2, 0, 2);
if (daveConnectPLC(dc)0) then
raise exception.Create(‘PLC Connect failed!’);
result:=true;
end;
There is also a TNoDaveComponent that need to be updated.
June 27, 2014 at 4:11 pm |
HI,
we have try to connect plc by com port but com is connected and PLC not connect with computer.
fds.rfd = libnodave.setPort(“COM3”, “9600”, 8) ‘ (102, IP)
fds.wfd = fds.rfd
If fds.rfd > 0 Then ‘ if step 1 is ok
di = New libnodave.daveInterface(fds, “IF1”, 0, libnodave.daveProtoISOTCP, libnodave.daveSpeed187k)
di.setTimeout(1000000) ‘ Make this longer if you have a very long response time
res = di.initAdapter
‘
If res = 0 Then ‘ init Adapter is ok
dc = New libnodave.daveConnection(di, 0, rack, slot) ‘ rack amd slot don’t matter in case of MPI
res = dc.connectPLC()
If res = 0 Then
Connection = True
ToolStripStatusLabel1.Text = “Connected ” + IP
End If
End If
End If
res is display -1 values after res = dc.connectPLC()
please help us
Thanking you
August 27, 2014 at 7:21 am |
Hi Alex,
Could you please clarify some questions.
I downloaded component LibNoDave with http://sourceforge.net/projects/libnodave/.
It has last update 2014-05-22.
I tried to install component, but Delphi XE6 can’t find the nodave.pas file.
How I can get this file?
Also, I tried to convert nodave.h to nodave.pas, but it was not success.
Thank you for your help!
Best Regards
Yevgeniy.
August 27, 2014 at 10:51 am |
I found solution for this problem.
Need to take nodave.pas from folder pascal and to change type of variables. According rule below.
from char to ansichar
from string to ansistring
from pchar to pansichar
Thanks,
Best Regard
Yevgeniy.
March 15, 2016 at 7:26 pm |
Hi Alex,
I have a problem with disconnecting from PLC.
I use your code to do it:
procedure TMainForm.Disconnect;
begin
if connected then
begin
daveDisconnectPLC(dc);
daveDisconnectAdapter(dcIn);
connected := false;
end;
end;
With a program I create a connection to PLC, then I disconnect.
I repeat this two more times with success (together 3 times), but the fourth attempt to connect failed. If I close the program and open it again I can connect and disconnect again 3 times.
I also try to add
DaveDisconnectPLC(dc);
CloseSocket(Port);
ClosePort(Port);
with no success.
Do you have any idea how to solve this.
Thanks,
Best Regards,
Matija
March 15, 2016 at 7:54 pm |
Hello
I find the solution.
I add at the end
CloseSocket(Port);
ClosePort(fds.rfd);
and it works.
Regards,
Matija