S7 DB copy data to other DB

theDave2

Member
Join Date
Aug 2004
Location
Rochester, NY
Posts
467
I can do this in AB and other plcs, but how to in S7:

DB8:

r1a real
r1b real
r1c real
r1d real
r1e real
r2a real
r2b real
r2c real
r2d real
r2e real
r3a real
r3b real
r3c real
r3d real
r3e real
...

r99a real
r99b real
r99c real
r99d real
r99e real

DB10:
r1 real
r2 real
r3 real
...
r99 real



Copy every 5th Real (4bytes) in DB8 to DB10.
This is a recipe thing. DB8 has 5 (a-e) recipes of 99 entries each. I want to copy one set of values into DB10.

Tx,Dave
 
I would swap the order of recipe number and value around.
Recipes_save.rec.vals[j]
i=the recipe number.
j=the value within a recipe.

UDT1: Recipe_framework
vals: ARRAY[1..99] OF REAL

DB8: Recipes_saved
rec: ARRAY[1..5] of UDT1

DB10: Recipe_active
rec: UDT1

Then you can use use for example SFC20 BLKMOV to do like this:

CALL "BLKMOV"
SRCBLK :="recipes_saved".rec[5]
RET_VAL:=MW10
DSTBLK :="recipe_active".rec

If the source recipe has to be dynamically selectable, then it gets more complicated.
It requires either pointers with STL programming (a bit complicated), or indexing in SCL (easy).

In SCL you can just write
Code:
 FUNCTION FC1 : INT 
VAR_TEMP
	i, j : INT ;// Temporary Variables
END_VAR
	i:=2 ;
	FOR j:= 1 TO 99 BY 1 DO
	recipe_active.rec.vals[j] := recipes_saved.rec[i].vals[j] ;
	END_FOR ;
   
	FC1 := 100;
END_FUNCTION
 
I'm looking for how to do this in STL, I guess. The data structures are as defined, no arrays.

If the .pdf books that came with S7 showed me how to do indirect addressing: how to define forming a pointer; how to specify indirect load / store I'd be only 1/2 done.

As I've not done any STL, I'd be spending the most part of a day trying things. I don't have an hour, much less a day.
 
krk said:
Simon G posted a function to do just that on an earlier thread..

Simon says there: "You can either pass the DB as a parameter, or, pass the db number as a parameter"

Which of course, I have no clue on how to do. Second, it copies the whole DB, anyone what to show me where to change it to copy every 5th real ?

Please read OP. If I knew STL, I would have coded it.
 
If it is an absolute requirement that you must keep the way it is ordered, with the lower order numeral before the higher order numeral, then I can suggest to make a 2-dimensional array.
Recipes_saved: ARRAY [1..99,1..5] of REAL
Recipe active: ARRAY [1..99] of REAL

Again, it is easy-peasy in SCL:
Code:
FUNCTION FC1 : INT
// copy from save recipe to active recipe
VAR_INPUT
	i : INT ;
END_VAR 
VAR_TEMP
	j : INT ;
END_VAR
  IF i>0 AND i<6 THEN
	FOR j:= 1 TO 99 BY 1 DO
	  recipe_active.vals[j] := recipes_saved.vals[i,j] ;
	END_FOR ;
  END_IF ;
   
	FC1 := 100;
END_FUNCTION

FUNCTION FC2 : INT
// copy from active recipe to save recipe
VAR_INPUT
	i : INT ;
END_VAR
VAR_TEMP
	j : INT ;
END_VAR
  IF i>0 AND i<6 THEN
	FOR j:= 1 TO 99 BY 1 DO
	  recipes_saved.vals[i,j] := recipe_active.vals[j] ;
	END_FOR ;
  END_IF ;
   
	FC2 := 100;
END_FUNCTION

I can send you the compiled blocks if you want to.
Anyway, if you plan on doing a lot of this, then I really recommend to spend what it costs to get SCL or (more favourable) a power pack to go to STEP7 PRO.
 
JesperMP said:
If it is an absolute requirement that you must keep the way it is ordered, with the lower order numeral before the higher order numeral, then I can suggest to make a 2-dimensional array.
Recipes_saved: ARRAY [1..99,1..5] of REAL
Recipe active: ARRAY [1..99] of REAL

Again, it is easy-peasy in SCL:
Code:
FUNCTION FC1 : INT
// copy from save recipe to active recipe
VAR_INPUT
	i : INT ;
END_VAR 
VAR_TEMP
	j : INT ;
END_VAR
IF i>0 AND i<6 THEN
	FOR j:= 1 TO 99 BY 1 DO
	 recipe_active.vals[j] := recipes_saved.vals[i,j] ;
	END_FOR ;
END_IF ;
 
	FC1 := 100;
END_FUNCTION
 
FUNCTION FC2 : INT
// copy from active recipe to save recipe
VAR_INPUT
	i : INT ;
END_VAR
VAR_TEMP
	j : INT ;
END_VAR
IF i>0 AND i<6 THEN
	FOR j:= 1 TO 99 BY 1 DO
	 recipes_saved.vals[i,j] := recipe_active.vals[j] ;
	END_FOR ;
END_IF ;
 
	FC2 := 100;
END_FUNCTION

I can send you the compiled blocks if you want to.
Anyway, if you plan on doing a lot of this, then I really recommend to spend what it costs to get SCL or (more favourable) a power pack to go to STEP7 PRO.

I think reading between the lines he wants it in STL :)
 
Simon says there: "You can either pass the DB as a parameter, or, pass the db number as a parameter"
As a parameter the source DB would be DB8 so call FC200 and enter DB8 or use 8 if you want to use the DB Number,dbDestinationDB would be DB10

Second, it copies the whole DB, anyone what to show me where to change it to copy every 5th real ?
No it doesn't - iSourceByteOffset and iDestinationByteOffset determine where the data start address is and destination start address and iNumberOfBytes determines the number of Bytes transfered.
 
Last edited:
I thought id post the code from post 4 here as then we wont have to keep jumping back and fro (it will help me anyways!)


Originally Posted By Simon G

Code:
FUNCTION FC200 : VOID
TITLE =transfer bytes between db's
//Transfer bytes of data between data blocks using SFC20
//
VAR_INPUT
dbSourceDB : BLOCK_DB ; //source data block
iSourceDBNumber : INT ; //source data block number (set to zero to use above)
iSourceByteOffset : INT ; //source data byte offset 
dbDestinationDB : BLOCK_DB ; //destination data block
iDestinationDBNumber : INT ; //destination data block number (set to zero to use above)
iDestinationByteOffset : INT ;	//destination data byte offset
iNumberOfBytes : INT ;	//number of bytes to xfer
END_VAR
VAR_OUTPUT
iMoveResult : INT ; //result from block xfer SFC20
END_VAR
VAR_TEMP
pSourceDB : ANY ; 
pDestDB : ANY ; 
END_VAR
BEGIN
NETWORK
TITLE =any pointer for source
	 LAR1 P##pSourceDB; 
	 L	 W#16#1002; //specify ANY pointer, type 02 = BYTE
	 T	 W [AR1,P#0.0]; 
	 L	 #iNumberOfBytes; //number of bytes to transfer
	 T	 W [AR1,P#2.0]; 
	 L	 0; 
	 L	 #iSourceDBNumber; //if iSourceDBNumber = 0 then 
	 ==I ; // opn db and use DBNO to find number
	 JC	opnS; // else use iSourceDBNumber
	 JU	trnS; 
opnS: OPN #dbSourceDB; 
	 L	 DBNO; //data block to use
trnS: T	 W [AR1,P#4.0]; 
	 L	 DW#16#84000000; //global data block for area pointer
	 L	 #iSourceByteOffset; 
	 SLD 3; 
	 +D	; 
	 T	 D [AR1,P#6.0]; //start of data block
NETWORK
TITLE =any pointer for destination
	 LAR1 P##pDestDB; 
	 L	 W#16#1002; //specify ANY pointer, type 02 = BYTE
	 T	 W [AR1,P#0.0]; 
	 L	 #iNumberOfBytes; //number of bytes to transfer
	 T	 W [AR1,P#2.0]; 
	 L	 0; 
	 L	 #iDestinationDBNumber; //if iDestinationDBNumber = 0 then 
	 ==I ; // opn db and use DBNO to find number
	 JC	opnD; // else use iDestinationDBNumber
	 JU	trnD; 
opnD: OPN #dbDestinationDB; 
	 L	 DBNO; //data block to use
trnD: T	 W [AR1,P#4.0]; 
	 L	 DW#16#84000000; //global data block for area pointer
	 L	 #iDestinationByteOffset; 
	 SLD 3; 
	 +D	; 
	 T	 D [AR1,P#6.0]; //start of data block
NETWORK
TITLE =copy data
	 CALL "BLKMOV" (
		 SRCBLK				 := #pSourceDB,
		 RET_VAL				 := #iMoveResult,
		 DSTBLK				 := #pDestDB);
	 NOP 0; 
NETWORK
TITLE =Make sure the ENO shows the BLKMOV result
	 A	 BR; // BR is 1 for no error
	 JC	ok; 
	 JU	nok; 
ok: SET ; // Make the ENO high
	 SAVE ; 
	 JU	end; 
nok: CLR ; // Make the ENO low
	 SAVE ; 
end: NOP 0; 
END_FUNCTION
 
Here's a quick hack that will get you where you need to go. In the long run, you really should arrange your DBs so that they can easily be pointed to symbollically to make stuff like this much easier, for instance if someone needed to add a sixth element to the recipes for some reason (not that that would ever happen....)

Anyway, you can do it with a loop without calling any functions (you will have to define a local INT called LoopCounter):

OPN DB 8
OPN DI 10

LAR1 P#0.0

L 99
top: T LoopCounter
L DBD[AR1, P#0.0]
T DID[AR1, P#0.0]
+AR1 P#20.0
L LoopCounter
LOOP top


I don't know which of the five elements you need to copy, so you might have to change your starting point. Also, just use the Siemens help to see what each instruction does. I did it off the top of my head, so there might be a problem or two, but it will get you started.
 
Here's my implementation. This has been tested in the simulator.

Code:
FUNCTION FC 1 : VOID
TITLE =
VERSION : 0.1
 
VAR_INPUT
iRecipe : INT ; //0=a, 1=b, 2=c, 3=d, 4=e
END_VAR
VAR_TEMP
iLoopCount : INT ; 
END_VAR
BEGIN
NETWORK
TITLE =
 
	 OPN DB	 8; //source DB
	 OPN DI	10; //Destination DB
	 LAR1 P#DBX 0.0; //Source start of data
	 L	 #iRecipe; 
	 SLD 5; 
	 +AR1 ; 
	 LAR2 P#DIX 0.0; //Destination start of sdata
	 L	 99; //loop count, 99 double words
A:	T	 #iLoopCount; //update loop count
	 L	 D [AR1,P#0.0]; //get source data
	 T	 D [AR2,P#0.0]; //write to destination
	 +AR1 P#20.0; //point 5*4 bytes to next real for source
	 +AR2 P#4.0; //point to next real for destination
	 L	 #iLoopCount; //test for end of loop
	 LOOP A; 
	 SET ; 
	 SAVE ; 
END_FUNCTION
 
Last edited:
theDave2 said:
Copy every 5th Real (4bytes) in DB8 to DB10.
This is a recipe thing. DB8 has 5 (a-e) recipes of 99 entries each. I want to copy one set of values into DB10.

What are you trying to do exactly? Do you have 99 recipes of 5 elements, or 5 recipes of 99 elements? And do you want to copy every 5th real as you said, or do you want to copy every fifth set of reals?
 

Similar Topics

This feels like a simple, elementary question, but I am a Siemens novice and know there are experts here. My S7-1500 project (TIA Portal v17) has...
Replies
10
Views
2,698
Hi everyone! I am working on a Siemens plc (1200/1500), and I have two instruction that i have to perform. A) data structure (40 bools, 40...
Replies
3
Views
2,449
Hello! I am completely new to PLCs, so I apologize in advance if this is a dumb question. I have a device that sends out its data as a number of...
Replies
5
Views
2,134
Hello, I am new to Siemens' Simotion Scout software. I looked for a thread that might include this but...I have a CU320 and an existing project...
Replies
9
Views
2,635
In a few months I'll be decommissioning a PLC-3. We have a DOS VM with the AB6200 software that can apparently go online with this beast. I say...
Replies
1
Views
1,457
Back
Top Bottom