S7 300 / 400 Arrays, How to loop it through..

adfox

Member
Join Date
Jun 2006
Location
Poland
Posts
334
Hi, I've got a little problem that involves arrays and looping it.

I've got an FB and 3 arrays of 128 bools inside.
One is a list of detected nodes on Profibus.
Second is a list of configured nodes on Profibus.
Third is a list of nodes that got error ( configured but not available, available but not configured ), array index is node's address.

So It looks like this:

Code:
      O(    
      A     #Status_Profi_conf[1]
      AN    #Status_Profi_read[1]
      )     
      O(    
      AN    #Status_Profi_conf[1]
      A     #Status_Profi_read[1]
      )     
      =     #Status_Profi_error[1]

To achieve an effect of having node's status from 1 to 127 I can copy and paste every one and change index, but i'd rather loop thru it. I tried looping and iserting INT/WORD counter into array index with no luck.
When getting to it with a pointer... how can I get to 3 arrays if I have only 2 Address registers... and even if I can hold counter value for example for 24 addres... how to count the P# value to 3.0 bit array adress?
 
Here's one implementation:

Code:
FUNCTION_BLOCK FB 1
TITLE =
VERSION : 0.1

VAR
  Status_Profi_conf : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_read : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_error : ARRAY  [1 .. 128 ] OF BOOL ; 
END_VAR
VAR_TEMP
  LStatus_Profi_conf : BOOL ; 
  LStatus_Profi_read : BOOL ; 
  LStatus_Profi_error : BOOL ; 
  iLoopCount : INT ; 
  iDB : INT ; 
  dwRead : DWORD ; 
  dwConf : DWORD ; 
  dwError : DWORD ; 
END_VAR
BEGIN
NETWORK
TITLE =
      LAR1  P##Status_Profi_read; 
      TAR2  ; 
      +AR1  ; 
      TAR1  #dwRead; 
      LAR1  P##Status_Profi_conf; 
      TAR2  ; 
      +AR1  ; 
      TAR1  #dwConf; 
      LAR1  P##Status_Profi_error; 
      TAR2  ; 
      +AR1  ; 
      TAR1  #dwError; 
      L     DINO; 
      T     #iDB; 
      OPN   DB [#iDB]; 
      L     128; 
L:    T     #iLoopCount; 
      LAR1  #dwRead; 
      A      [AR1,P#0.0]; 
      =     #LStatus_Profi_read; 

      LAR1  #dwConf; 
      A      [AR1,P#0.0]; 
      =     #LStatus_Profi_conf; 

      O(    ; 
      A     #LStatus_Profi_conf; 
      AN    #LStatus_Profi_read; 
      )     ; 
      O(    ; 
      AN    #LStatus_Profi_conf; 
      A     #LStatus_Profi_read; 
      )     ; 
      =     #LStatus_Profi_error; 
      LAR1  #dwError; 
      A     #LStatus_Profi_error; 
      =      [AR1,P#0.0]; 

      L     #dwRead; 
      L     1; 
      +D    ; 
      T     #dwRead; 
      L     #dwConf; 
      L     1; 
      +D    ; 
      T     #dwConf; 
      L     #dwError; 
      L     1; 
      +D    ; 
      T     #dwError; 

      L     #iLoopCount; 
      LOOP  L; 
END_FUNCTION_BLOCK
 
There are many ways to do this, here's another (shorter) block that uses AR2

Code:
FUNCTION_BLOCK FB 3
TITLE =
VERSION : 0.1

VAR
  Status_Profi_conf : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_read : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_error : ARRAY  [1 .. 128 ] OF BOOL ; 
END_VAR
VAR_TEMP
  iLoopCount : INT ; 
  dwAR2Store : DWORD ; 
END_VAR
BEGIN
NETWORK
TITLE =
      TAR2  #dwAR2Store; 
      L     128; 
L:    T     #iLoopCount; 
//no FB interface access allowed in this loop !
      O(    ; 
      A     #Status_Profi_conf[1]; 
      AN    #Status_Profi_read[1]; 
      )     ; 
      O(    ; 
      AN    #Status_Profi_conf[1]; 
      A     #Status_Profi_read[1]; 
      )     ; 
      =     #Status_Profi_error[1]; 
      +AR2  P#0.1; 
      L     #iLoopCount; 
      LOOP  L; 
      LAR2  #dwAR2Store; 
END_FUNCTION_BLOCK
 
XOR 32 bits at a time:-

Code:
FUNCTION_BLOCK FB 4
TITLE =
VERSION : 0.1

VAR
  Status_Profi_conf : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_read : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_error : ARRAY  [1 .. 128 ] OF BOOL ; 
END_VAR
VAR_TEMP
  iLoopCount : INT ; 
  iDB : INT ; 
  dwRead : DWORD ; 
  dwConf : DWORD ; 
  dwError : DWORD ; 
END_VAR
BEGIN
NETWORK
TITLE =
      LAR1  P##Status_Profi_read; 
      TAR2  ; 
      +AR1  ; 
      TAR1  #dwRead; 
      LAR1  P##Status_Profi_conf; 
      TAR2  ; 
      +AR1  ; 
      TAR1  #dwConf; 
      LAR1  P##Status_Profi_error; 
      TAR2  ; 
      +AR1  ; 
      TAR1  #dwError; 
      L     DINO; 
      T     #iDB; 
      OPN   DB [#iDB]; 
      LAR1  #dwRead; 
      L     D [AR1,P#0.0]; 
      LAR1  #dwConf; 
      L     D [AR1,P#0.0]; 
      XOD   ; 
      LAR1  #dwError; 
      T     D [AR1,P#0.0]; 
      LAR1  #dwRead; 
      L     D [AR1,P#4.0]; 
      LAR1  #dwConf; 
      L     D [AR1,P#4.0]; 
      XOD   ; 
      LAR1  #dwError; 
      T     D [AR1,P#4.0]; 
      LAR1  #dwRead; 
      L     D [AR1,P#8.0]; 
      LAR1  #dwConf; 
      L     D [AR1,P#8.0]; 
      XOD   ; 
      LAR1  #dwError; 
      T     D [AR1,P#8.0]; 
      LAR1  #dwRead; 
      L     D [AR1,P#12.0]; 
      LAR1  #dwConf; 
      L     D [AR1,P#12.0]; 
      XOD   ; 
      LAR1  #dwError; 
      T     D [AR1,P#12.0]; 
END_FUNCTION_BLOCK
 
That still looks ugly

Why are you messing around with the index registers?
Why not load the DWORDS directly?
Code:
     LD ThisDword[0]
     X   ThatDWord[0]
     ST ResultDWORD[0]
     LD ThisDword[1]
     X   ThatDWord[1]
     ST ResultDWORD[1]
     LD ThisDword[2]
     X   ThatDWord[2]
     ST ResultDWORD[2]
     LD ThisDword[3]
     X   ThatDWord[3]
     ST ResultDWORD[3]
It should be that simple. If the S7 is too crippled to do that then
Code:
FUNCTION_BLOCK FB 4
TITLE =
VERSION : 0.1

VAR
  Status_Profi_conf : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_read : ARRAY  [1 .. 128 ] OF BOOL ; 
  Status_Profi_error : ARRAY  [1 .. 128 ] OF BOOL ; 
END_VAR
VAR_TEMP
  iLoopCount : INT ; 
  iDB : INT ; 
  dwRead : DWORD ; 
  dwConf : DWORD ; 
  dwError : DWORD ; 
END_VAR
BEGIN
NETWORK
TITLE =
      LAR1  P##Status_Profi_read; 
      TAR2  ; 
      +AR1  ;
      L     DINO; 
      T     #iDB; 
      OPN   DB [#iDB];  // I KNOW WHY THE UP TO HERE IS NECESSARY BUT IT SHOULDN'T BE

      L     D [AR1,P#0.0];    // LEAN AND MEAN 
      L     D [AR1,P#16.0]; 
      XOD   ; 
      T     D [AR1,P#32.0]; 

      L     D [AR1,P#4.0]; 
      L     D [AR1,P#20.0]; 
      XOD   ; 
      T     D [AR1,P#36.0];
 
      L     D [AR1,P#8.0]; 
      L     D [AR1,P#24.0]; 
      XOD   ; 
      T     D [AR1,P#40.0]; 
      L     D [AR1,P#12.0];
 
      L     D [AR1,P#28.0]; 
      XOD   ; 
      T     D [AR1,P#44.0]; 
END_FUNCTION_BLOCK
Now don't complain about the hard coded offsets to me. Complain to the people that don't permit symbolic offsets. These should be computed at compile time NOT during run time.
 
Peter, it may be lean and mean, but only until he changes the array and forgets to change the code. This should be done symbolically, or at a minimum, with caluclated offsets so the code works even if the array changes structure.
 
Peter, it may be lean and mean, but only until he changes the array and forgets to change the code. This should be done symbolically, or at a minimum, with caluclated offsets so the code works even if the array changes structure.
So how does one do this at compile time and symbolically? I could do this with my 8080 assembler back in the 70s.
 
Yet another
Code:
FUNCTION_BLOCK FB 2
TITLE =
VERSION : 0.1


VAR
  Confi : ARRAY  [0 .. 128 ] OF BOOL ;    
  Read : ARRAY  [0 .. 128 ] OF BOOL ;    
  Error : ARRAY  [0 .. 128 ] OF BOOL ;    
END_VAR
VAR_TEMP
  Counts : WORD ;    
END_VAR
BEGIN
NETWORK
TITLE =

      OPN   DI    20; 
      LAR1  P#0.0; //Configured address
      LAR2  P##Read; //Read address
      L     129; 
a1:   T     #Counts; 
      O(    ; 
      A     DIX [AR1,P#0.0]; 
      AN     [AR2,P#0.0]; 
      )     ; 
      O(    ; 
      AN    DIX [AR1,P#0.0]; 
      A      [AR2,P#0.0]; 
      )     ; 
      =     M [AR1,P#0.0]; 
      +AR1  P#0.1; 
      +AR2  P#0.1; 
      L     #Counts; 

      LOOP  a1; 
      L     MD     0; 
      T     DID   36; 
      L     MD     4; 
      T     DID   40; 
      L     MD     8; 
      T     DID   44; 
      L     MD    12; 
      T     DID   48; 


END_FUNCTION_BLOCK
 
Manmeet - Why have you hard coded the DI number ?

When using indirect addressing in FB's, always test the FB's operation as a multiple instance making sure it is not the first entry in the STAT section.
 
So how does one do this at compile time and symbolically? I could do this with my 8080 assembler back in the 70s.

LD shows one example that is symbolic, and it works fine. I do it that way all the time. Again, think in terms of a name space, and AR2 is just used to point to another name space, much as call instances are called in higher level languages.

The main diifference is that I would have used the XN instruction:

XN M 10.0
XN M 10.1
= M 10.2

And, I would have defined a variable at startup that defined the number of bits in the array, and then the code would still work if the array changed (i.e, 128 to 256).

There are other ways as well. I just wrote a simulator that broadcasts UDP messages from 60 controllers to a java app I wrote, and I change the structure of the DBs and UDTs all the time without touching any code, and all my code is symbolic. I don't think there is an single instance of something like D[ar1,P#0.0]. My basic rule of thumb is that I should be able to change something in one place without affecting a dozen other places. Otherwise, I'm doing it wrong.


I'm not sure what this has to do with an 8080 assembler from the 70s (nothing against the 8080). I can't run MS Excel in an S7 either, but I don't get worked up about it.
 

Similar Topics

Hello everyone, One of our machine we use Siemens Cpu315-2dp. And this cpu communicate with 4 Lenze servo drives series 9300 via profibus. Also...
Replies
0
Views
141
Hi guys, I'm having problems converting WinAC (WinLC RTF F application) to S7 300 project based on CPU 319F-3PN or S7 400/416F-3PN. The problem is...
Replies
0
Views
594
Hello All I hope you are well and safe. I have a problem that I could use your appreciated input for: SW: SIMATIC MANAGER v5.5 SP3 HW1...
Replies
2
Views
1,201
Hi What stage of its life cycle, S7-300/400 controllers are at now? In my existing unit, we are using these controller and in near futher there is...
Replies
8
Views
6,879
We all know that the S7-300 range has been around for an age and the new S7-1200 & S7-1500 ranges are well established any one know if the...
Replies
4
Views
3,711
Back
Top Bottom