Modbus TCP to PLC using vb.net

S

Thread Starter

Steve Sodzi

I have finally been able to write up some visual basic code to write to a Schneider Premium PLC via TCP. The only problem is that i cannot read the response back from the PLC. It also breaks off the socket connection after 3 write attempts :(
<pre>Imports System.IO

Imports System.Net.Sockets
Imports System.Text

Public Class Form1
'"localhost", 8585)

'= serverListener.GetStream
Dim str As String
Dim mix As Integer
Dim modmsg As String
Dim rcvbytes(256) As Byte
Dim jj As String

Dim sendbyte(256) As Byte


Private Sub cmdSendmsg_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSendmsg.Click


Try
Dim serverListener As New TcpClient()
Dim newlistener As New TcpClient()
Dim readStream As Stream
Dim newstream As Stream
Dim returndata As String = ""
Dim zz As Integer = 0
Dim j, sx As Integer
Dim ct = 0
Dim joy As String
Dim snt As Integer
Dim sendbuff(256) As Byte

j = 1
serverListener.Connect(Me.txtAdr.Text, 502)
newlistener.Connect(Me.txtAdr.Text, 502)


readStream = serverListener.GetStream
newstream = serverListener.GetStream


serverListener.SendBufferSize = 1024
serverListener.ReceiveBufferSize = 1024

newlistener.SendBufferSize = 256
newlistener.ReceiveBufferSize = 256

' serverListener.Client.ReceiveTimeout = 10000;
'serverListener.Client.SendTimeout = 10;
' serverListener.s()
'' Console.WriteLine("Input Lines:")

' Me.txtMsg.Text = modmsg
str = Me.txtMsg.Text

If j = 1 Then

'Single reg
'Byte 0
sendbuff(0) = 0
sendbuff(1) = 1
sendbuff(2) = 0
sendbuff(3) = 0
sendbuff(4) = 0
'Byte 0 Function code
sendbuff(5) = 6
'Byte 1 Function code
sendbuff(6) = 1
sendbuff(7) = 6
sendbuff(8) = 0
'register offset ' %MW1=1, %MW2=2 %MW3=3
sendbuff(9) = 1

sendbuff(10) = 0
'value to write
sendbuff(11) = 6

Else
'Multiple regs
'Byte 0
sendbuff(0) = 0
'think its an ID
sendbuff(1) = 1
sendbuff(2) = 0
sendbuff(3) = 0
sendbuff(4) = 0
'Byte 0 - Depends on number of regidsters 0b, od - Think its total packet size
sendbuff(5) = 11
'Byte 1
sendbuff(6) = 1
'Byte 2 function code
sendbuff(7) = 10
'Byte 3 not sure
sendbuff(8) = 0
'Byte 4 not sure
sendbuff(9) = 0
'Byte 5 not sure
sendbuff(10) = 0
'Byte 7 no of registers
sendbuff(11) = 2
'Byte 8 twice the previous no.
sendbuff(12) = 4
'Byte 9 First val
sendbuff(13) = 0
'Byte 10 first val
sendbuff(14) = 6
'Byte 11 second val
sendbuff(15) = 0
'Byte 12 second val
sendbuff(16) = 7
End If

' Dim sendBuff As Byte() = System.Text.Encoding.ASCII.GetBytes(str)

'sendbuff = System.Text.Encoding.ASCII.GetBytes(str)

Do While (Not serverListener.GetStream.DataAvailable()) And (sx < 3)

If serverListener.GetStream.CanWrite Then
If serverlistener.connected Then
serverListener.GetStream.Write(sendbuff, 0, sendbuff.Length)
End If
'readStream.Flush()

Else
MsgBox("sorry socket writing accessible")
End If


sx = sx + 1

Loop



Do While ((ct < 1000))
If Me.chkGetres.Checked = True Then
If serverListener.GetStream.CanRead Then
Do While serverListener.GetStream.DataAvailable()
serverListener.GetStream.Read(rcvbytes, 0, CInt(serverListener.ReceiveBufferSize))
returndata = Encoding.ASCII.GetString(rcvbytes)
Me.txtResp.Text = returndata
Loop
Else
MsgBox("sorry socket reading accessible")
End If
End If



ct = ct + 1
Loop


mix = mix + 1
jj = CStr(mix)

If mix < 10000 Then modmsg = "00000000000000" & "03" & "" & jj & "0001"
If mix < 1000 Then modmsg = "00000000000000" & "03" & "0" & jj & "0001"
If mix < 100 Then modmsg = "00000000000000" & "03" & "00" & jj & "0001"
If mix < 10 Then modmsg = "00000000000000" + "03" + "000" + jj + "0001"


serverListener.Close()
Catch exp As Exception
MsgBox("Exception: " + exp.ToString())
End Try


' serverListener.Close()


End Sub




Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.txtAdr.Text = "192.168.2.5"
mix = 1000
jj = CStr(mix)



If mix < 10000 Then modmsg = "00000000000000" & "03" & "" & jj & "0001"
If mix < 1000 Then modmsg = "00000000000000" & "03" & "0" & jj & "0001"
If mix < 100 Then modmsg = "00000000000000" & "03" & "00" & jj & "0001"
If mix < 10 Then modmsg = "00000000000000" + "03" + "000" + jj + "0001"

Me.txtMsg.Text = modmsg
End Sub

Public Sub New()

' This call is required by the Windows Form Designer.
InitializeComponent()

' Add any initialization after the InitializeComponent() call.

End Sub
End Class</pre>
 
How many bytes are you actually sending in each request? I haven't got a copy of VB to test that with, but I think you are sending the whole buffer array instead of just the actual message. I don't know how the PLC would react to a string of garbage on the end of the message, but it might not like it.

I also think you have way too much code there. Try to simplify it (a lot).
 
''This is about as small as i can make it
>Imports System.Net.Sockets
<pre>
Public Class Form1
Dim clientSocket As New System.Net.Sockets.TcpClient()
Dim SendmodbusWord As String = ""

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

clientSocket.Connect("192.168.0.218", 502)

If clientSocket.Connected Then
Label1.Text = "Server Connected ..."
Else
Label1.Text = "Server Not Connected ..."
End If

modbusWord()

End Sub

Private Sub modbusWord()
'CMD = * * * *
'1 = read 0X outputs
'2 = read 1X inputs
'3 = read 4X registors
'4 = read 3X analog
'5 = write 0X output
'6 = write (1) 4x registors
'15 = write multiple 0X outputs
'16 = write multiple 4X registors

'Chr(6) = Total Byte 2 Send
'Chr(3)= cmd word (3=eg read 4x)
' ModbusCountReg = Add as many as needed
' For CMD Chr(16) add (2 pre registor),
' but Change Chr(6) by that number


Dim ModbusAddress As Long = 50 '.............. READing starting fron this register +1
Dim ModbusCountReg As Long = 50 '............ Number of register to read

SendmodbusWord = Chr(0) & Chr(0) & Chr(0) & Chr(0) & Chr(0) & Chr(6) & _
Chr(0) & Chr(3) & _
Chr(ModbusAddress \ 256) & Chr(ModbusAddress Mod 256) & _
Chr(ModbusCountReg \ 256) & Chr(ModbusCountReg Mod 256)

End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim serverStream As NetworkStream = clientSocket.GetStream()
Dim outStream As Byte() = System.Text.Encoding.ASCII.GetBytes(SendmodbusWord)
serverStream.Write(outStream, 0, outStream.Length)
serverStream.Flush()
Dim inStream(8192) As Byte
'Don't know why the smallest buffer size has to be 8192

' System.Windows.Forms.Application.DoEvents()

Dim cnt As Long
serverStream.Read(inStream, 0, CInt(clientSocket.ReceiveBufferSize))
For cnt = 1 To UBound(inStream)
If cnt = 6 Then ListBox1.Items.Add("Total byte read And Cmd")
If cnt = 8 Then ListBox1.Items.Add("CMD number")
If cnt = 9 Then ListBox1.Items.Add("Total byte read")

ListBox1.Items.Add(inStream(cnt))

If cnt = 10 Then ListBox1.Items.Add((inStream(9) * 256) + inStream(10) & "ModbusAddress +1")
If cnt = 12 Then ListBox1.Items.Add((inStream(11) * 256) + inStream(12) & "ModbusAddress +2")

Next cnt


End Sub
End Class</pre>
 
Make change to the follow line
From... 'Dim outStream As Byte() = System.Text.Encoding. ASCII.GetBytes(SendmodbusWord)
to..... Dim outStream As Byte() = System.Text.Encoding.Default.GetBytes(SendmodbusWord)
 
H

Hadi Hidayat

thanks for the code.
i have been tried it.
everything is ok until some error occurred when i read address with Start Address from 10624.

-Hadi H-

>''This is about as small as i can make
>it
>>Imports System.Net.Sockets
><pre>
>Public Class Form1
> Dim clientSocket As New
>System.Net.Sockets.TcpClient()
> Dim SendmodbusWord As String = ""
>
> Private Sub Form1_Load(ByVal sender
>As System.Object, ByVal e As
>System.EventArgs) Handles MyBase.Load
>
>clientSocket.Connect("192.168.0.218",
>502)
>
>If clientSocket.Connected Then
> Label1.Text = "Server
>Connected ..."
> Else
> Label1.Text = "Server Not
>Connected ..."
> End If
>
> modbusWord()
>
> End Sub
>
> Private Sub modbusWord()
> 'CMD = * * * *
> '1 = read 0X outputs
> '2 = read 1X inputs
> '3 = read 4X registors
> '4 = read 3X analog
> '5 = write 0X output
> '6 = write (1) 4x registors
> '15 = write multiple 0X
>outputs
> '16 = write multiple 4X
>registors
>
>'Chr(6) = Total Byte 2 Send
>'Chr(3)= cmd word (3=eg read 4x)
>' ModbusCountReg = Add as many as
>needed
>' For CMD Chr(16) add (2 pre
>registor),
>' but Change Chr(6) by that number
>
>
> Dim ModbusAddress As Long = 50
>'.............. READing starting fron
>this register +1
> Dim ModbusCountReg As Long = 50
>'............ Number of register to
>read
>
> SendmodbusWord = Chr(0) &
>Chr(0) & Chr(0) & Chr(0) & Chr(0) &
>Chr(6) & _
> Chr(0) & Chr(3) & _
> Chr(ModbusAddress \ 256) &
>Chr(ModbusAddress Mod 256) & _
> Chr(ModbusCountReg \ 256) &
>Chr(ModbusCountReg Mod 256)
>
> End Sub
> Private Sub Button1_Click(ByVal
>sender As System.Object, ByVal e As
>System.EventArgs) Handles Button1.Click
>
> Dim serverStream As
>NetworkStream =
>clientSocket.GetStream()
> Dim outStream As Byte() =
>System.Text.Encoding.ASCII.GetBytes(SendmodbusWord)
> serverStream.Write(outStream,
>0, outStream.Length)
> serverStream.Flush()
> Dim inStream(8192) As Byte
> 'Don't know why the smallest
>buffer size has to be 8192
>
> '
>System.Windows.Forms.Application.DoEvents()
>
> Dim cnt As Long
> serverStream.Read(inStream, 0,
>CInt(clientSocket.ReceiveBufferSize))
> For cnt = 1 To
>UBound(inStream)
> If cnt = 6 Then
>ListBox1.Items.Add("Total byte read And
>Cmd")
> If cnt = 8 Then
>ListBox1.Items.Add("CMD number")
> If cnt = 9 Then
>ListBox1.Items.Add("Total byte read")
>
>
>ListBox1.Items.Add(inStream(cnt))
>
> If cnt = 10 Then
>ListBox1.Items.Add((inStream(9) * 256) +
>inStream(10) & "ModbusAddress +1")
> If cnt = 12 Then
>ListBox1.Items.Add((inStream(11) * 256)
>+ inStream(12) & "ModbusAddress +2")
>
> Next cnt
>
>
> End Sub
>End Class</pre>
 
How to read multiple devices at a time?

>''This is about as small as i can make
>it
>>Imports System.Net.Sockets
><pre>
>Public Class Form1
> Dim clientSocket As New
>System.Net.Sockets.TcpClient()
> Dim SendmodbusWord As String = ""
</pre>
---- snipped by moderator -----
 
thank u very much for code. i can read 129 word in this program block.
I change this "Chr(3)" for 3x analog value this one "Chr(4)". can read with kepserver 3000001 but i can't read this program. how can i read 3000001?<pre>
> Private Sub modbusWord()
> 'CMD = * * * *
> '1 = read 0X outputs
> '2 = read 1X inputs
> '3 = read 4X registors
> '4 = read 3X analog
> '5 = write 0X output
> '6 = write (1) 4x registors
> '15 = write multiple 0X
>outputs
> '16 = write multiple 4X
>registors
>
>'Chr(6) = Total Byte 2 Send
>'Chr(3)= cmd word (3=eg read 4x)
>' ModbusCountReg = Add as many as
>needed
>' For CMD Chr(16) add (2 pre
>registor),
>' but Change Chr(6) by that number
>
>
> Dim ModbusAddress As Long = 50
>'.............. READing starting fron
>this register +1
> Dim ModbusCountReg As Long = 50
>'............ Number of register to
>read
>
> SendmodbusWord = Chr(0) &
>Chr(0) & Chr(0) & Chr(0) & Chr(0) &
>Chr(6) & _
> Chr(0) & Chr(4) & _
> Chr(ModbusAddress \ 256) &
>Chr(ModbusAddress Mod 256) & _
> Chr(ModbusCountReg \ 256) &
>Chr(ModbusCountReg Mod 256)
>

>End Class</pre>
 
My dll can do all of this and it's free. It's called Shortbus. Look up "shortbus modbus dll" on Google.
 
M

martijn pijpers

> My dll can do all of this and it's free. It's called Shortbus. Look up "shortbus modbus dll" on Google.

i use this dll and its great.....
 
Top