Sign in to follow this  
Followers 0
JesúsRodríguez

AB PLC data vía C++ function

7 posts in this topic

Hi everybody For several days I have been trying to read and write data from an Allen Bradley PLC using a C++ function executed externally. Has anybody done this? I would appreciate any sample code you have so I can test it. Thanks.

Share this post


Link to post
Share on other sites
Hello, What PLC model? Hardware connection type?

Share this post


Link to post
Share on other sites
Right now im trying with RSLogix Emulate 5000, and RSLinx Classic Gateway. I could use a Control Logix as well or a micrologix 1500. For simplicity I use the emulator, and OPC communication works fine. That´s why im wondering around OPC sites, but still nothing working, just some places where they sell some Toolkits.

Share this post


Link to post
Share on other sites
Have you seen the Opener open source EtherNet/IP adapter stack? TuxEIP is another package you may like. Sourceforge likely has a number of them to get you started. There are also guides on how to access data from a Logix PLC using EtherNet/IP. Any of these would do - but if this is for production, I would use a kit someone else supports. OPC libraries work too... if it's easier to deal with these middle layers.

Share this post


Link to post
Share on other sites
Hmm, not quite what i was thinking about, Billy. But probably it´s even better. Thanks!!

Share this post


Link to post
Share on other sites
Did this with Windows 7 many moons ago. If I remember correctly, I used Visual Studio sample code from Kepware and figured out how to address the canonical data types with the Kepware OPC server first. Then I made subroutines that would query the canonical data type for any of the read write functions. Really interesting how much is going on in the background for an HMI when reading and writing to an analog value. I posted a program here (4 or 5 years ago) called UNI LOOP which was a universal loop controller. It would work with RSLinx Classic and Kepware OPC servers. It had drop down menus for all of the tags (e.g. PV SP CV locked auto manual) and drop down menu's for which type of OPC server you plan to use. I posted it for free and nobody really understood what it was for or even tried it. It would support multiple instances so I could open it up ten times or more and run ten different loops in an Allen Bradly Compact Logix or Control Logix PLC. Heck I showed a co-worker at the University of Chicago and he couldn't believe it. Here on my desktop was all the active loops he was running the west campus plant with on Invensys Wonderware..... Not rocket science..... I also had it working with RSLinx Classic. After Visual Studio is talking, you can work on getting C++ talking.

Share this post


Link to post
Share on other sites
Here's a code snippet for addressing the canonical data types... plop it in Visual Basic 2010 and get the OPC library.. ' >>>>>>>>>> ACTIVE SYNC WRITE 1 BOOL True then False w Adjustable Delay <<<<<<<<<<< Private Sub Label_LP01buttonAMselectASW_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Label_LP01buttonAMselectASW.Click Dim aswItemNumber As Short 'Item handle we write to Dim aswNumItems As Short 'How many Items to Write Short is 16 bits and can be converted to many data types Dim aswItemValue As String 'Value of item to write Dim isTrue As String 'Bool value True Dim isFalse As String 'Bool vlaue False isTrue = 1 isFalse = 0 'Which item handle to write "One" Based Array Size aswItemNumber = 2 'Second Server Handle starting from 1 'How many Items to Write aswNumItems = 1 'What will we Write? aswItemValue = isTrue 'Use of string is universal for user input >>> Labels and Text Boxes <<<, Process figures out how to convert.... Call aswProcess_DataType(aswItemNumber, aswNumItems, aswItemValue) ' Process Canocal Data Types and send Sync Write Delay(0.75) 'Which item handle to write "One" Based Array Size aswItemNumber = 2 'How many Items to Write aswNumItems = 1 'What will we Write? aswItemValue = isFalse Call aswProcess_DataType(aswItemNumber, aswNumItems, aswItemValue) End Sub ' >>>>>>>>>> PROCESS ACTIVE SYNC WRITE Request for Canonical Data Types <<<<<<<<<<< Private Sub aswProcess_DataType(ByRef aswItemNumber As Short, ByRef aswNumItems As Short, ByRef aswItemValue As String) If Not OPCGroup Is Nothing Then Dim aswValue(NumItems) As Object Dim aswItem(NumItems) As Integer aswValue(aswItemNumber) = aswItemValue Try Dim SyncItemServerErrors As System.Array Dim AnOPCItem As OPCAutomation.OPCItem aswServerHandles(1) = ServerHandles(aswItemNumber) AnOPCItem = OPCGroup.OPCItems.GetOPCItem(ServerHandles(aswItemNumber)) Dim ItsAnArray As Array Dim CanonDT As Short CanonDT = AnOPCItem.CanonicalDataType() ' If it is an array, figure out the base type If CanonDT > vbArray Then CanonDT -= vbArray End If Select Case CanonDT Case CanonicalDataTypes.CanonDtByte If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(Byte), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToByte(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtChar If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType([SByte]), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToSByte(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtWord If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(UInt16), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToUInt16(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtShort If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(Int16), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToInt16(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtDWord If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(UInt32), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToUInt32(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtLong If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(Int32), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToInt32(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtFloat If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(Single), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToSingle(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtDouble If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(Double), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToDouble(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtBool If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(Boolean), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToBoolean(aswValue(aswItemNumber)) End If ' End case Case CanonicalDataTypes.CanonDtString If aswItem(aswItemNumber) > 0 Then ItsAnArray = Array.CreateInstance(GetType(String), aswItem(aswItemNumber)) If Not aswLoadArray(ItsAnArray, CanonDT, aswValue(aswItemNumber)) Then Return End If aswItemValues(1) = CObj(ItsAnArray) Else aswItemValues(1) = Convert.ToString(aswValue(aswItemNumber)) End If ' End case Case Else MsgBox("Write Fail>>Unknown Data Type", MsgBoxStyle.Exclamation) Return ' End case End Select ' Invoke the SyncWrite operation. Remember this call will not wait until completion OPCGroup.AsyncWrite(aswNumItems, aswServerHandles, aswItemValues, SyncItemServerErrors, TransactionID, CancelID) ' Server Error handling If SyncItemServerErrors(1) <> 0 Then MsgBox("SyncItemServerError: " & SyncItemServerErrors(1)) End If Catch ex As Exception ' Write Error handling Timer_LP01_UP.Enabled = False Timer_LP01_DN.Enabled = False MessageBox.Show("Write Tag Failed: " + ex.Message, "Exception", MessageBoxButtons.OK) End Try End If End Sub ' >>>>>>>>>> LOAD ARRAY SCRIPT <<<<<<<<<<< Private Function aswLoadArray(ByRef AnArray As System.Array, ByVal CanonDT As Short, ByRef wrTxt As String) As Boolean Dim ii As Integer Dim loc As Integer Dim Wlen As Integer Dim start As Integer Try start = 1 Wlen = Len(wrTxt) For ii = AnArray.GetLowerBound(0) To AnArray.GetUpperBound(0) loc = InStr(start, wrTxt, ",") If ii < AnArray.GetUpperBound(0) Then If loc = 0 Then MsgBox("Write Value: Incorrect Number of Items for Array Size?", MsgBoxStyle.Exclamation) Return False End If Else loc = Wlen + 1 End If Select Case CanonDT Case CanonicalDataTypes.CanonDtByte AnArray(ii) = Convert.ToByte(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtChar AnArray(ii) = Convert.ToSByte(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtWord AnArray(ii) = Convert.ToUInt16(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtShort AnArray(ii) = Convert.ToInt16(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtDWord AnArray(ii) = Convert.ToUInt32(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtLong AnArray(ii) = Convert.ToInt32(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtFloat AnArray(ii) = Convert.ToSingle(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtDouble AnArray(ii) = Convert.ToDouble(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtBool AnArray(ii) = Convert.ToBoolean(Mid(wrTxt, start, loc - start)) ' End case Case CanonicalDataTypes.CanonDtString AnArray(ii) = Convert.ToString(Mid(wrTxt, start, loc - start)) ' End case Case Else MsgBox("Write Value Unknown data type", MsgBoxStyle.Exclamation) Return False End Select start = loc + 1 Next ii Return True Catch ex As Exception MsgBox("Write Value generated Exception: " & ex.Message, MsgBoxStyle.Exclamation, "UNI_LOOP Exception") Return False End Try End Function ' >>>>>>>>>>>HANDLE OPC ERRORS CALL TO THIS ROUTINE - NOT AN EVENT<<<<<<<<<<<<< Private Sub DisplayOPC_COM_ErrorValue(ByVal OPC_Function As String, ByVal ErrorCode As Long) 'Handles displaying any OPC/COM/VB errors that are caught by the exception handler Dim Response Dim ErrorDisplay As String ErrorDisplay = "The OPC Function '" + OPC_Function + "' Has Returned an Error of " + Str(ErrorCode) + " or Hex 0x" + Hex(ErrorCode) Response = MsgBox(ErrorDisplay, vbOKOnly, "OPC Function Error") End Sub

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0