STL Help again!!

FUNCTION "2nd test" : VOID
TITLE =
VERSION : 0.1


VAR_INPUT
DB_Sensor : WORD ;
DB_Sensor_Range_Start : DWORD ;
DB_Timer : WORD ;
DB_Alarm : WORD ;
DB_Alarm_Range_Start : DWORD ;
Sensor_State : BOOL ;
Fault_Delay_Time : INT ;
END_VAR
VAR_TEMP
Temp_TL_Index_No : DWORD ; //Textlist number generated from FC82
Temp_Sensor_Offset : DWORD ;
Temp_Alarm_Offset : DWORD ;
Temp_DB_Sensor : WORD ;
Temp_Sensor_DB : WORD ;
Temp_Timer_Offset : DWORD ;
Temp_Timer_Address : DWORD ;
Temp_DB_Time : WORD ;
Temp_DB_Alarm : WORD ;
Temp_DB_Original : WORD ;
END_VAR
BEGIN
NETWORK
TITLE =

// Store DB active when Entered/restore after processing
L DBNO;
T #Temp_DB_Original;

// sourced from DB41 written by FC82
// Called before this block
// DB41"Station 1" or DB42"Station 2" is already open

L DBW 30;
T #Temp_TL_Index_No;
NETWORK
TITLE =Generate Sensor Address and Test status

L #DB_Sensor; // load the DB Address where sensor state is stored
T #Temp_Sensor_DB;

OPN DB [#Temp_Sensor_DB]; //

L #DB_Sensor_Range_Start; // Load the Byte start address of the sensor Data
SLD 3; // byte offset
L #Temp_TL_Index_No; // Generated Text list Address
+D ;
T #Temp_Sensor_Offset; // Final Sensor Address

//Sensor State ~ High/low for comparison

AN #Sensor_State;
JC OFF;
A DBX [#Temp_Sensor_Offset];
JU TIME;
OFF: AN DBX [#Temp_Sensor_Offset];
NETWORK
TITLE =Time Delay

//Adjust offset to suit Timer range

TIME: L #DB_Timer; // DB of Timers
T #Temp_DB_Time;

L #Temp_TL_Index_No; // Load offset
T #Temp_Timer_Offset;

A "Time_Pulse"; // CPU Clock generated Pulse
JCN END;

L #Temp_Timer_Offset;
SLD 3; // Move to Byte area
T #Temp_Timer_Address;

OPN DB [#Temp_DB_Time]; // Open Timer DB
L DBW [#Temp_Timer_Address]; // Increment Timer
+ 1;
T DBW [#Temp_Timer_Address];

// time preset exceeded?

L DBW [#Temp_Timer_Address];
L #Fault_Delay_Time;
<=I ;
JC END;
NETWORK
TITLE =Write Error Message

//Open Message DB

L #DB_Alarm; // DB for Alarm generation
T #Temp_DB_Alarm;

OPN DI [#Temp_DB_Alarm]; // Open as an Instance
L #DB_Alarm_Range_Start;
SLD 3; //byte offset 40.0
L #Temp_TL_Index_No;
+D ;
T #Temp_Alarm_Offset; // Total Offset

= DIX [#Temp_Alarm_Offset]; // Write Alarm Bit

// Clear Timer value
L 0;
T DBW [#Temp_Timer_Address];
NETWORK
TITLE =Restore open DB prior to block call

END: OPN DB [Temp_DB_Original];


END_FUNCTION

 
Last edited:
STL??? said:
but only an Int value is generated between 0 + 160 to display the message.

ok - if the message integer is in the range 1-160 and it stays at that value for your fault time, you have your error index.


The same fundamental problem with timers exists with your proposed code (if I understand where it will be inserted), namely how do you detect that you have just started timing a particular set of inputs. From what you have posted you need to detect that a step transition has occurred and hence you can reset the timer values for the inputs you are now monitoring - does that make sense ?

A couple of comments on the code itself....

Why not call the block conditionally depending on the system timer bit - that way you only execute the code when you are going to update the counts

The time will be incremented always - you have missed a jump to skip the updating of the timer values
 
Last edited:
The same fundamental problem with timers exists with your proposed code (if I understand where it will be inserted), namely how do you detect that you have just started timing a particular set of inputs. From what you have posted you need to detect that a step transition has occurred and hence you can reset the timer values for the inputs you are now monitoring - does that make sense ?

On the button as usual simon,

If the sensor address changes before the time elapses, next time the sensor is evaluated it already has a partial count.

I need to look again at this tomorrow 🔨

To date its probably the most complex thing i've tried to Code!

Thanks STL
 
A couple of comments on the code itself....

Why not call the block conditionally depending on the system timer bit - that way you only execute the code when you are going to update the counts

The time will be incremented always - you have missed a jump to skip the updating of the timer values

Thats an idea, But i'm still struggling to develop a method. To keep track of the previous Counter and zero it.

Like you say, i could use the index to control which message is displayed and ditch the DB call and evaluation of the sensor.

Ill start from scratch tomorrow and see how i get on.

thanks again Simon
 
The time will be incremented always - you have missed a jump to skip the updating of the timer values

I've tested the code with the status bit set to true and without the indirectly addressed sensor on, the Timer count doesnt increment.
 
a couple of things concerning your use of DW's to count.

1. you are testing M140.0 to M159.7, therefore this bit of code

L #Temp_TL_Index_No; // Load offset
T #Temp_Timer_Offset;

will always be 0 to 7. So your using the same 8 timers 10 times.

You may need something like

L #Max Range No;
L DB_Sensor_Range_Start;
-I;
L #Temp_TL_Index_No;
*I
T #Temp_Timer_Offset;

2. A common mistake by people unused to Siemens bytes and words. Siemens works in bytes not words, therefore DBW0 = DBB0 and DBB1, DBW1 = DBB1 and DBB2, so if you use both, DBB1 will corrupt both. This continues to each DBW you use.

To offset datawords, you must multiply by 2, therefore:

L #Max Range No;
L DB_Sensor_Range_Start;
-I;
L #Temp_TL_Index_No;
*I
L 2;
*I;
T #Temp_Timer_Offset;

A couple of points though,

why not do a loop and test all 160 in one go.

I could be shot down in flames here, but I'm sure there's no need to save the DB that was open in the last block, I'm sure thats auto recovered when you leave the FC. I may be wrong but perhaps test it and see, the saving and recovering may just be unessesary.
 
This bit can be confusing for techs too


//Sensor State ~ High/low for comparison
AN #Sensor_State;
JC OFF;
A DBX [#Temp_Sensor_Offset];
JU TIME;
OFF: AN DBX [#Temp_Sensor_Offset];
NETWORK
TITLE =Time Delay
//Adjust offset to suit Timer range
TIME: L #DB_Timer; // DB of Timers
T #Temp_DB_Time;
L #Temp_TL_Index_No; // Load offset
T #Temp_Timer_Offset;
A "Time_Pulse"; // CPU Clock generated Pulse
JCN END;

You've started the logic on one network and continue on the next, not sure without testing if the RLO resets on a new network or not, but even if it doesn't it would look better as:

NETWORK
TITLE =Time Delay

//Adjust offset to suit Timer range
L #DB_Timer; // DB of Timers
T #Temp_DB_Time;
L #Temp_TL_Index_No; // Load offset
T #Temp_Timer_Offset;

//Sensor State ~ High/low for comparison
AN #Sensor_State;
JC OFF;
A DBX [#Temp_Sensor_Offset];
JU TIME;
OFF: AN DBX [#Temp_Sensor_Offset];
TIME: A "Time_Pulse"; // CPU Clock generated Pulse
JCN END;
 
1. you are testing M140.0 to M159.7, therefore this bit of code

L #Temp_TL_Index_No; // Load offset
T #Temp_Timer_Offset;

Hi Peter,
#Temp_TL_Index_No will have a value between 1-160, which is the sensor range.

I could be shot down in flames here, but I'm sure there's no need to save the DB that was open in the last block, I'm sure thats auto recovered when you leave the FC. I may be wrong but perhaps test it and see, the saving and recovering may just be unessesary.

DB41 is opened at the beginning of the sequence for st1, After the diagnostic has ran, The few networks left reference this DB
in this manner:

L DBW28 etc

So i think its needed.

Going to try and write something based on simons idea, probably be back here in a few hours :unsure:

Thanks for your input
STL
 
STL??? said:
Hi Peter,
#Temp_TL_Index_No will have a value between 1-160, which is the sensor range.
STL


Then this doesn't make sense.

L #DB_Sensor_Range_Start // Load the Byte start address of the sensor Data
SLD 3 // byte offset
L #Temp_TL_Index_No // Generated Text list Address
+D
T #Temp_Sensor_Offset // Final Sensor Address


The pointer is of the format Byte, bit. The last 3 bits of the Double word are the bit address 000 = bit 0 to 111 = bit 7. A number between 1 and 160 will corrupt your whole addressing.





Did you take to comment about the DW using 2 bytes into account as well.
 
I'm bored, so I did a 160 bit loop to test and set all.


First I created a UDT.

udt.JPG



to store all the sensor status


Then created a sensor DB

db1.JPG


when opened looks like

db2.JPG



then created an FC, with the UDT as one of the TEMP declarations

fc1.JPG



Then a bit of code to initialise everything

fc2.JPG



then the loop

fc3.JPG


fc4.JPG


fc5.JPG


The bit where I offset to the next, I had moved from the start of the loop but not compensated for it, so

L 160 // Offset start address of Sensor
L #t_Loop // Data to next Sensor
-I
L 10
*I
T #t_Next_Sensor

should read:

L 161 // Offset start address of Sensor
L #t_Loop // Data to next Sensor
-I
L 10
*I
T #t_Next_Sensor


(GOD I'M BORED)
 
Last edited:
OK,

I have changed the program so i only have to process 1 value at a time,all the value range checking of the index is done in the original block.

i call my block directly after, based on a 1s pulse (thanks Simon!)

This works perfect in the simulator
FUNCTION "3rd test" : VOID
TITLE =
VERSION : 0.1

VAR_INPUT
Timeout : INT ;
Alarm_DB : WORD ;
DB_Alarm_Range_Start : DWORD ;
END_VAR
VAR_IN_OUT
Fault_Timer : INT ;
Index_Value : INT ;
Index_History : INT ;
END_VAR
VAR_TEMP
Temp_DB_Original : WORD ;
Temp_DB_Alarm : WORD ;
Temp_TL_Index_No : DWORD ;
Temp_Alarm_Offset : DWORD ;
END_VAR
BEGIN
NETWORK
TITLE =
L #Index_Value;
L #Index_History;
<>I ;
JC CLR; // zero timer ready for ne
NETWORK
TITLE =Generate Time
//
L #Fault_Timer;
L #Timeout;
>=I ;
JC ALM;
// Increment the timer
L #Fault_Timer;
INC 1;
T #Fault_Timer;
JU NW5;

NETWORK
TITLE =Timeout time exceeded
ALM: L #Alarm_DB; // DB for Alarm generation
T #Temp_DB_Alarm;
OPN DB [#Temp_DB_Alarm]; // Open as an Instance
L #DB_Alarm_Range_Start;
SLD 3; //byte offset 40.0
L #Index_Value;
+D ;
T #Temp_Alarm_Offset; // Total Offset
= DBX [#Temp_Alarm_Offset]; // Write Alarm Bit

NETWORK
TITLE =Prepare ready for next call

CLR: L 0;
T #Fault_Timer;

// Update History
NW5: L #Index_Value;
T #Index_History;

END_FUNCTION



I tried to make a FB and use the Static area as storage, However this caused me more grief, so i went back to a FC

I passed in 0 to 160 and everytime the correct message bit was triggered after the 60 sec delay.

PeterW,
Thanks for taking the time to create that program, i will study it and i'm sure ill learn loads from it!

OPN DB [#Temp_DB_Alarm]; // Open as an Instance
L #DB_Alarm_Range_Start;
SLD 3; //byte offset 40.0
L #Index_Value;
+D ;
T #Temp_Alarm_Offset; // Total Offset
= DBX [#Temp_Alarm_Offset]; // Write Alarm Bit

Could you explain whats wrong with how i generate the Message Offset, i dont understand what you mean in your previous post?

Thanks to all for your Help.
 
Actually now I've woken up, it should be OK as your start point always remains the same.I was thinking the bit range is 0-7, therefore once it got to 8 it would overflow, but of course the overflow is simply changing the byte to point to the next. doh o_O
 
1. How do you clear your alarm bits ?

2. In the following network when you set the alarm bit, the RLO is set due to the fact that you arrive at the ALM label following a JC
As you want to set the alarm bit, why not use the S instruction as using the = may leave a question in some minds that the bit may become a zero or a one. Also, instead of relying on the RLO not being changed after the JC, I use the explicit SET instruction in cases like this. (I wouldn't bother if the S was immediately after the JC)

(My sugggested mods in bold)
Code:
ALM: L #Alarm_DB; // DB for Alarm generation
T #Temp_DB_Alarm; 
OPN DB [#Temp_DB_Alarm]; // Open as an Instance
L #DB_Alarm_Range_Start; 
SLD 3; //byte offset 40.0
L #Index_Value; 
+D ; 
T #Temp_Alarm_Offset; // Total Offset
[b]SET[/b]
[b]S DBX [#Temp_Alarm_Offset]; // Write Alarm Bit[/b]
 
1. How do you clear your alarm bits ?
When fault reset is pressed i use SFC21 FILL to clear the Alarm bit DB.

2. In the following network when you set the alarm bit, the RLO is set due to the fact that you arrive at the ALM label following a JC
As you want to set the alarm bit, why not use the S instruction as using the = may leave a question in some minds that the bit may become a zero or a one. Also, instead of relying on the RLO not being changed after the JC, I use the explicit SET instruction in cases like this. (I wouldn't bother if the S was immediately after the JC)
Good point - One day i will get to grips with this kind of stuff:oops:

One more question guys, How long have you been coding this siemens stuff? i have no S5 experience and have been using S7 for 2 years now. All my learning to date has been through this site!

Thanks again - much apprieciated
 

Similar Topics

Hi, I need to create a FC/FB to sort through DB error messages and prioritise them in the order of Importance. the values generated(x5)...
Replies
15
Views
4,519
Hello nice to meet you, im new in here, I'm currently trying to convert code written in STL for a S7-400 to SCL for an S7-1500, because when i run...
Replies
5
Views
325
Hi! I am working on a project were we will be replacing an 300 CPU with a 1500 CPU and we are working on migrating / converting code. There is a...
Replies
9
Views
1,079
Hello everyone, friends. I asked a similar question before, and you helped, but I'm very weak in STL and I'm having trouble learning it. What I...
Replies
2
Views
744
i hope you could help me to convert the network Stl to lad it's apart from program of machine and i try to find solution for the reason of error...
Replies
10
Views
1,936
Back
Top Bottom