![]() ![]() ![]() ![]() ![]() ![]() |
||
![]() |
||
![]() ![]() ![]() ![]() This board is for PLC Related Q&A ONLY. Please DON'T use it for advertising, etc. |
||
![]() |
![]() |
#1 |
Member
![]() ![]() Join Date: Oct 2005
Location: Damanjodi
Posts: 155
|
![]()
Dear S7 Experts,
After several attempts I have come to conclusion that I should seek your help...The below is the stl source code. FC311 calls FC1008 and DB900 is the data block which is passed into FC1008.. I am not able to intrepret the code and the data movement/manuplation in the DB900...and also I am not getting the concept why the programmer is using SLD3 for multiplication by 8. Advance thanks. FUNCTION FC 311 : VOID TITLE =Pusher VERSION : 0.1 VAR_TEMP sp_push_time_int : REAL ; table : ARRAY [0 .. 19 ] OF REAL ; END_VAR BEGIN NETWORK TITLE =Pusher-Speed_ convert time to valve position (lookUpTable) A M 0.1; = L 84.0; BLD 103; CALL FC 1008 ( Table := DB 900, Input := MD 1652, low := 7.500000e+001, high := 2.100000e+002, invert := L 84.0, output := MD 1644); NOP 0; END_FUNCTION DATA_BLOCK DB 900 TITLE = VERSION : 0.1 STRUCT POS_0 : REAL := 7.500000e+001; POS_05 : REAL := 7.600000e+001; POS_10 : REAL := 7.700000e+001; POS_15 : REAL := 7.800000e+001; POS_20 : REAL := 7.900000e+001; POS_25 : REAL := 8.100000e+001; POS_30 : REAL := 8.500000e+001; POS_35 : REAL := 9.000000e+001; POS_40 : REAL := 9.900000e+001; POS_45 : REAL := 1.290000e+002; POS_50 : REAL := 1.500000e+002; POS_55 : REAL := 1.800000e+002; POS_60 : REAL := 2.100000e+002; POS_65 : REAL := 2.100000e+002; POS_70 : REAL := 2.100000e+002; POS_75 : REAL := 2.100000e+002; POS_80 : REAL := 2.100000e+002; POS_85 : REAL := 2.100000e+002; POS_90 : REAL := 2.000000e+003; POS_95 : REAL := 2.100000e+003; POS_100 : REAL := 2.100000e+002; END_STRUCT ; BEGIN POS_0 := 7.500000e+001; POS_05 := 7.600000e+001; POS_10 := 7.700000e+001; POS_15 := 7.800000e+001; POS_20 := 7.900000e+001; POS_25 := 8.100000e+001; POS_30 := 8.500000e+001; POS_35 := 9.000000e+001; POS_40 := 9.900000e+001; POS_45 := 1.290000e+002; POS_50 := 1.500000e+002; POS_55 := 1.800000e+002; POS_60 := 2.100000e+002; POS_65 := 2.100000e+002; POS_70 := 2.100000e+002; POS_75 := 2.100000e+002; POS_80 := 2.100000e+002; POS_85 := 2.100000e+002; POS_90 := 2.100000e+002; POS_95 := 2.100000e+002; POS_100 := 2.100000e+002; END_DATA_BLOCK FUNCTION FC 1008 : VOID TITLE = VERSION : 0.1 VAR_INPUT Table : BLOCK_DB ; Input : REAL ; low : REAL ; high : REAL ; invert : BOOL ; END_VAR VAR_OUTPUT output : REAL ; END_VAR VAR_TEMP index : INT ; pointer_min : DINT ; pointer_max : DINT ; min : REAL ; max : REAL ; input_int : REAL ; dummy : REAL ; END_VAR BEGIN NETWORK TITLE =limit imput value A M 0.1; = L 26.0; A L 26.0; JNB _001; L #Input; T #input_int; _001: NOP 0; A L 26.0; A( ; L #Input; L #high; >R ; ) ; JNB _002; L #high; T #input_int; _002: NOP 0; A L 26.0; A( ; L #Input; L #low; <R ; ) ; JNB _003; L #low; T #input_int; _003: NOP 0; NETWORK TITLE = OPN #Table; NETWORK TITLE = //5*(index-((max-input)/(max-min))) L 1; //start index T #index; loop: L #index; //create pointer L 4; *I ; SLD 3; T #pointer_max; L #index; //create pointer+1 L 1; -I ; L 4; *I ; SLD 3; T #pointer_min; //compare L #input_int; L DBD [#pointer_max]; <=R ; JCN inc; //calc L DBD [#pointer_max]; L DBD [#pointer_min]; -R ; L 1.000000e-009; // no div by 0 +R ; T #dummy; L DBD [#pointer_max]; L #input_int; -R ; L #dummy; /R ; L #index; ITD ; DTR ; TAK ; -R ; L 5.000000e+000; *R ; T #output; JU end; inc: L #index; L 1; +I ; T #index; JU loop; end: NOP 0; NETWORK TITLE =invert output A #invert; JCN end1; L 1.000000e+002; L #output; -R ; T #output; end1: NOP 0; END_FUNCTION |
![]() |
![]() |
#2 |
Member
![]() ![]() Join Date: Jun 2006
Location: Calgary, AB
Posts: 2,531
|
'also I am not getting the concept why the programmer is using SLD3 for multiplication by 8.'
This is OK if you are confident the result will not overflow. Its to do with binary. Shift Left 1 = Multiply by 2 Shift Left 2 = Multiply by 4 Shift Left 3 = Multiply by 8 Shift Left 4 = Multiply by 16 etc. Example for 8 bits. 0000 0001 = 1 Shift by 1 = 0000 0010 = 2 Shift by 2 = 0000 0100 = 4 Shift by 3 = 0000 1000 = 8 Shift by 4 = 0001 0000 = 16 etc.. edit: ![]() ![]() ![]() Last edited by PeterW; August 7th, 2007 at 02:50 PM. |
![]() |
![]() |
#3 |
Member
![]() ![]() Join Date: Jun 2006
Location: Calgary, AB
Posts: 2,531
|
I also don't have S7, so looking at the code is awkward, but just noticed, the SLD3 is not multiplying by 8, but setting up a pointer. (Should have guessed really).
Pointer format, 32 bits mmmm mmmm 0000 0bbb bbbb bbbb bxxx where: m = code for data type 0 = not used b = byte address x = bit address so the SLD3 is moving the byte address over to the correct area of the double word. |
![]() |
![]() |
#4 |
Member
![]() ![]() Join Date: Jun 2006
Location: Calgary, AB
Posts: 2,531
|
From this point:
Code:
NETWORK TITLE = //5*(index-((max-input)/(max-min))) L 1; //start index T #index; Presets index to 1. Code:
loop: L #index; //create pointer L 4; *I ; SLD 3; T #pointer_max; the loop: part indicates he jumps back to here (as opposed to a LOOP instruction) On the first run index =1, therefore 1 * 4 = 4, shift left 3 and stores at pointer max., this will point to byte 4. Code:
L #index; //create pointer+1 L 1; -I ; L 4; *I ; SLD 3; T #pointer_min; Index = 1, therefore 1-1 = 0, 0*4 = 0, after shifting will point to byte 0. Code:
//compare L #input_int; L DBD [#pointer_max]; <=R ; JCN inc; This is comparing the input against DBD4 If the input is NOT less than or equal to DBD4, it will jump to label inc. Code:
//calc L DBD [#pointer_max]; L DBD [#pointer_min]; -R ; L 1.000000e-009; // no div by 0 +R ; T #dummy; L DBD [#pointer_max]; L #input_int; -R ; L #dummy; /R ; Subtract DBD0 from DBD4 and adds 1 (edit: sorry not 1, but a very small number) (=dummy), he then subtracts the INPUT from DBD4 and divides by the dummy value. Code:
L #index; ITD ; DTR ; TAK ; -R ; L 5.000000e+000; *R ; T #output; JU end; Then he takes the INDEX value and converts from Integer to Double Integer (ITD), then from Double Integer to real (DTR). TAK swaps the ACCU’s around, so the modified INDEX goes to ACCU2 and the previous calc value returns to ACCU 1. He then subtracts the index value from the previous calc and multiples by 0.5. Then transfers it to the output. Had he jumped to inc after the earlier compare, he increments INDEX and goes back to loop. There’s a little bit at the end where he inverts the output if required. I don’t know if I missed it but it looks as if it could go in an eternal loop! If the comparison never allows the program to flow through. Last edited by PeterW; August 7th, 2007 at 03:23 PM. |
![]() |
![]() |
#5 |
Member
![]() ![]() Join Date: Oct 2005
Location: Damanjodi
Posts: 155
|
![]()
Dear PeterW,
I am not able to understand why on the first scan #pointer_max contains/refers to the location DBD4? #pointer_max should contain 32 and L DBD [#pointer_max] should refer to DBD32...Why it is not so here?? OPN #Table //Data Block L #index //index =1 on first instance. L 4 *I SLD 3 T #pointer_max Am I missing a simple thing? |
![]() |
![]() |
#6 |
Member
|
Yes. The last 3 bits in pointer are decoded as number of a bit. That's why there's "SLD 3".
__________________
jacekd |
![]() |
![]() |
#7 | |
Member
![]() ![]() Join Date: Jun 2006
Location: Calgary, AB
Posts: 2,531
|
Quote:
To answer your question, re-look at this. The SDL3 is NOT multiplying by 8. The SLD3 is moving the Number, in the first case 4, to match up with the byte address. 4 = 100 in binary, after SLD3 it = 100000, now match this to the pointer format. mmmm mmmm 0000 0bbb bbbb bbbb bxxx 0000 0000 0000 0000 0000 0010 0000 Taking just the b's which is the byte address bbb bbbb bbbb b 000 0000 0010 0 this = byte 4. |
|
![]() |
![]() |
#8 |
Member
![]() ![]() Join Date: Oct 2005
Location: Damanjodi
Posts: 155
|
![]()
Dear PeterW,
Thank you very much...now I have understood the concept... L 4.000000e+000 T DB1.DBD 24 //In this case the 4.0 will be transferred to DB1.DBD 24 //open DB1 OPN DB1 // load decimal 36 L 36 // multiply with 8 SLD 3 // Transfer the result 8x8=64 to MD30. T MD 30 // Load real number 10.8 L 1.080000e+001 // Transfer to already opened DB1 at memory byte // location specified by the pointer MD30 T DBD [MD 30] So When we use square brackets then compiler treats MD30 as a pointer not its value, which is 64....Binary equivalent of 64 is taken and from that, using rules of pointer addressing its value is obtained to be 36. And finally 10.8 is transferred to DB1.DBD36 |
![]() |
![]() |
#9 | |
Member
![]() ![]() Join Date: Oct 2005
Location: Damanjodi
Posts: 155
|
![]() Quote:
SLD 3 // Transfer the result 36x8=288 to MD30. T MD 30 // Load real number 10.8 L 1.080000e+001 // Transfer to already opened DB1 at memory byte // location specified by the pointer MD30 T DBD [MD 30] So When we use square brackets then compiler treats MD30 as a pointer not its value, which is 288....Binary equivalent of 288 is taken [0001_0010_0000]and from that, using rules of pointer addressing its value is obtained to be [0001_0010_0] or simply [100100]....is equivalent to 36. And finally 10.8 is transferred to DB1.DBD36 |
|
![]() |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Display Modes | |
|
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
Simplify some S7 STL code | userxyz | LIVE PLC Questions And Answers | 13 | November 9th, 2006 08:19 AM |
S7 code optimizing... | Borte | LIVE PLC Questions And Answers | 8 | September 7th, 2005 04:06 AM |
S7 - what's wrong with this code which could cause an endless loop? | RMA | LIVE PLC Questions And Answers | 7 | June 14th, 2005 11:40 AM |
Simulator, Simulation, Shadow Code | Terry Woods | LIVE PLC Questions And Answers | 1 | January 2nd, 2005 03:40 PM |
Self Tuned Pid Code For S7 200 | GOKALP | LIVE PLC Questions And Answers | 1 | April 12th, 2003 02:07 PM |