Free Alarm Logging Software?

Or..... just use the WinCC you allready have...

ModbusRTU is supported in siemens 200 and 1200, TCP in 1200 but 300 needs a driver like you said. And AdvancedHMI doesnt have a siemens driver (only reason I never use it).

Depending of the version and licences, you could use Wincc as OPC server and link them that way...

Or just check the "will be logged" option I told you about earlier...
 
Or..... just use the WinCC you allready have...

ModbusRTU is supported in siemens 200 and 1200, TCP in 1200 but 300 needs a driver like you said. And AdvancedHMI doesnt have a siemens driver (only reason I never use it).

Depending of the version and licences, you could use Wincc as OPC server and link them that way...

Or just check the "will be logged" option I told you about earlier...

Our WinCC system is in the process of being upgraded. It's got lots of custom code in it which writes data between excel sheets and the system which has all been done in german. Error messages are created/edited in excel and a macro is run to import it into WinCC. So if I make any amendments to the WinCC then it will be lost when the new system arrives. Besides, not all our machines have WinCC and not all machines are Siemens.
 
Our WinCC system is in the process of being upgraded. It's got lots of custom code in it which writes data between excel sheets and the system which has all been done in german. Error messages are created/edited in excel and a macro is run to import it into WinCC. So if I make any amendments to the WinCC then it will be lost when the new system arrives. Besides, not all our machines have WinCC and not all machines are Siemens.

Ok.. but you can still try to use them as opc servers..
 
If I am interpreting this correctly, you want to monitor 500 bits. If this is the case, the DataSubscriber will not be the best solution. The DataSubscriber was created allow subscribing to a small number of items without the need to write code.

I will give you a lower level solution to subscribe to 500 elements directly to the driver. The Modbus driver does not support subscribing to arrays, so an individual subscription has to be created for each item.

Start by right clicking a blank area in your MainForm and select View Code. Then paste the following code:
Code:
    Private SubscriptionID(500) As Integer
    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Try
            For i = 1 To 500
                SubscriptionID(i) = ModbusTCPCom1.Subscribe("0000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
            Next
        Catch ex As Exception
            Dim dbg = 0
        End Try
    End Sub

    Private LastValues(500) As String
    Private Sub ModbusTCPCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs)
        Dim index As Integer = CInt(e.PlcAddress)

        '* Make sure data has been return
        If e.ErrorId = 0 AndAlso e.Values.Count > 0 Then
            '* Did the value change?
            If e.Values(0) <> LastValues(index) Then
                '* Save this value for the next roudn trip comparison
                LastValues(index) = e.Values(0)

                '* Is it true?
                If String.Compare(e.Values(0), "True", True) = 0 Then
                    Try
                        '* Place your code here that you want to do when a bit has gone true
                        'MsgBox("Item " & e.PlcAddress & " has went true")
                    Catch ex As Exception
                        '* Show the error
                        MsgBox(ex.Message)
                    End Try
                End If
            End If
        End If
    End Sub

This may seem a bit complicated because it is directly subscribing to the driver, but it is the most efficient method.

From here you can fill in the area with the code such as your database writing.

Hey Archie, I wondered if I can bug you for a little advice on this.

If you recall I was wanting to monitor data from a Siemens PLC. As the 300 series CPU's required a modbus licence, I decided to use a spare 1200 CPU (which has modbusTCP capability built in) as an interface between the 315CPU and the AdvancedHMI.

I've had alsorts of trouble getting that working but have got there in the end.

Basically, a block in the CPU will read a database and transfer it into the Modbus Holding Register. I've got my rig all set up and have all the comms up and running and tonight put it to the test to record the error bits from the datablock.

Here's what I found though.... in trials I was using the Do-More-PLC simulator to give an output to the modbus and it was happily recording an error into the datablock using your code you sent me above.

Now, I'm writing to the holding register and not the input register, hence your code isn't scanning for changes there.

I thought that changing this line:
SubscriptionID(i) = ModbusTCPCom1.Subscribe("0000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
to "4000" & CStr(i) might work (as 40001 - 49999 is the holding register address) but it does not. I know that the holding register addresses is stored as words and not boolean bits, whereas the input register is boolean bits (or coils).

Any ideas?

I'm looking at another option in the PLC to write to output coils (Siemens Q0.0 = Modbus 00001 - tried and tested and works) but it is not possible to do a move from DB to Q area (can do DBD to QD and repeat to cover all the area required but that will take a lot of repetitive programming - especially if when I expand I want to make use of the whole 8000+ modbus inputs - thats about 250+ Double word move commands :eek::eek::eek:)
 
Last edited:
Now, I'm writing to the holding register and not the input register, hence your code isn't scanning for changes there.

I thought that changing this line:

to "4000" & CStr(i) might work (as 40001 - 49999 is the holding register address) but it does not. I know that the holding register addresses is stored as words and not boolean bits, whereas the input register is boolean bits (or coils).

Any ideas?
When you say it does not work, what result are you getting?

Reading the 4xxxx series is going to return a signed 16 bit integer. If you want to look at each individual bit, then you will need to convert from an integer to booleans values.
 
Capture-2.png


Here is the screen grab. When I turn the comms on, it crashes with this....

You can see the index value which is out of range (40001) which is where I've changed that line of code I mentioned in previous post.

And I think it is because I will need to convert from integer to boolean. But how do I do that?
 
Now that you are using 4xxxx series addresses, the index variable needs to be calculated differently. You need to ignore the "4" like this:


Dim index as Integer=Cint(e.PLCAddress.substring(1))
 
When you say it does not work, what result are you getting?

Reading the 4xxxx series is going to return a signed 16 bit integer. If you want to look at each individual bit, then you will need to convert from an integer to booleans values.

Thanks Archie...

So just to confirm I have this correct, I leave ModbusTCPCom1.Subscribe("0000" & CStr(i) as is and I change your code to this (See bold part below)?

Code:
 Private SubscriptionID(500) As Integer
    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Try
            For i = 1 To 500
                SubscriptionID(i) = ModbusTCPCom1.Subscribe("0000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
            Next
        Catch ex As Exception
            Dim dbg = 0
        End Try
    End Sub

    Private LastValues(500) As String
    Private Sub ModbusTCPCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs)
        [i][B]Dim index As Integer = CInt(e.PlcAddress.substring(1))[/B][/i]

        '* Make sure data has been return
        If e.ErrorId = 0 AndAlso e.Values.Count > 0 Then
            '* Did the value change?
            If e.Values(0) <> LastValues(index) Then
                '* Save this value for the next roudn trip comparison
                LastValues(index) = e.Values(0)

                '* Is it true?
                If String.Compare(e.Values(0), "True", True) = 0 Then
                    Try
                        '* Place your code here that you want to do when a bit has gone true
                        'MsgBox("Item " & e.PlcAddress & " has went true")
                    Catch ex As Exception
                        '* Show the error
                        MsgBox(ex.Message)
                    End Try
                End If
            End If
        End If
    End Sub
 
The one line you changed is correct, but if you are going to pack your bits into the 4xxxx series registers, it gets a little more involved to extract them.

You would use this

SubscriptionID(i) = ModbusTCPCom1.Subscribe("4000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)


You would then need a way to extract the bits, like this:
Code:
    Private Function ExtractBitsFromInt(ByVal v As Int16) As Boolean()
        Dim bytes() As Byte = BitConverter.GetBytes(v)
        Dim b As New BitArray(bytes)

        Dim bits(15) As Boolean
        b.CopyTo(bits, 0)

        Return bits
    End Function

So then you need to extract and compare each bit within the 4xxxx register. Your new code will look something like this:
Code:
    Private LastIntValues(100) As String
    Private Sub ModbusTCPCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs)
        Dim index As Integer = CInt(e.PlcAddress.substring(1))

        '* Make sure data has been return
        If e.ErrorId = 0 AndAlso e.Values.Count > 0 Then
            '* Did the value change?
            If e.Values(0) <> LastIntValues(index) Then
                '* We need to extract the individual bits, then see if any of them changed from False to True
                Dim OldBits() As Boolean = ExtractBitsFromInt(Convert.ToInt16(LastIntValues(index)))
                Dim NewBits() As Boolean = ExtractBitsFromInt(Convert.ToInt16(e.values(0)))
                '* Save this value for the next round trip comparison
                LastIntValues(index) = e.Values(0)

                '* Loop through the 16 bits in this register to see if any went from False to True
                For BitNumber = 0 To 15
                    If NewBits(BitNumber) And Not OldBits(BitNumber) Then
                        Try
                            '* Place your code here that you want to do when a bit has gone true
                            MsgBox("Item " & (index * 15) + BitNumber & " has went true")
                        Catch ex As Exception
                            '* Show the error
                            MsgBox(ex.Message)
                        End Try
                    End If
                Next
            End If
        End If
    End Sub
 
The one line you changed is correct, but if you are going to pack your bits into the 4xxxx series registers, it gets a little more involved to extract them.

You would use this

SubscriptionID(i) = ModbusTCPCom1.Subscribe("4000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)


You would then need a way to extract the bits, like this:
Code:
    Private Function ExtractBitsFromInt(ByVal v As Int16) As Boolean()
        Dim bytes() As Byte = BitConverter.GetBytes(v)
        Dim b As New BitArray(bytes)

        Dim bits(15) As Boolean
        b.CopyTo(bits, 0)

        Return bits
    End Function

So then you need to extract and compare each bit within the 4xxxx register. Your new code will look something like this:
Code:
    Private LastIntValues(100) As String
    Private Sub ModbusTCPCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs)
        Dim index As Integer = CInt(e.PlcAddress.substring(1))

        '* Make sure data has been return
        If e.ErrorId = 0 AndAlso e.Values.Count > 0 Then
            '* Did the value change?
            If e.Values(0) <> LastIntValues(index) Then
                '* We need to extract the individual bits, then see if any of them changed from False to True
                Dim OldBits() As Boolean = ExtractBitsFromInt(Convert.ToInt16(LastIntValues(index)))
                Dim NewBits() As Boolean = ExtractBitsFromInt(Convert.ToInt16(e.values(0)))
                '* Save this value for the next round trip comparison
                LastIntValues(index) = e.Values(0)

                '* Loop through the 16 bits in this register to see if any went from False to True
                For BitNumber = 0 To 15
                    If NewBits(BitNumber) And Not OldBits(BitNumber) Then
                        Try
                            '* Place your code here that you want to do when a bit has gone true
                            MsgBox("Item " & (index * 15) + BitNumber & " has went true")
                        Catch ex As Exception
                            '* Show the error
                            MsgBox(ex.Message)
                        End Try
                    End If
                Next
            End If
        End If
    End Sub

Thanks Archie, I'm not back on site until Thursday so will give this a try then.
For now, I'm using the old code and in the PLC I'm moving my data to the Modbus inputs. I'm having to use many move commands (16 so far, just for the 500 test bit's I'm playing with).
It's working a treat! Obviously if I continue this way to expand and integrate more machines, and want to make use of the 8000+ modbus inputs available, then I'v a lot more move commands to add!
 
Archie,

I got this working quite well! It needs a bit of tweaking here and there but I've got a good base now! Thank you!

Just a quick question...

the original code read 500 bits.
Code:
For i = 1 To 500
SubscriptionID(i) = ModbusTCPCom1.Subscribe("0000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
Next

Now that it has changed to:
Code:
For i = 1 To 500
SubscriptionID(i) = ModbusTCPCom1.Subscribe("4000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
Next

Does this mean it is now reading 500 Words instead of Bits?
 
Now that it has changed to:
Code:
For i = 1 To 500
SubscriptionID(i) = ModbusTCPCom1.Subscribe("4000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
Next

Does this mean it is now reading 500 Words instead of Bits?
Yes, that code is subscribing to 500 words.
 
Yes, that code is subscribing to 500 words.

What is limiting the maximum read address?

I've left "For i = 1 To 500" as is, which should give me 8000 bits of data to work with. But it seems to max out at 2447 bits of data (Integer 152 - bitnumber 15)

I tried upping it to "For i = 1 To 1000" but still limited at the same address.

What is limiting me here?

UPDATE: I managed to up the max reading to 2703 bits of data (Integer 168:bitnumber15) by setting the MudBusTCPCom1 setting MaxReadGroupSize from 20 to 43. If I set it any higher, it doesn't work at all.
 
Last edited:
Are you sure the PLC allows that high of an address? Try starting with a new blank AdvancedHMI project, add the driver, then add a BasicLabel. Set PLCAddressValue to 40154 then run the application. If there is a problem, the BasicLabel should show an error.
 
Are you sure the PLC allows that high of an address? Try starting with a new blank AdvancedHMI project, add the driver, then add a BasicLabel. Set PLCAddressValue to 40154 then run the application. If there is a problem, the BasicLabel should show an error.

Tried this. Working OK. I took the BasicLabel address up to 40169 which takes me to the very end (currently) of the data I'm trying to send. If I edit the last bit of data I can see the value change in the BasicLabel. I then went on and expanded my Datablock to 270 words long. Addressed the BasicLabel to 40270 and changed the value. It can be read OK.

I've got my message box active and set as:
Code:
 MsgBox ("Item " & ((Index * 16) + Bitnumber) & "has went true" & index & ":" & bitnumber)

This shows me the integer and the bitnumber when I set the bit in the PLC high. Works right up until index168:bit15 but not after.

And doing the test you suggested above shows data is able to be read from later indexes, confirming PLC is sending data. (Last bit sent is equivalent to index169:bit8)

Something here is limiting me and I can't work out what it is...o_O

UPDATE:

Just looking back at this code
Code:
For i = 1 To 500
SubscriptionID(i) = ModbusTCPCom1.Subscribe("4000" & CStr(i), 1, 100, AddressOf ModbusTCPCom1_DataReceived)
Next

I had CStr(i), 1, 100, ......

I've changed to CStr(i), 1, 500, and seem to be able to read more data.

Is this correct?

I'm imagining this is telling the subscription to cycle between 40001 and 40500??
 
Last edited:

Similar Topics

Hi everyone, I'm in search of software for electrical drawings, preferably free but also interested in paid options. Any recommendations or...
Replies
33
Views
1,674
Hello, S7-200 is installed with dot matrix printer. its printer is not working. now I have changed the printer. Problem in new printer is that...
Replies
0
Views
218
We are to develop a first application in Codesys. It will contain motion (Softmotion) with drives on Ethercat (CSP mode). Off course there will be...
Replies
2
Views
939
Just started working with some HART loops and I'm trying out Pactware.I'm using Krohne and it works just fine recognizing my modem. I downloaded...
Replies
9
Views
1,453
Hi, There's a problem I face with upgrading the OS from XP which has the Step 7 Lite installed to windows 10. As I can't use a cracked version of...
Replies
2
Views
639
Back
Top Bottom