STEP7 UDTs and initial values.

Thanks Ken, but it was no problem putting this together, and I’m always glad to share. I used to teach Siemens PLC programming, so it doesn’t take long to put something together. It even helps me out to explain it to myself sometimes, and I’m glad if someone can get something from it, even if they can’t apply the approach to an entire project.

Also, I finally had a chance to look at the sample project again, and I caught a couple of other errors (in a couple of the FBs, I pasted the UDT as an In_Out declaration instead of a STAT). So, I’ll post it again with the corrections and you can toss away the old one.

Jesper, I see where you are coming from now. In my example, to keep things simple to explain, I assumed some kind of rotary assembly machine where each station had different functions but similar IO. If I had a machine where the IO was scattered all over the place or was radically different at each station, I would have to do something different. Here are some ideas:

1. If the IO is completely different at each station, but each station at least has its own IO, then I would come up with individual UDTs to describe that IO. Then, I might have to build my DB differently. If I had plenty of space in the DB, I would still use arrays and make all of the IO UDTs available to each station along with a configuration variable that told each station which IO to use. Or, if that is too clunky, I would skip the arrays and manually list each station in the DB with its own IO UDT. That would be a one time effort, and I would still be able to continue using my approach. The only thing I might have to do is calculate the pointers and lengths for each individual station at start-up if it’s possible that the UDT lengths could be different.

2. If the IO isn’t contiguous, then I would use bit pointers (each IO point would have its own DINT pointer). One problem is that this way of indirect addressing- “A I[#StartButton]” -is inefficient. It is essentially two instructions, plus S7 doesn’t let you use STAT variables in the brackets, so I would have to pass each dint into local memory. If scan time is not an issue, or if I only had a few IO, I guess that would be ok, but if I had thousands of IO, I would be resigned to mapping the absolute bits one by one in a custom function. I would hate to do that, but at least the custom hard-coding would be limited to a couple of functions. Thinking about it, since I use symbolic priority, it wouldn’t be to bad to do it like that as long as I made sure my symbol table was current.

Unfortunately, no matter which approach you use, if you make a change to a DB, I can’t think of a way of downloading the DB without stopping the PLC first. It would be like overwriting an MS Word doc while saving the text in the old one.
 
Right, I should have explained what it is that I do.
It is a collection of very different objects, conveyors, ploughs, silos, mixers, pneumatic transports, weigh hoppers, etc. etc.
Each project is different, some projects are even old plants that I have to upgrade with new PLC and HMI, meaning that the same thing can be done in an old and a new way - at the same plant.

My programming style is traditional FBs + instance DBs for the objects that are more or less standard. I try to keep the FBs small and simple, I dont want to look inside an FB after it is assigned, it is like a small Lego block that I use to build a large project.
On a higher level I use FCs with data from a shared DB. This because of the ability to make changes online as I describe below.

S7Guy said:
Unfortunately, no matter which approach you use, if you make a change to a DB, I can’t think of a way of downloading the DB without stopping the PLC first.

You can change both shared DBs and instance DBs, and download them without stopping the PLC if OB121 is programmed.
In order to not wreak havoc in the running program, you can only add variables to unused positions (or append them to the end), so that all the other variables doesnt change positions.
I normally DO NOT change instance DBs except for the occasional Actual value of an existing DB. - That isn't good practice though, as 'initialising' the DB will change the Actual value back to the initial.
On the other hand I regularly change shared DBs and download these during running proces cycle. This can mean that the various FC and FB calls in the offline project will report timestamp conflicts, but I can wait to sort that out when there is a production stop.

With 'regular' FBs and FCs, it is easy to change the i/o as each has its own 'pin'.

I would certainly reconsider my entire programming strategy if there is a more clever way of doing things. But I emphasise online editing.
 
S7Guy:

In the machines that are using this program, is it compromised of different "machine modules", so that it's only the configuration (type, amount and position) that changes from project to project?
As far as I could tell, the sample project runs the same io code on alle stations. Am I right on this?

I'm trying to figure out if I could use this approach on the machines that I work with (I really liked the system). But the problem I have is that it's never the same, the amount of IO is specific, the confiuration of the IO is specific, the code for each io would be different. So I don't see how I could apply this system.

I prefer making code that would be "generic" but it's kinda hard when all aspects of the machine usually changes from project to project.

Regards
Borte
 
JesperMP said:
....So, the trick is to:
a. When commisioning is finished, upload the DBs that are important to the offline project (go online, highlight the relevant DB(s) and select PLC ... Upload to PG).
b. Select PLC ... Download user program to memory card.
c. Archive the project.
d. Save the project under a new version number.

The only thing that can go wrong, is if you accidently use the 'Initialize datablock' function.

What must do when DB must extend and download over oldone, what is DB's contents after that? There are only very common UDT-type variable declarations in the DB.
 
Hi seppo,

I am not using any UDT variables. I was only experimenting to find out if I could get better functionality.
I could have used UDT's though, and still be able to download a changed DB over an existing one.
You just have to be very careful that the existing and active parts of the DB does not change positions.
 
Sorry,
I answered something else than what Seppo asked about :oops:

If you have UDT variables, then you should be careful not to initialise the DB that you have uploaded. This because there is no way to set the individual 'Initial Values' for each DB variable. These are set when defining the UDT.

This is the main reason that I cannot use UDTs (as I was worried about when I started this thread).
When using shared DBs with 'regular' variables - no UDTs, you can manipulate both 'Initial Values' and 'Actual Values'.
 
Last edited:
Hi S7Guy,

I'm just working my way slowly through the UDT Sample Project again and on the whole, it's going not too badly. However, I have a couple of questions.

1) In Post 31 you mention having spotted a couple of errors, in particular you mention having incorrectly declared Station as IN_OUT instead of STAT. I've downloaded the file again, in case I had the early version, but while Station is a STAT in FB20, 21 and 100, in FB10, 11 and 12, it's still declared as IN_OUT. Is this just an oversight, or is there a reason for it. Come to that, I'm not entirely clear as to why you can't (or perhaps don't want to) use an IN_OUT for this.

2) In FC101 you've got the following code:

L P##UDTAddress
LAR1
L W [AR1,P#2.0]
SLD 3
T #Length
L D [AR1,P#6.0]
SLD 3
SRD 3
T #StartPoint

While I think I see what it does OK, I can't understand what you're doing (or possibly more precisely, what you're achieving) with the SLD 3 / SRD 3 command pair at the end.

The only think I can think of is that if the pointer is a boundary crossing pointer, this would erase the MSB, effectively turning the pointer back into an internal one, but there again, you could do that with SLD 1 / SRD 1, so that's pretty unlikely!

3) This one just occurred to me while writing the last paragraph. How does Step7 know/decide what type of pointer you're using/creating anyway?

Hope I'm not being too much of a nuisance, it's just that I belong to that weird species who like to know why they are doing something and not just accepting that it works!

Cheers

Roy
 
Roy, in case #1 it should be a STAT. It was an oversight, as I never use the other variables when calling the FBs using this method. That said, I think I actually could, but I wouldn't want to, the reason being that it would affect the AR2 offset (you'll see this if you insert an IN/OUT/INOUT variable.



In #2, I just do it by habit I guess. Byte 6 in an ANYPointer is the data type, and it may or may not be compatible with what I want to do with it. Since all I really want is the XXX.Y part, I wipe the first byte clean before the transfer. I also made a mistake in using 3. It should be 8 instead (it was late, and I obviously was correlating SL3 with “multiply by 8”, which doesn’t make sense in this code).



#3: I’ve often wondered the same thing, and evidently within the low-level architecture of the S7, there must be something that automatically matches the STAT variable to the AR2 register, just as it automatically uses the current IDB and not the shared DB. It’s just the way it is.
 
In #2, I just do it by habit I guess. Byte 6 in an ANYPointer is the data type, and it may or may not be compatible with what I want to do with it. Since all I really want is the XXX.Y part, I wipe the first byte clean before the transfer. I also made a mistake in using 3. It should be 8 instead (it was late, and I obviously was correlating SL3 with “multiply by 8”, which doesn’t make sense in this code).



According to the diagrams in my copy of Berger, Byte 6 is only the Data Type for Timer or Counter ANY-Pointers, in the ANY-Pointer for Data Types Byte 6 is the first Byte of the Area Pointer. I would have thought that your UDT Pointers would count as Data-Type Pointers, they certainly aren't Counter or Timer Pointers, or have I misunderstood something fundamental about what is meant when Berger refers to the three different formats for the ANY-Pointer?
 
Take a look at the Siemens AnyPointer help, and it will explain Byte 6. In addition to timers and counters, it can point to all of the other data types. For instance, a DB is hex 84, and an IDB is hex 85.
 
Interesting, the Help file lays the emphasis a bit differently from Berger. First of all they don't differentiate between Timers/Counters and Blocks and then they imply a similarity between the data in Byte 6 which I certainly didn't get a feel of from Berger.

Funny how you can take essentially the same information and depending on how it's presented, come away with a completely different understanding of it.
 
RMA - what similarity are you referring to for byte 6 ?

Any pointer for data types, byte 6 = Address area
Any pointer for timers/counters, byte 6 = Data type
Any pointer for blocks, byte 6 =Data type (from help) or 0 (Berger)

The only ambiguity is the conflict between the help and Berger.
 
The only ambiguity is the conflict between the help and Berger.



That's certainly the main point, but I'm working with the German version of Step7 and in the Help file the description of the Pointer structure for Timers/Counters and Blocks are lumped together.

Come to think of it, I think part of the problem is that I've only got a very hazy idea of exactly what they mean when they use the term "Parameter type" in this context.

Actually, that's probably not the only thing I've got a pretty hazy idea of on the subject of ANY pointers!:)

It occurs to me that part of my problem might be the fact that I'm having to read this all in German. Although my German's pretty good, (I've lived here for getting on for 20 years now) it still aint my mother tongue! Could you post the ANY-pointer Help file in English - that might help sort things out a bit.

Thanks

Roy
 
Please see pasted help below. Running in a plc simulator, byte 6=0 for a block type any pointer. (I haven't included the full table of address areas, types)

any2.GIF

any3.GIF
 
Last edited:
Thanks, Simon,

turns out to be a (very) direct translation from the German, or maybe the German is a direct translation of the English, I'm not sure which. Either way it hasn't moved me on much. This is a problem I've run into before, being entirely self-taught as far as S7 is concerned I'm not always 100% certain what some of the terminology actually means.

As usual, I'll just have to play around with it a bit more and look at as many examples as possible, until I get more comfortable with it.

Thanks for posting it though.

Cheers

Roy
 

Similar Topics

This is the first time I am working with Simatic Manager Step7 as I started my siemens journey with TIA which is pretty easy and do a lot of stuff...
Replies
3
Views
153
When you download a DB, the values get overwritten by what is in the "actual" column in offline DB. Does this happen at the start of the PLC...
Replies
6
Views
150
Hello Inside a FB, I´m trying to transfer a string from a DB to a IN_OUT var that was define as a UDT. The problem is that i can´t determine the...
Replies
4
Views
142
Hi all, I am trying to convert RSLogix 5000 program to Step7. I need to bit shift left my array of double integers for tracking the product on...
Replies
2
Views
528
I have a word in some DB which I want to load to AR1 and use as a pointer. In order to do this I need to write L DBxy.DBW xy SLD 3 LAR1 I...
Replies
3
Views
544
Back
Top Bottom