Sign in to follow this  
Followers 0
John Croson

HELP!

17 posts in this topic

I am not a PLC person, but I am a VBA person. I can create a hot link in Excel to an SLC503+ and see my data. But if I try to use the following code, I get a Type Mismatch error. This usually tells me that I'm using an invalid variable type to hold the data, but I'm using a Variant type!! 'assign PLC bit values to VB variant varibles varDump = DDERequest(RSIChan, "C5:2.ACC") This space is supposed to hold a number from 0 to 25. If I do a Copy DDE link from RSLinx (Single Node), I get this: [ENDRES]C5:2.ACC,L1,C1 Can anyone tell me why I get this error? Thanks!

Share this post


Link to post
Share on other sites
I do not see any problem with that line, I use similar lines of code all the time. Have you tried getting a different address such as an integer ex N7:0 . Are you initiating the DDE link first, what other lines of code do you have before this line?? Might need some more info. JJ

Share this post


Link to post
Share on other sites
Thanks for the reply. Here is the top of the sub: Dim lngRow As Long Dim varDump As Variant Dim sngWeight As Single Dim varResults As Variant Dim intVar As Integer, intCount As Integer, _ intData As Integer, strData As String On Error GoTo Error 'opens a COLD DDE link RSIChan = DDEInitiate("RSLINX", "ENDRES") 'assign PLC bit values to VB variant varibles varDump = DDERequest(RSIChan, "C5:2.ACC") 'close COLD DDE link DDETerminate (RSIChan) 'check to see if anything has been dumped If varDump > 0 Then Thanks again! Edited by John Croson

Share this post


Link to post
Share on other sites
Boy....I am confused too. I am like teckjunkie, that should work. Do you have a DDE topic created in RS Linx Single Node? That topic name needs to be "ENDRES" based on your code. See attached JPG.

Share this post


Link to post
Share on other sites
I guess I have to agree with TechJunki. Have you tried using another address? Like N7:0? Address C5:2 should be a default address that should be accessable in the SLC memory without having to create that address. It does seem odd that you can create a "HOT" topic to that address. I cruised AB's KB, and found this tech doc. It kind of points in the direction of creating your own data type. I've never done that before but see if you can use this code snipplet. http://domino.automation.rockwell.com/appl...D8?OpenDocument Or click Here Actually they don't even DIM the "data" varible, which I believe is suppose to make "data" a Variant anyway if you don't DIM it if I recall my VB rules... but it looks like they are trying to detrimine the data type in the next line of code with the mytype varible.

Share this post


Link to post
Share on other sites
COOL! Thanks for the pointer. Bad form using Variants, but so be it... The Example: Sub Word_Read()      Dim mytype As String      Dim test As Integer      Dim junk As Tag      Set junk = gTagDb.GetTag("analog")      'open DDE link: testsol=DDE Topic      RSIchan = DDEInitiate("RSLinx", "testsol")      'get data and store in data variable      data = DDERequest(RSIchan, "N7:0")      'shows the variable type for data      'use the TypeName function and the Locals Window to determine      'the data type for the variable 'data' to determine it is an array.      'the line is not necessary for the script to run.      mytype = TypeName(data)      'store the value from data into variable and tag      test = data(1)      junk.Value = data(1)      'close dde link      DDETerminate (RSIchan)      'release memory for tag      Set junk = Nothing End Sub The thing I can't understand is why I'm setting the junk variable. Is this simply used for a test? I am using the example this way: Sub Start() Dim lngRow As Long Dim varResults As Variant Dim strTestType As String Dim intDump As Integer Dim junk As Tag Dim intVar As Integer, intCount As Integer, _    intData As Integer, strData As String On Error GoTo Error     Set junk = gTagDb.GetTag("test")    'opens a COLD DDE link    RSIChan = DDEInitiate("RSLINX", "ENDRES")        'assign PLC bit values to VB variant varibles    dumpqty = DDERequest(RSIChan, "C5:2.ACC")         'shows the variable type for data 'use the TypeName function and the Locals Window to determine 'the data type for the variable 'data' to determine it is an array. 'the line is not necessary for the script to run.    strTestType = TypeName(dumpqty)        ' Convert our variable into something usable    intDump = dumpqty(1)    junk.Value = dumpqty(1)        'close COLD DDE link    DDETerminate (RSIChan)        'check to see if anything has been dumped    If intDump > 0 Then For intCount = 0 To intDump        'starts at row 3 of sheet        lngRow = 3                If Range("INDATA!A3").Value > 3 Then            'look up last cell and change position            lngRow = Range("INDATA!A3").Value        End If                'check until end of sheet        For lngRow = lngRow To 65500            'look for next empty cell            If Cells(lngRow, 1) = "" Then Exit For                        'write current cell location to sheet INDATA            'rather than writing a loop to search on            'every cycle, by the time the log is at row 21,500            'it could take a long time to search the rows...            Range("INDATA!A3").Value = lngRow + 1                                'add 1 to row "x" to check next row        Next                  'opens a COLD DDE link        RSIChan = DDEInitiate("RSLINX", "ENDRES")                'there might be a better way to do this like        'using this somehow ???????? but I don't know how        'data = DDERequest(RSIchan, "f11:0,L7,C7")        'Range("[ENDRES.xls]LOG!R[x]C1:R[x]C7").Value = data                                                             For intCount = 0 To intDump         ' Fill in the TYPE Column        intData = DDERequest(RSIChan, "N24:" & intVar)            Select Case intData            Case Is = 1                strData = "BREAD"            Case Is = 2                strData = "PRETZEL"        End Select        Cells(lngRow, 1).Value = strData        'increment our var        intVar = intVar + 1        'zero our data        intData = 0            ' Fill in the Room Column        intData = DDERequest(RSIChan, "N24:" & intVar)            Select Case intData                Case Is = 1            strData = "Mixing Room"                Case Is = 2            strData = "Package Room"                Case Is = 3            strData = "Oven Room"        End Select        Cells(lngRow, 2).Value = strData        'increment our var        intVar = intVar + 1        'zero our data        intData = 0                    ' Fill in the Line        intData = DDERequest(RSIChan, "N24:" & intVar)            Select Case intData            Case Is = 5                strData = "Other"            Case Else                strData = intData        End Select        Cells(lngRow, 3).Value = strData        'increment our var        intVar = intVar + 1        'zero our data        intData = 0                    ' Fill in the Result Of Column        intData = DDERequest(RSIChan, "N24:" & intVar)            Select Case intData            Case Is = 1                strData = "From Startup"            Case Is = 2                strData = "From Shutdown"            Case Is = 3                strData = "Normal Production"            Case Is = 4                strData = "From R&D"            Case Is = 5                strData = "From Change Over"            Case Is = 6                strData = "Other"        End Select        Cells(lngRow, 4).Value = strData        'increment our var        intVar = intVar + 1        'zero our data        intData = 0                 Next intCount                      'close COLD DDE link        DDETerminate (RSIChan) The installer of the panel supplied these instructions: Word 1 ( N24:0 ) = TOTE WEIGHT Word 2 ( N24:1 ) = PRODUCT TYPE, 1=bread / 2=pretzel Word 3 ( N24:2 ) = ROOM, 1=mixing / 2=packaging / 3=oven Word 4 ( N24:3 ) = LINE, 1,2,3,4,5 Word 5 ( N24:4 ) = RESULT OF, 1=startup / 2=shutdown / 3=normal 4=r&d / 5=change over / 6=other Then it starts over, counting Word 1 from N24:5, the weight. The rest of the code has been snipped, but I just want to check for an accumulated value in C5:2.ACC, and if it is more than 0, grab all the data in the "array" and push it into my spreadsheet. It seems that I have to do a var check for all of the PLC types of data? Thanks for looking!

Share this post


Link to post
Share on other sites
What happens now with your example that you snagged from AB? Do you still get a TYPE MIS-MATCH even now without DIMing your variable? PS: Glad people are using my example, looks like you've got some of my orginal code I did when I first tackled this DDE and Excel stuff with this download: http://forums.mrplc.com/index.php?act=Downl...&CODE=02&id=134 Going back to your orginal code, try this: Putting an L1, meaning read one word then a carriage return after the first word. Dim lngRow As Long Dim sngWeight As Single Dim varResults As Variant Dim intVar As Integer, intCount As Integer, _ intData As Integer, strData As String On Error GoTo Error 'opens a COLD DDE link RSIChan = DDEInitiate("RSLINX", "ENDRES") 'assign PLC bit values to VB variant varibles varDump = DDERequest(RSIChan, "C5:2.ACC,L1,C1") 'close COLD DDE link DDETerminate (RSIChan) 'check to see if anything has been dumped If varDump > 0 Then I think what the problem is, is that that counter is considered an array when taking about DDE much like a timer value. Like C5:2.DN, C5:2.EN,C5:2.PRE,C5:2.ACC...so we gotta handle that array of data somehow.... What would be EASIER at this point is to get your PLC guru to copy C5:2.ACC into a N7:xx memory location. N7:xx memory location will not be an array of data that you need to deal with and you can move on with your project. Here is a list of all those stupid things you don't know about DDE and data type formatting. BTY..... Take note to the "X" identifier... Regardless of the client application used with RSLinx, the address of the DDE item specified must be of the following form: [address]<,L##><,C##><R##>{,N}{,D}{,E}{,DH}{,EH}(,T)(,B)(,W)(,X)(,M) (,SA##)(,SC##)(,SP##)(,SS##)(,SA##) where: [ ] indicates a required field (address) that is suitable for the PLC type specified within the topic. < > indicates an optional block read or block formatting command. L## indicates the total length (block size), or number of items to be read. C## indicates the number of columns in which to format the data. This is for display purposes in the client application. R## indicates the number or rows in which to format the data. This is for display purposes in the client application. ## indicates a numeric value that must be placed after the optional specifier. (Specifying C## without a corresponding L## specifier has no effect. However, specifying an L## without a C## results in a display as if L##,C1.) { } indicates an optional data type specifier that is only used with a PLC-2. If none of these specifiers is used then the default type is N, 16-bit signed integer. M: used for specifying a Motorola byte ordering, which causes the conversion routines to swap bytes before interpreting the data. This was mainly intended to fix a problem when reading strings with unsolicited messages. N: 16-bit signed integer D: 12-bit, 3-digit BCD number E: 16-bit, 4-digit BCD number DH: 12-bit, 3-digit BCD number, displays the hexadecimal value EH: 16-bit, 4-digit BCD number, displays the hexadecimal value (T) indicates a special specifier used only with unsolicited messages when the source of the data table is a PLC-5 timer accumulated value and the destination address is something other than another timer accumulated value. In most situations this specifier is not needed. (B) indicates a special specifier used only with the Allen-Bradley PLC data types that are 16-bits. This specifier causes the data to be displayed as a string of 1's and 0's instead of an unsigned integer. (W) indicates a special specifier used only with the Allen-Bradley PLC data types. This specifier is used when specifying an array of bits. It causes data to be read from consecutive elements. For example in a structured data type (timers, counters, etc.), T4:0.DN,L10,C1,W reads T4:0.DN, T4:1.DN, T4:2.DN, etc. For a non-structured type (binary, integer, etc.), B3/0,L10,C1,W reads B3:0/1, B3:1/1, B3:2/1, etc. (X) indicates a special specifier used only with the Allen-Bradley PLC data types. This specifier is used when specifying an array of bits. It causes data to be read from consecutive bits. For example in a structured data type (timers, counters, etc.), T4:0.DN,L3,C1,X reads T4:0.DN, T4:0.TT, T4:0.EN. For a non-structured type (binary, integer, etc.), B3/0,L10,C1,X reads B3:0/1, B3:0/2, B3:0/3, etc. (SA##) sends all updates to the client RSLinx receives even if they have not changed. (SC##) indicates a special specifier used only with the Allen-Bradley Integer (N) or ASCII (A) PLC data types for C style strings. (SP##) indicates a special specifier used only with the Allen-Bradley Integer (N) or ASCII (A) PLC data types for Pascal style strings. (SS##) indicates a special specifier used only with the Allen-Bradley Integer (N) or ASCII (A) PLC data types for space-padded strings.

Share this post


Link to post
Share on other sites
Thanks! Yes, I did hack up your original example, and AB's. I'm more of a vb guy, never having grabbed data from a PLC before, so it threw me off, not declaring variables, and then passing the var's into int's, etc. The only issue I'm having now is DDEPoke into B3/100 to reset the array. It doesn't seem to work. My code: Sub DDE_Write() RSIChan = DDEInitiate("RSLINX", "ENDRES") 'write data thru channel DDEPoke RSIChan, "B3:100", Range("OUTDATA!A11").Value DDEPoke RSIChan, "B3:100", Range("OUTDATA!A10").Value 'close dde channel DDETerminate (RSIChan) End Sub Thanks!

Share this post


Link to post
Share on other sites
Try substituting in the following code, substituting Book1 and Sheet1 with the correct names in your project. You do also realize that you are writing to the same address twice B3:100, are you possibly canceling out the data you are sending here?? Sub DDE_Write() RSIChan = DDEInitiate("RSLINX", "ENDRES") 'write data thru channel DDEPoke RSIchan, "B3:100", Range("[Book1.XLS]Sheet1!A11") DDEPoke RSIchan, "B3:100", Range("[Book1.XLS]Sheet1!A10") 'close dde channel DDETerminate (RSIChan) End Sub Edited by TechJunki

Share this post


Link to post
Share on other sites
Since I don't know what you got in your spreadsheet at: OUTDATA!A11 You have two different things going on there. B3/100 is a "BIT" in the PLC. You would only be able to write a "0" or a "1" to that address and would format your code like: DDEPoke RSIChan, "B3/100", Range("OUTDATA!A11").Value B3:100 is a whole "WORD", or 16 bits. You could write more than just a "0" or "1" to that word. Which one are you trying to do?

Share this post


Link to post
Share on other sites
Sorry for my incomplete post! This cell contains a "1" DDEPoke RSIChan, "B3:100", Range("OUTDATA!A11").Value This cell contains a "0" DDEPoke RSIChan, "B3:100", Range("OUTDATA!A10").Value I was told that if I set the bit in this b3/100 to 1 and then back to 0, it would reset my n24 integer bits. Thanks again! You guys are great!

Share this post


Link to post
Share on other sites
You're not giving the PLC enough time to recognize the setting of the bit if you immediately turn it back off. The PLC scan time is going to be at least 10msec and the communication cycle rate is a factor as well. I would just set the bit, and let the PLC turn it back off after it has reset the array counter. Your format will write a "1" to the 16 bit word B3:100. It will clear 15 bits and set bit 0. You could just write to a single bit using the / delimiter "B3:100/0" B3/100 IS NOT IN THE SAME WORD AS B3:100! B3/100 IS THE SAME AS B3:6/4. Using the "/" delimiter like this "B3/100" refers to the 100th bit in the FILE B3. Now, if your VB code sets the CORRECT bit, and lets the PLC RESet it, then you could read the same bit in a DO...LOOP and make sure it is zero as a handshake before ending the routine. (be sure to put in a time limit to escape your loop if comms fail!) I'm not a VB guy so I don't have examples, but I think my general suggestion will get you where you need to be. Make sure you get the correct bit address and get away from the word reference. If you use the whole word, it will work, but some poor fool will pull all his hair out later when he tries to use one of those other bits in the PLC that won't stay on! OkiePC

Share this post


Link to post
Share on other sites
This is what I'll end up using. This should set the bit to 1, wait a second, and then set it back to 0. Could I have also just have used something like this? DDEPoke RSIChan, "B3/100", 1 Pause 1 DDEPoke RSIChan, "B3/100", 0 Should I have those number in quotes? Sub DDE_Write() Dim intSet As Integer RSIChan = DDEInitiate("RSLINX", "ENDRES") 'write data thru channel 'set the bit to 1 DDEPoke RSIChan, "B3/100", Range("OUTDATA!A11").Value Pause 1 'and set it back to 0 DDEPoke RSIChan, "B3/100", Range("OUTDATA!A10").Value 'close dde channel DDETerminate (RSIChan) End Sub Public Sub Pause(ByVal pSng_Secs As Single) 'Wait for the number of seconds given by pSng_Secs Dim lSng_Start As Single Dim lSng_End As Single On Error GoTo Err_Pause    lSng_Start = Timer    lSng_End = Timer + pSng_Secs    Do While Timer < lSng_End    '' Correction if the timer moves over to a new day (midnight)    '' 86400-num of secs in a day        If Timer < lSng_Start Then lSng_End = lSng_End - 86400    Loop Err_Pause:    Exit Sub     End Sub Thanks.

Share this post


Link to post
Share on other sites
No, your constants should be outside of the quotation marks, but I'm not sure if the DDEPoke will write to a single bit or to a whole word. Be sure that the next sixteen bits (b3/100 - b3/115) are not used in the PLC before you try this. The one second delay should be plenty of time, but may need to be increased if using DH485 with a lot of traffic. I still think it would be more bullet proof if you let the PLC unlatch (reset) the bit, and then in your VB code make sure it's zero before you examine the accumulator to read another batch of data. Modifying the SLC code online is really safe and painless and won't even require the process to be stopped. I wish I had more experience so I could tell you exactly what will happen bit by bit...I'll look on ab.com and see what's been written on the subject.

Share this post


Link to post
Share on other sites
I did some experimenting of my own and found that it would not work with literals or local variables. I found that I had to use a cell reference to get the data to change in the PLC. I found that if your PLC address refers to a single bit, it will be set to a "1" if the cell reference is non-zero. It does not disturb adjacent bits. This is my oversimplified example that did work: Sub Word_Write() 'open dde link: testsol=DDE Topic RSIchan = DDEInitiate("RSLinx", "BS6") 'write data thru channel DDEPoke RSIchan, "B14:4/0", Range("Sheet1!A8") 'close dde channel DDETerminate (RSIchan) End Sub Hope this helps. Edited by OkiePC

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