Question about S7Guy's FB_UDT~1 project example

douyi

Member
Join Date
Aug 2005
Location
Toronto
Posts
123
I'm not sure if you guys still remember this project template, I'm reading it. If you can't remember, it's here (Thanks RMA).

Q1:
I noticed in each FB, it either use "STAT" or "IN_OUT" local memory instead of use one shared DB (such as 'Station'). Because it doesn't have a DB, so everytime when it's return to calling block, all the memory will be replaced by another current running block, how can you keep data consistency?

For example:

First you call "FB Load Inputs", it has its local symbols declared in 'STAT' as "Station";

Then you call "FB Setpoint Evaluation", it has its local symbols decalred in 'IN_OUT' as "Station" as well.

So how the values pass by thru "FB Load Inputs" to "FB Setpoint Evaluation" ? S7 supose to clear the memory before it load "FB Setpoint Evaluation".

Q2:
Why in some FB the symbols declared in 'STAT' and others in 'IN_OUT'? What's the reason to put it in 'STAT'?

Q3:
For the FBs which symbols declared in 'IN_OUT', it's same as FC. Why use FB not FC?

Q4:
Let's back to Q1. What I'm doing is almost same except declare all the symbols in some shared DBs (because I have a lot, I tried to put in one DB, and it's too slow to open it and display symbol names while LAD editing). What's the difference of that two ways?

Q5:
You opened a DB as an IDB, what's for? If I do it in LAD way, how can I do that or I don't need to worry about that at all? Or if I involve LAD at least at the beginning, do I have to use STL to open this DB as IDB ?

Thanks
 
Q1 - A function block uses an instance data block for all inputs/outputs/in_outs and static data. If you call the function block with Call FB, the editor puts in the instructions which copy the inputs into the instance DB before calling the FB (similarly for the in_outs and the outs). If you call the FB using UC, no copying takes place and the FB just acts on the DB data according to the instance DB and AR2. By making the interfaces in the FB's the same i.e. using a common UDT, the instance DB is actually being used like a global DB but with the advantage of being able to use symbolic references (instead of DBW 0 for example).


Q2 - i think this is a typo, but, as the interfaces contain just one UDT, I think they will actually operate on the same data areas.

Q3 - FC's use a different mechanism for passing UDT variables, they actually pass a pointer to the UDT and each reference to the variable in the FC results in the pointer having to be examined for the data area used, the relevant DB to be opened, AR1 loaded with the variable offset and the variable is finally loaded. With an FB, the variables are copied in to the instance DB and the FB operates on the instance DB.

Q4 - should be answered by Q1 above

Q5 - should be answered by Q1 above
 
Q2) Yes this is a Typo, they should all be STATs.

There are another couple of Typos in FC101, the

SLD 3
SRD 3

should be:
SLD 8
SRD 8

which clears out Byte 6, the Type declaration. (SLD 3 is of course x8, hence the confusion).
 
Thanks.

for the answer of Q3, Siemens said UDT will not be download into PLC, so it's impossible to have a pointer to there. Is that right?
 
UDT is "user defined data type". One way of thinking of these is to replace UDT with INT in any question. For example, can I download an INT to the plc ? No an INT is a data type. Can I have a pointer to an INT ? No an INT is a data type.

In my description a better phrase may have been "a pointer to the data area referred to by the UDT".
 
Last edited:
Another question about "FC UDT Structure"

Thanks Simon.

The program is :
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
UDTAddress is input, Length and StartPoint is Output.

I can't understand why after load the value from UDTAddress plus 2bytes then shift 3 bits will become "Length", same as "StartPoint"

Anyone can explain me why?

Thanks.
 
See post 3 above.

Ooops sorry, misread that.

On the assumption that you're puzzled by the SLD 3 instruction in line 4, this converting the data from the Load instruction on the previous line into the Byte.Bit format necessary for Indirect/Pointer addressing.
 
Last edited:
But at line 3, why add offset 2bytes?
Seems it's looking for a variable "Instance" which is INT, and next one add offset 6 bytes is looking for "StationPointer" which is DINT.

So, if they are empty, the return value will be 0, it's no use. This program supose to find out the length and start point automatically, not read the data from DB.

Another question is why left shift 3 bits will be the correct xx.xxx? so how to explain next left shift 3 bits and right shift 3 again. it seems the program want to cut highest three bits.
 
Last edited:
It's a long time since I battled my way through this (much like you are at present) so I've forgotten a lot - unfortunately, I don't seem to have made some notes which would be useful now.

I think the problem is that this is just a sample of the structure and that in a real world example this bit would be populated. In this case I guess "instance" contains the number of stations - that after all is something you know, you don't have to calculate it.

If I'm wrong, S7Guy will no doubt take a look in and clear things up! :)

Another question is why left shift 3 bits will be the correct xx.xxx? so how to explain next left shift 3 bits and right shift 3 again. it seems the program want to cut highest three bits.
That's the bit I was referring to in Post 3, that should be 8 bits, but I got my Byte number wrong - it should have been Byte 4. That's where the operator type is defined in a Pointer which can be in a different memory area. I checked this with S7Guy and it was a Typo. I also asked him why he did it and I'm not absolutely certain, but I believe he said that in this particular case it was not essential, but he more less did it out of habit.
 
According to siemens manual,
pointer_format.JPG


If I shift 8 bits left, then it will becom
"bbbb bxxx 0000 0000". If you transfer it to a DINT variable, it will become a number. In this case, it's like "Instance" * 256 (2**8). Is that right?

for the "StartPoint" it will cut-off the higher 8 bits and become the address of "bbbb bxxx" form
 
Yes, that diagram is slightly misleading (remember the way Byte addressing runs in S7, Byte 5 is actually the LSByte). The actual Pointer as such is actually only four Bytes long, then there are DB Pointers, which is the one shown above and ANY Pointers, which have another four Bytes of information. In each case the actual addressing part of the pointers is the LS 4 Bytes.

In the example above the green bit called memory area defines where in memory the data is located, i.e. it defines an absolute address. If this area is zero then your address is a relative address in the currently selected memory area. This Byte (2 above) is what S7Guy is clearing out when he does his SLD 8, SRD 8 (as it should be).

Great way of passing the time this, isn't it! :D
 
Thanks a lot RMA! So is that means the first part of getting length missed "SRD 8"? then it make sense.

Thanks again.
 
douyi said:
Thanks a lot RMA! So is that means the first part of getting length missed "SRD 8"? then it make sense.

Thanks again.

Sorry I misunderstood. The first SLD is to make the number in "Instance" as byte number of byte.bits, after that, it stored in pointer like instance.000 which is correct format for a pointer.

But the destination is a DINT not a pointer, how to explain?
 
But the destination is a DINT not a pointer, how to explain?

Well, the dint is just a place to store the pointer for when I need to use it later. I can't store it as a pointer because a DB won't accept the pointer data type.

For instance, I could do something like this:

OB100:
L P#10.0
T MD 20

Later on in the code...
L MD20
LAR2

I can't understand why after load the value from UDTAddress plus 2bytes then shift 3 bits will become "Length", same as "StartPoint"

The Length and StartPoint are not the same. The 2nd byte in an ANY Pointer is the repetition in bytes. I want the length in bits, so I just need to shift by three.

Also, I'm sorry for the confusion caused by my mistake with the SLD8/SRD8. But in case you aren't already confused enough, I'll explain why I did it that particular way. Looking at the code:

L D [AR1,P#6.0]
SLD 3
SRD 3
T #StartPoint

You can see that StartPoint is just a pointer without a data type (refer to Simon's diagram). Later in my code, I can add the data type according to where I want to use it. For instance, I could do this when building an ANY POINTER to be used with SFC20:

L #StartPoint
L P#DIX0.0
OD
T LD[AR1,P#6.0] (creates a pointer to the IDB)


or,

L #StartPoint
L P#M0.0
OD
T LD[AR1,P#6.0] (creates a pointer to a memory byte)

So, I can wait until I actually use the calculated pointer to decide the data type I'm using it with. Just a personal preference.
 
Thanks everyone!

About the Length, before I read the "FC UDT Structure", I thought it suppose to calculate out the length from startpoint to the end automatically, not read a number and all depend on that number - is that what you did in "FC UDT Structure"? I think you have more than enough skills to do it without read that number.

After all, for "length", 'SLD 3' or 'SLD 8' which one is correct?
I think for "StartPoint" it is 'SLD 8' AND 'SRD 8' like RMA said.

So now, let me write what I understood from your program, please tell me if it's right or not. Thanks.

In "FC Start Up":
...
CALL "FC UDT Structure"
UDTAddress:="DB Stations".Station
//Point to DB10.DBX4.0
// that's the start point of "Station" in DB10
// which is the 3rd item (an Array)

StartPoint:=#StationUDTPointer
Length :=#StationUDTLength

In "FC UDT Structure":

L P##UDTAddress
LAR1
//load "DB10.DBX4.0" as a pointer value
//into AR1

L W [AR1,P#2.0]
//load 16-bit value in address "DB10.DBW6"
//which is "DB Stations".Station[1].Configuration.Instance

SLD 3
//Left shift ACCU1 3 bits, the "Instance"
//value become "0000 0000 0000 0bbb bbbb bbbb bbbb b000"
//format as a pointer

T #Length
//pass it to calling block "FC Start Up"

L D [AR1,P#6.0]
//load 32-bit value in "DB10.DBD10" which is
// "DB Stations".Station[1].Configuration.StationPointer

SLD 3
//Should be 'SLD 8'.

SRD 3

//Should be 'SRD 8'. These two are clear ACCU1 bits from 24-31
//make it relative address can be used in local memory

T #StartPoint
//pass it to calling block "FC Start Up"

In "FC Start Up":
...
CALL "FC UDT Structure"
UDTAddress:="DB Stations".Station[1]
StartPoint:=MD28
Length :=MD24
//Point to same address as before "DB10.DBX4.0"
//The MD28 and MD24 should be the same as
//#StationUDTPointer and #StationUDTLength

...
OPN DI 10
L MD 28
LAR2

//Open DB10 as IDB and set startpoint at
//"DB Stations".Station[1]

L #StationUDTLength
L MD 24
/I
Top: T #LoopStations
// #StationUDTlength divided by MD24 and transfer it to
// #LoopStations to do the loop, as I mentioned before,
// the result is 1, so it only did 1 time.

And I agree for #StationUDTlength and MD24 ,it doesn't matter in divid operation if they shift bits or not, but in the future you can still use that as a pointer. I'm still thinking the result isn't 1, I must be wrong, but where?

Thanks.
 

Similar Topics

Hello again..trying something on an existing poorly written program and just wanted to double check something system is an A-B MicroLogix 1200 In...
Replies
5
Views
169
Good morning! Let me start by saying, I am still learning about this type of HMI programming. I recently watched a video about recipes and how it...
Replies
0
Views
71
I have some logic that I have written within a 5380 series controller that tracks the time an event is started, while the event is running an RTO...
Replies
2
Views
93
I have an HMI 2711R - T4T Series B, and I want to know which PLCs, besides Micro 820, can communicate with it.
Replies
2
Views
88
HI i would like to know how to get a variable that will store the amount of times a program has been executed. The issue is I have 3 DBs for 1 FB...
Replies
2
Views
82
Back
Top Bottom