PDA

View Full Version : S7 - Problems with FC103, CDT - correlated Data Table


RMA
February 14th, 2005, 09:34 AM
Has anybody ever used this FC from the TI - S7 conversion library. It has exactly the function that I require, but I'm having problems trying to parameterise it. When I try to enter the Pointers for the IN_TBL, OUT_TBL, etc. DBs as P#DB10.DBX0.0, if I've got symbolic display switched off, after the second RETURN, the input box goes blank. If I then click on the input box to edit it, instead of showing the Pointer which I've just entered, it shows me the Symbolic address of WORD 0. This also happens if I change the "View" back to symbolic display after entering the Pointer, but now if I switch back to non-symbolic display, the symbolic address remains visible.

Despite these peculiarities, the FC runs without any failure message in RET_VAL, but the values that come out of the Table are completely wrong and don't change as the input changes.

Anybody got any ideas?

S7Guy
February 14th, 2005, 12:58 PM
You will see the input address remain in symbolic form regardless of whether you are in symbolic mode or not when coding pointers if the pointer address starts on a variable boundry (I probably did a terrible job of explaining that). For instance, as a test try inputting P#DB10.DBX 0.5 as a pointer, and you'll see that it won't convert. Or, delete the symbol for DB10, and it will stay in absolute form. But, going back to your original problem, if you are looking at this in STL with VIEW>DISPLAY WITH>SYMBOL INFORMATION turned on, you will see the absolute address on the right, so that should tell you if the pointer is correct.

As for the other problems, it's hard to tell. Have you gone online and verified that there are valid values in the tables (sorry, I had to ask)? Are the return values all zeros or are you getting completely unexpected results?

RMA
February 15th, 2005, 02:29 AM
I turned the Symbol Information on and it shows me, as I suspected, that the address has been changed from P#DB10.DBX0.0 to DB10.DBW0. Whether or not this is actually the problem, is another question.

After re-reading the help file it occurs to me that it says "When creating the tables (IN_TBL and OUT_TBL) you must initialise the first entry (Table-length) in each case." I assume this is our old friend Initial- vs. Actual-values raising it's ugly head again. I actually created the tables with the values I wanted, but I haven't yet checked Online to see what is actually there - must go and do that.

The values I'm getting out do not exist in the Output table (always assuming I've finally got them the right way round - the weren't at first!). They do exist in the Input table though. As they are all round numbers, I'll try changing them to something more obscure to try and track it down.

Edit:

Have just checked, the values in the IN_TBL and OUT_TBL DBs look OK, but by changing the appropriate entry in IN_TBL, I could see that the result I'm getting out of FC103 in NW1 is the third entry in IN_TBL and the value for NW2 is the seventh entry - this is regardless of what value is fed into IN. What doesn't make matters any easier is that regarless of whether I View the program in STL or FBD the values of the inputs and outputs of the FC103 are not displayed, with the exception of the B#16#05 for E_TYPE indicating that the Table entries are INT and the RET_VAL of "0".

Most peculiar!

RMA
February 15th, 2005, 04:34 AM
Having noticed that with Symbol information switched on, the IN_TBL and other entries were being displayed as DB10.DBW0 instead of as Pointers, I tried reentering the Pointers with the Symbol Information still enabled. This time the entry showed up in the Symbol Information box as *"Reuse Module Delay".Table_Length*. I then switched off Symbolic Display (NOT Display Symbol Information) and the entry changed to
*""Reuse Module Delay".Table_Length"*.

There was another effect as well, NW1 still picks up and places in OUT the third entry in the IN_TBL and NW2 still picks up Entry seven but now they display in hex instead of decimal - same value, different Format, so reentering the the Pointer has had some effect.

That wasn't quite the end of it. Having decided that I had now, at last, managed to get my Pointers entered as Pointers, I decided to archive the project in this condition. Having brought the CD back to the office and de-archived the Project, so as to continue working with the most up to date version, I then discovered that my pointers were once again being displayed as DB10.DBW0!

This is slowly getting frustrating!!! banghead

S7Guy
February 15th, 2005, 09:21 AM
Roy,

Again, don't get hung up on the symbols. Even if you used absolute addresses, you would get the same results whether you entered, for instance, MW50 or P#M50.0.

In your input/output tables, did you enter the length of the tables as the first value? This is necessary, as otherwise the code won't know how far to loop. The actual table data must begin with value 2.

S7Guy
February 15th, 2005, 10:20 AM
Ok, I looked at FC103, and I think it has problems (actually, I know it has problems). I found a condition where it simply returns the same value that I input and ignores the output table. Can you list the exact parameters you are using?

RMA
February 15th, 2005, 02:19 PM
Hi S7Guy,

I'm back at the apartment now so the parameters will have to wait till tomorrow.

In your input/output tables, did you enter the length of the tables as the first value? This is necessary, as otherwise the code won't know how far to loop. The actual table data must begin with value 2.

I've entered the length as the first value OK, BUT I've entered "1" as the first value in the comparison table.

Is this another case like the DBx.DBB0 parameter for the FM352-5, where they show a certain value in the example but don't mention anywhere in the text, that this is not just a random value and that you MUST use this value.

That's the first thing to check out tomorrow morning. If that then solves the main problem, I'# be back to ask about the special case where the OUT_TBL was ignored!

S7Guy
February 15th, 2005, 03:14 PM
The "1" in the comparison table is OK. In the case I found where the output table was ignored, the input table and output table resided in different data blocks. I hacked into FC103 to take a look, and sure enough, when I changed the code to look at the second DB (actually, it is opened as a DI), it worked fine. I then tried it with both tables residing in the same block, and it worked ok without my change.

So, I'm guessing your two tables are in different blocks.

RMA
February 15th, 2005, 04:46 PM
So, I'm guessing your two tables are in different blocks.

Another thing to change tomorrow - more poor Siemens documentation - it's slowly starting to really pi$$ me off!

RolfB
February 15th, 2005, 05:08 PM
Hi Roy,

I reread your former post and maybe
I have missreaded it, but I think you
could do the programming with one
Datatable with 24 timevalues;
a INT var for the setpoint ( 1 - 24 KV )
and then indexing e.g.
L DBW[setpoint]
transfer it to VAR delaytime ( INT )
and then
L delaytime
set Tx as on_delay
and Tx ... do sth.

I've tested the function 103 too. For my
opinion it's buggy and a waste your time.
throw it away.

Regards
Rolf

S7Guy
February 15th, 2005, 09:58 PM
Hey Roy,

I started thinking about this at dinner, and figured I could throw together something a little more streamlined than the FC103. I made it somewhat similar so you wouldn’t have to figure out something completely new, but I think it might be easier to understand. Plus, you can troubleshoot it if you want.

The differences:

1. I used an AnyPointer so that the length of the table would be passed in with the pointer. That way you won’t have to initialize the length in the DB. If you have created a STRUCT to store your tables, then you should be able to type in the struct address and Siemens will convert it to the correct pointer format. Otherwise, just type it in manually in the form of “P#DB100.DBX40.0 Byte 50” for a table of 25 integers.
2. In the Siemens CDT, it looked for values that were >=, but I wrote it so that the values had to be an exact match. One reason I did this is that I wanted it to be a true look-up table that allowed any values in any order, so it could be later used for something completely non-linear like a greyscale encoder or some sort of recipe. That said, you can change this very easily if you want, but you will have to ensure that the input table is in ascending order just like FC103 required.
3. The Siemens functions limited the values to INT, DINT, and REAL, but there is no reason that this one couldn’t be modified for any data type just by evaluating the pointer, i.e:

If you use P#DB100.DBX0.0 BYTE 100, then W[AR1,P#0.0] will be h1002.
If you use P#DB100.DBX0.0 WORD 100, then W[AR1,P#0.0] will be h1004.
If you use P#DB100.DBX0.0 DWORD 100, then W[AR1,P#0.0] will be h1006.

Once W[AR1,P#0.0] is determined, you could dynamically change the amount that AR1 is indexed, as well as the data type that is compared (DBB vs DBW vs DBD). Then, you could compare CHAR, WORD, or whatever. But in this function I have limited it to any 16 bit value, and I expect a BYTE data type in the pointer.

If you open up DB200 and DB201, you can see I just stuck random numbers in DB200, and sequential numbers in DB201, but you can literally insert anything in either block, even negative numbers.

Obviously, the sky is the limit, but this function as it stands will handle what you are trying to do. I couldn’t try this out because I don’t have a test station in my hotel room, but I am 99% sure it will work. If you don’t want to use it, that’s ok too, no offense taken.

I've attached an archive, but this is the bulk of the code:


CLR
= #Error

//**********************
//Determine the input table DB, the
//table length, and the starting address
//**********************
L P##InputTable
LAR1
L W [AR1,P#2.0]
SRW 1
T #Length
L W [AR1,P#4.0]
T #DataBlock
OPN DB [#DataBlock]
L D [AR1,P#6.0]
LAR1

//**********************
//Determine the output table DB and
//the starting address
//**********************
L P##OutputTable
LAR2
L W [AR2,P#4.0]
T #DataBlock
OPN DI [#DataBlock]
L D [AR2,P#6.0]
LAR2

//**********************
//Loop through the input table
//and look for a match. Increase
//AR1 by two bytes on each loop.
//When a match is found, jump
//to calc.
//**********************
L #Length
Top: T #Index
L DBW [AR1,P#0.0]
L #InputValue
==I
JC calc
+AR1 P#2.0
L #Index
LOOP Top
//**********************
//Set an error if no value matches
//**********************
SET
= #Error
BEU

//**********************
//Since we know the length and the
//number of times it looped, the
//DB offset can be calculated and added
//to AR2. The correct value is then
//transferred to the output value.
//**********************
calc: L #Length
L #Index
-I
L P#2.0
*D
TAR2
+D
LAR2
L DIW [AR2,P#0.0]
T #OutputValue

RolfB
February 16th, 2005, 03:55 AM
Hey Roy,


If you only need a timedelay, related to the
current Setpoint (KV)to start next cycle,
then this may work.


Regards
Rolf

RMA
February 16th, 2005, 05:09 AM
Well it turns out that the basic problem is that at the very least IN_TBL and OUT_TBL must be in the same DB. Having gone that far I packed IN and OUT in there as well and sure enough everything's running sweetly now.

However, given that both RolfB and S7Guy mentioned having problems with FC103, I won't carry on using it. On the other hand, I'm one of these people who likes to know why something does or doesn't work, so that's why I carried on looking.

Actually, the most interesting part of the whole job was looking at the two programs offered and fathoming out how they worked. I've learnt a whole load in the process about working with local memory, DB Pointers and ANY Pointers (with a little help from Berger for the structures), how to declare STRUCTs in local memory, the use (and existence) of the L DBLG command, etc. etc.

In the end, I decided to use S7Guy's version because I found it slightly easier to understand, although I changed it to work with >= since the operator can enter the SetPoint as Volts, rather than kV. Since they have a 5MJ limit up to which people can continue working in adjacent labs, I'm sure we'll have the situation where somebody is wanting to enter 21234 V in order to adjust the total energy to 4.999999 MJ!

Thanks a lot for the help and the education guys!


This problem does highlight a problem with Siemens' documentation which is beginning to pi$$ me off in a big way. It would appear that Siemens are too tight to hire or employ Technical Authors to write their documentation. Instead some poor sod in the development department who has never been properly trained in the art (and it is an art!) of writing technical documentation gets the job dumped in his lap. Because this guy knows the product inside out, such things as having to use only one DB for the Input and Output data are so self-evident to him, that it probably doesn't even occur to him that they might not be so self-evident to somebody else who is not familiar with the product.

As a general rule, people who know a product inside out are not the best people to write technical documentation which also has to be used by people who may be meeting the product for the first time. That is a job which is best left to Technical Authors and since doing a good job of it is not as easy as some people might think, they don't come cheap!

The biggest problems with this sort of thing are that

1) you usually finish up wasting several days

partly because, as in this case

2) the Hotline can't help either



By the way, the best documentation I ever came across was the DEC VAX documentation in the '70s and '80s. You may have needed to sacrifice a few square meters of wall space for the shelving, but everything you needed was in the manuals and they were really well cross-referenced.

The KENT K90 manuals in the seventies were also pretty good, unfortunately in the '80s they decided to start saving money as well (must have been after they became Brown Boveri Kent). :(

S7Guy
February 16th, 2005, 05:59 AM
Actually Roy, I don't think the problem was so much with the documentation as with the code and testing. It looks like someone wrote the code, tested it with two tables in the same block, and called it good. Maybe the person who wrote it was really a TI guy, and it never occurred to him to use two different blocks. The code itself doesn't look like something that someone who is experienced with S7 would do.

And that is why I steer away from those canned Siemens FC and FB blocks. I just don't know how much validation went on while writing them, and they might fail when I least expect it.

By the way, did the code I posted work? I'll try it myself if I can find time.

RMA
February 16th, 2005, 06:06 AM
By the way, did the code I posted work? I'll try it myself if I can find time.

I haven't had a chance to test it yet, because we're getting ready to wrap everything up for shipping tomorrow and I've got a couple of other minor problems which have a higher priority.

I'll probably finish up testing it on site next week, although it occurs to me that once the system has shipped I can try it out on the 314C-2 DP, since I don't need any I/O to test.

S7Guy
February 16th, 2005, 08:08 AM
I gave it a try, and it works fine. I'll probably snazz it up for my own use later in case I need my own lookup table.

I'm sure we'll have the situation where somebody is wanting to enter 21234 V in order to adjust the total energy to 4.999999 MJ!

For some reason I assumed that you needed an INT table. If you are working with 32 bit values (real, dint, dword), then the code has to be changed a bit, and you have to change the InputValue and OutputValue to DINTs. If you make this change, it will still work with INTs:


CLR
= #Error

//**********************
//Determine the input table DB, the
//table length, and the starting address
//**********************
L P##InputTable
LAR1
L W [AR1,P#2.0]
SRW 2
T #Length
L W [AR1,P#4.0]
T #DataBlock
OPN DB [#DataBlock]
L D [AR1,P#6.0]
LAR1

//**********************
//Determine the output table DB and
//the starting address
//**********************
L P##OutputTable
LAR2
L W [AR2,P#4.0]
T #DataBlock
OPN DI [#DataBlock]
L D [AR2,P#6.0]
LAR2

//**********************
//Loop through the input table
//and look for a match. Increase
//AR1 by two bytes on each loop.
//When a match is found, jump
//to calc.
//**********************
L #Length
Top: T #Index
L DBD [AR1,P#0.0]
L #InputValue
>=D
JC calc
+AR1 P#4.0
L #Index
LOOP Top
//**********************
//Set an error if no value matches
//**********************
SET
= #Error
BEU

//**********************
//Since we know the length and the
//number of times it looped, the
//DB offset can be calculated and added
//to AR2. The correct value is then
//transferred to the output value.
//**********************
calc: L #Length
L #Index
-D
L P#4.0
*D
TAR2
+D
LAR2
L DID [AR2,P#0.0]
T #OutputValue

Ken M
February 24th, 2005, 10:43 AM
Roy, (and others),

I'm really sorry I started this by suggesting to Roy that FC103 might fit his original problem (now what was that again?) I've only just got back to the office after several days out, and to be honest I'd forgotten about this issue. However something nagged at the back of my mind, and when I searched here I was horrified to see how much time and efort had been consumed on this.

The trouble is, I can't get FC103 not to work! When I tested it first, I had everything in the one datablock: the two tables, the input value and the output value. After reading some of the comments I then split the IN_TBL and IN in to one DB and the OUT_TBL and OUT in to another DB. Still works! Personally I hate all that P#... notation and get in to symbols at every opportunity. So in this case I had -

DB1 "DataIn"
DB2 "DataOut"

In DB1 I created an array of 12 Integers named 'Measured', plus another single Integer named 'TestVal'
In DB2 I created an array of 12 Integers named 'Empirical', plus another single Integer named 'Result'

Then the actual parameters I applied to FC103 were (in order down the FC) -

"DataIn".Measured
"DataOut".Empirical
"DataIn".TestVal
"DataOut".Result
B#16#05 (actually, I even declared a variable named ByteSize and gave it a value of 5!)

The values I applied for test purposes were (in "DataIn".Measured) 12, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 and (in "DataOut".Empirical) 12, 25, 27, 29, 33, 37, 41, 42, 43, 46, 41, 52 The significance of the '12' was to tell the FC how long the table was.

And for every value I stuck in to "DataIn".TestVal I got the corresponding value out at "DataOut".Result Now here's a question you don't see often at PLCs.net - what on Earth am I doing right?

Regards

Ken