Program Structure

S7Guy said:
I like to add comments liberably as well, but not within the comment header of the network

I do similar, sometimes it can be just a single line identifying what the next group of instructions are about.
 
... hmmm...
... hmmm...
... hmmm...
... hmmm...
... hmmm...
... hmmm...
... hmmm...
... hmmm...
... hmmm...


Damn... NOT THAT ANYONE SHOULD TRY TO PLEASE ME...

...but I am not pleased, not pleased at all, with the signal names (especially the signal names), nor the comments. Nor, for that matter, many of the presented organizational concepts.

Yeah... I'm workin' on an explanation of my concerns with what I have seen, and my version of how it should be. I'll be back... right after this word from our sponsors.
 
I've been hammering the idea for years that the specific "NAMES" given to any conditions (Inputs, Outputs, and Internal (Control) Relays) are VERY, VERY IMPORTANT for understanding the essence of the particular signal and the part it plays!

If the "Name" is properly specified... and I really mean "properly specified"... then, comments for that particular Input, Output, Internal (Control) Relay, should be supervoulous, or, at least, redundant!

In general, you should not need to create comments for a particular "rung". Granted... some "rungs" are complicated in themselves and bear at least a little explanation.

However, in general, simple rungs should be "self-explanatory". That is, if properly named conditions are read in the form of a question... in their particular combinations, that reading should provide a reasonable description, explanation, in itself, thus eliminating the need for the "comment".

It is reasonable to expect that a particular "rung" is just one of a number of "rungs" in a "module". The particular "module" might actually be a "sub-module" of a greater "module"... but the point is, the single "rung" is usually just one part of something greater.

Without a doubt... there should be a HUGE comment describing the purpose and operation of the particular "greater" entity. That "greater" entity will consist of at least a few rungs.

Let's look at the example presented by PeterW...

A -motorA // If the overload is OK when required to Run
AN -motorA_O/L
= -Run_Motor //Then start the drive

Doesn't the above code (and comment) look like this in Ladder...

// If the overload is OK when required to Run then start the drive //

-motorA
-motorA O/L
---| |-------|/|-------( ) -Run_Motor


.
Now... piece by piece...

-motorA... What is that? What does it mean? Is there an implied question in there somewhere?

-motorA_O/L... I can see what it is... but, what is the implied question?

-Run_Motor... If this output is supposed to be a signal to a "drive" (as indicated in the comment - I assume a "frequency drive") then this signal name should indicate that it is "talking" directly to the "drive"... the "drive" is being told to run... not the motor. (Hey... it's not my design.)

What is this about an "implied question"?

Back to basics... ---| |--- and ---|/|--- are questions.

---| |--- asks the question... is the signal associated with the "named" condition ON?
That is... is the named condition TRUE?

---|/|--- asks the question... is the signal associated with the "named" condition OFF?
That is... is the named condition FALSE?

Any name, such as "-motorA", even with a comment that it is an input from "-motorA", is non-informative. Even though it can be seen to be an input-element (possibly a real Input from the field, or, an internal input generated in some other rung, or perhaps from an HMI) the "essesnce", or the "nature", of the signal is NOT indicated.

If the "name" can NOT be expressed in the form of a question (YES! We are playing JEOPARDY! here...), then that "name" is a "cryptic-name".

With that in mind, try this...

// While "Call for Run Motor-A" is ON, if "Motor-A O/L is Tripped" is OFF, then...
turn ON "Run Motor-A Drive" //

Call Motor-A
for Run O/L is
Motor-A Tripped
---| |-------|/|-------( ) Run Motor-A Drive


.
In STL form...

// While "Call for Run Motor-A" is ON, if "Motor-A O/L is Tripped" is OFF, then...
turn ON "Run Motor-A Drive" //

A Call_for_Run_Motor_A
AN Motor_A_O/L_is_Tripped
= Run_Motor_Drive_A


.
Notice how the comment is nothing more than a straight reading of the rung... that is redundancy!

If you have several copies of this rung for various motor-drives... and then, if you really feel the urge to comment, then you could develop a "generic comment" that would apply to all of the copies...

// While the call to run the motor signal is ON... if the motor overload tripped
signal is OFF, then... turn ON the output to run the drive for that motor. //


.
Notice that it is very "generic", and yet, it applies correctly to the rung above. However, don't you also see that, at least in this case, with properly specified "names", the comment is really unnecessary?

Granted... there are plenty of cases where the particular "rung" (in Ladder or STL) is much more complicated than a simple serial-pair. The more complicated the rung, the more likely that a comment, or two, is necessary.

This is especially true when it comes to data manipulation (moving, math, etc.). If it is not clearly apparent what is happening... then there should definitely be an explanatory comment!

However, the more properly the code is layed out, and the more properly the players are named, then the more likely the "rung" is self-explanatory, and less likely to need a comment.

I am NOT trying to prevent the existence of comments! I like comments.

However, what I AM trying to do is MINIMIZE THE CRITICAL NEED for those comments!

Bear in mind that, to "minimize" does NOT necessarily mean to "eliminate"!

The more "cryptic" the names, the more necessary comments become. It could reach the point where you spend more time creating comments than coding. All because of lousy "names".

CONTINUED...
 
Moving on...

PROGRAM ORGANIZATION:

Now, regardless of the programming method, Ladder, STL, Staging, whatever..., all programs should be MODULARIZED to the extent of the process.

This means... starting at the highest level, namely THE PROCESS itself, start breaking the process down into its major FUNCTIONAL COMPONENTS. Those components should be easily, and clearly
Identified in terms of their particular high-level activities. For example, A Punch Press Operation could be broken down to FEEDER, LOADER, PUNCH, UNLOADER, STACKER. It should be easy for you to identify these major activities if you consider what you would do if you had to perform the entire process manually (by-hand) on a SINGLE PART!

Don't confuse yourself by trying to envision the automatic processing where parts are entering and leaving all of the various sections of the process at the same time. That issue will take care of itself if you properly design the process, starting with specifying the process in terms of a single part.

I think I can get away with saying that ALL PROCESSES HAVE LENGTH. The process described above certainly does. In ALL CASES, there is at least, a GOZINTA... a SUMTHIN... and a GOZOTTA.

"GOZINTA" = "GO-ZIN-TA" = "GOES INTO"
The "gozinta" is that part of the process where material enters. Even if hand-fed, this part exists and is a separate part of the process from the others.

"SUMPM" = "SUMP-MM" = "SOMETHING"
The "sumpm" is that part of the process where a major "something" happens to the material.

"GOZOTTA" = "GOZ-OTT-A" = "GOES OUT OF"
The "gozotta" is that part of the process where the material, already processed by the "SUMTHIN", leaves that part of the process. Even if the part is removed by-hand, this part exists and is a separate part in the process.

The following is a simplified view of a few unique processes...

Gozinta - Sumpm - Gozotta
(a simple one-operation process at one station)

Gozinta - Sumpm - Sumpm - Gozotta
(a simple two-operation process at one station)

Gozinta - Sumpm - Gozotta - Gozinta - Sumpm - Gozotta
(a two-station process with one-operation at each station)

Gozinta - Sumpm - Gozotta - Gozinta - Gozotta - Gozinta - Sumpm - Gozotta
(a two-station process with one-operation at each station, with a stand-alone transfer-operation between stations)

In general, each "module" consists of a Gozinta, a Sumpm, and a Gozotta. However, as indicated above, a "module" could be a simple transfer-operation without actually performing an operation that causes some sort of change in the material.

Large, complicated processes tend to consist of many of these in various combinations. Looking at the entire process, at the same time, can be quite overwhelming. However, if you break the process down into the basic "modules", as described in the previous paragraph, even the largest process becomes quite manageable.

For myself, this ALWAYS involves a lot of pencil & paper work.

Anyone that would attempt to develop even a smaller medium-sized project by "programming on-the-fly" is... nuts. Doing so can not help but become a serious case of "spaghetti-code". A debugging nightmare! (...even if there are tons of comments!)

Once you identify the various "modules" (these are the high-level modules) you can start considering the content of each module, separately, as if each was the entire process in itself.

In doing so, you might very well find that the particular module consists of "lesser" sets of Gozinta-Sumpm-Gozotta. If so, then those are "sub-modules" within the "module". Continue to identify all of those "sub-modules" within that "module".

After doing so, then examine the content of each of those "sub-modules". In very complicated systems, don't be surprised if you find lesser modules within those "sub-module"; those lesser modules are called "sub-sub-modules".

After you identify all of the various modules, at all levels, within the high-level module, it's time to get to work developing general descriptions of the various modules. The fact that you can identify these as particular modules means that you already have an idea of the purpose of the particular modules.

Start at the highest level and work your way down. Keep those descriptions as general as possible in terms of the process-oriented-function provided. As you work your way down, the descriptions will become more specific on their own. This is because you are moving closer and closer to the final driven devices. When you get to the lowest-level module for any particular digital-device (ON/OFF), that final device is going to be either ON, or OFF.

Did I mention that this part of the development process might involve going from top-to-bottom, and bottom-to-top, perhaps several times? Well... most of the time... it does... especially in the larger, more complicated, processes.

Now, with respect to those lowest-level modules which usually address the actual control of a driven device...

In some cases, simpler cases, there is one, and only one, "cause" for a particular output device to be ON. In other cases, more complicated cases, there might be upto several different "causes" for a particular output device to be ON.

If there is one, and only one, "cause"... then that specific output device should be controlled directly by the code that generates the "cause".

If there are several "causes", then that specific output device should be controlled directly by "flags" from the various "causal-codes", as well as E-Stop's, device faults, and anything else that should prevent the device from being "told" to turn ON.

The purpose of this method is to make it as easy as possible to troubleshoot process problems.

Device E-Stop
Cause-A Faulted is OK
---| |---+---|/|------| |----( ) Turn ON Device
|
Cause-B |
---| |---+
|
Cause-C |
---| |---+
|
Cause-D |
---| |---+


.
Examples of "causal factors" might be... "Auto-Cycle the Device", "Manual-Cycle the Device", "Manual-Jog the Device", "Simulation-Cycle the Device".

In troubleshooting the control of this device, you would come directly to this rung to see if the device is being "told" to go ON. If so, and the device is not operating, then the problem is external.

The "Device Faulted" condition depends on what you are monitoring. You could be monitoring a signal from a device controller (perhaps an AUX Contact), and/or you could be monitoring the activity expected after turning ON the device.

In any case, the "Fault" condition shows up here! NOT back in the particular "driving-code"!

It is very beneficial to KNOW that the driving-code is operating properly! And then, at the same time, it is beneficial to KNOW that the device is being prevented from running because of a particular "Fault" condition.

If you KNOW that the device should be responding to a particular "cause" then you should be able to easily see if the "cause" is present. If so, then checking the "Fault" and E-STOP should clearly indicate the basic reason that the device is not functioning.

The E-STOP is self-explanatory.

The "Device Faulted" condition requires a little more investigation... in the code.

If the expected "causal factor" is NOT present, then the lack of that "causal factor" requires more investigation at that particular "causal factor" code.

For example... the particular device should be ON right now... it's not.

You KNOW that the device should be ON under the "Auto-Cycle the Device" condition.

You look at the Device Output rung... the E-STOP is OK, the Device Faulted signal is OK... but you also see that the "Auto-Cycle the Device" signal is NOT present.

You then perform a "SEARCH" for the rung containing that particular Internal Control-Relay as an Output. Or, in "lame-mode"... you look up the particular bit in your hard-copy cross-reference, and look in that listing for where that bit is activated/de-activated.

One way or another, you go to the rung that generates the particular signal. You then go through that rung to determine what is missing. If necessary, you follow that missing-signal back to it's control-rung.

Continue doing so until you finally derive the REAL cause of the failure.

And if you are worth your salt, this should ALWAYS be a case of an I/O failure, and NEVER, NEVER, NEVER, a case of code-failure. "Code-Failure" occurs most often with bit-chasing, spaghetti-code... you know, the ones where someone decided to program on-the-fly.

Oh, goodness me... I find that I have gone on, and on, and on... Oh, my goodness... you must think me absolutely boring... I'm so sorry.

So... maybe what I have said... boring, or otherwise, is at least food for thought.

Basically... I have to forcibly keep myself from writing that damned book here... on-line.

If you want the book... yer gonna have to pay for it! Fair is fair... no?

(520)
 
Last edited:
Wow Terry, I was wondering how you managed to keep out of the thread then suddenly in 3 entries you manange a ratio of 3 words to everyone elses 1!

As with most of your posts I agree and disagree with various points.

I agree with your 'on the fly comments' and your description of how to write the code is similar to my outlook and sounds more than similar to KISS :unsure: .

The comments I'm not so in agreement with.

Terry Woods said:
...but I am not pleased, not pleased at all, with the signal names (especially the signal names), nor the comments.

You then take the example and savagely pull it to pieces.

Terry Woods said:
A -motorA // If the overload is OK when required to Run
AN -motorA_O/L
= -Run_Motor //Then start the drive

Doesn't the above code (and comment) look like this in Ladder...


// If the overload is OK when required to Run then start the drive //


-motorA

-motorA O/L

---| |-------|/|-------( ) -Run_Motor



A bit unfair I thought as this was not a piece of functioning code, the signals don't mean anything, they were after all set up as an example of the mix if symbols and comments to assist in documenting code.

Lets look a a real working piece of code.

Code:
If there is data present on the end position the type of data is determined:
- Reservation/empty window code or (UFO)PIC
- In case of (UFO)PIC: Induct bit or not
If the data is a reservation/empty window code or a (UFO)PIC with induct bit 
(NO physical product expected), the one-shot data_sync is directly SET, the 
data is copied to the FIF downstream and the entry is deleted from tracking. 
If the data is a (UFO)PIC without induct bit (physical product expected) the 
following handling is executed:
- If the product is at the handover position and being handed over 
  (M_SI_Hand_Over), the one-shot data_sync is SET, the data is copied to the 
  FIF downstream and the entry is deleted from tracking. 
- If the product is at the handover position (product offset >= handover 
  offset) and NOT being handed over (eg in a die-back situation) nothing 
  happens.
- If there is NO product at the handover position (NOT M_SI_Hand_Over and 
  product offset < handover offset) the entry is deleted from tracking 
  (invalid entry).
NOTICE: The detection of data at the end of the conveyor and the detection of a 
product at the handover position comes exactly at the same moment! 
 
 
OPN   #i_DB_Track				 // Open tracking DB
	  L	 DBNO
	  T	 #t_DB_Num_Track			 // Determine tracking block DB number
	  SET							   // RESET one-shot handover data
	  R	 "M_FD_Data_Sync"
// Check if entries are used in the tracking DB
	  L	 DBW	0
	  L	 0
	  >I	
	  JCN   HA99
// Determine pointer to last used entry
	  L	 DBW	0					// Number of entries used in tracking DB
	  SLW   5						   // Shift bytes to make pointer to last entry
	  L	 P#2.0					   // 6 (Header lenght) - 4 (record lenght) = offset  
	  +D								// Add offset to jump over tracking DB header
	  LAR1  
// Detect data at end position
	  L	 DBW [AR1,P#0.0]			 // IF position of last entry >= position end
	  L	 #t_Position_End
	  >=I   
	  JCN   HA99
// Determine data type at end position: (UFO)PIC or Res/E 
// Determine if the induct bit is set in case of (UFO)PIC
	  SET							   // Reset data type bits
	  R	 #t_Data_Is_PIC
	  R	 #t_Data_Is_Induct_Bit
	  L	 DBW [AR1,P#2.0]			 // Copy data at end position to temp 
	  T	 #s_Data
	  L	 0						   // IF found data is a (UFO)PIC code
	  >I	
	  JCN   HA20
	  S	 #t_Data_Is_PIC			  // SET temp Data_Is_PIC
	  TAR1							  // Copy AR1 to temp t_Memory_AR1
	  T	 #t_Memory_AR1
	  CALL  "FC_Read_Bool_Record"	   // IF induct bit is set (no physical product expected)
	   i_Record_Number:=#s_Data
	   i_P_BOOL_Record:="DB_UDT_PIC_Record".Status.Induct_Bit
	   i_DB_Number	:="DB_PIC_List"
	   o_BOOL		 :=#t_Data_Is_Induct_Bit	// SET temp Data_Is_Induct_Bit 
	  L	 #t_Memory_AR1			   // Copy temp t_Memory_AR1 to AR1
	  LAR1  
HA20: ON	#t_Data_Is_PIC			  // IF data is Res/E 
	  O	 #t_Data_Is_Induct_Bit	   // OR data is Induct (UFO)PIC
	  O(	
	  A	 #t_Data_Is_PIC			  // OR data is (UFO)PIC
	  AN	#t_Data_Is_Induct_Bit
	  A	 "M_SI_Hand_Over"			// AND at handover position + being handed over
	  )	 
	  JC	HA50						// THEN jump to set data sync 
	  L	 "MW_SI_Product_Offset"	  // ELSE IF NO product on Handover position
	  L	 "MW_SI_Handover_Offset"	 // (Product offset < Handover offset)
	  <I	
	  JCN   HA99
	  TAR1							  // Copy AR1 to temp t_Memory_AR1
	  T	 #t_Memory_AR1
	  CALL  "FC_Log_Event_Track"		// AND Report event PIC data lost due to wrong position
	   i_Event_ID  :="DB_Event".Tracking.PIC_Lost_Wrong_Position
	   i_Event_Data:=#s_Data
	   i_AreaID	:="MW_SI_AreaID"
	   i_ZoneID	:="MW_SI_ZoneID"
	   i_SectionID :="MW_SI_SectionID"
	  L	 #t_Memory_AR1			   // Copy back temp t_Memory_AR1 to AR1
	  LAR1  
	  JU	HA51						// AND jump to remove (UFO)PIC from tracking
// Set one-shot data sync + copy data to FIF Downstream
HA50: S	 "M_FD_Data_Sync"			// SET one-shot handover data
	  L	 DBW [AR1,P#2.0]			 // AND copy data last entry to FIF Downstream
	  T	 "MW_FD_PIC"
HA51: L	 DBW [AR1,P#0.0]			 // Copy position to temp
	  T	 #t_Pos_Data_Delete
	  CALL  "FC_Write_Track_Unc"		// AND clear entry from tracking
	   i_DB_Num_Track  :=#t_DB_Num_Track
	   i_Position_Write:=#t_Pos_Data_Delete
	   i_Data		  :=0
HA99: NOP   0

The sample you disected was a very simplified example, it is normal in STL to code as much code in a single network that ladder code take 10, 20 or more networks to achieve.

With S7 you can extend the symbol length, most people keep it as default. From my experience the symbol for I/O is usually a plant code, for example the motor output on conveyor 32 could have the symbol -C032M001, this is what you see and when you put the mouse over you see the object comment, could be 'Contactor Output'. The two pieces together convey the information.

BUT, you don't normally see this inside the FB, as it is a sub-routine used once for each motor. Therefore you only see the symbol at the block call. Inside the block you see the blocks declaration names. Motor Output, could be just that -Motor_Output!

I know AB gives a better symbol ability and AB does not lend itself easily to sub-routines, so your more likely to see cut and pasted code where the actual I/O is used and your arguements hold water in such cases, especially in ladder where each network is doing a single small function, then the network comment can be specific to that small function.

In STL the network maybe doing a complete function with a number of the above small functions. Therefore the network comment will be of little help to the individual sections within the network.
 
The sample you disected was a very simplified example, it is normal in STL to code as much code in a single network that ladder code take 10, 20 or more networks to achieve.

This part has me confused, I have not heard of this, got an example of STL in one "network" that would translate to 20 rungs of ladder?
 
RS, that's how most STL programmers do it. I would say that 90% of my projects contain functions of one network because it makes it so simple to scroll down through the code both when programming and troubleshooting. I set up individual logic components within the network with "//", so funtionally it can contain many "rungs".

To see this, create a dozen rungs in Ladder, switch to STL, and then cut and paste all of that logic into one network.
 
rsdoran said:
This part has me confused, I have not heard of this, got an example of STL in one "network" that would translate to 20 rungs of ladder?

You can see it in that example of working code.

The way Siemens works, when solving logic, the result is held in a status bit, the RLO.

When you set/reset a coil, for example with instruction '= m 4.1' (equivalent to -( )-), the flag will become the same status of the RLO. A S (set) or R (reset) instruction will only actuate if the RLO = 1, once that logic is complete the RLO resets to zero, thus enabling another piece of logic to follow on from the first.

So in STL, you tend to do a complete section of logic on one network. But STL can be confusing if your not used to it and the more complex parallel logic is not as easy to see straight off, that is why comments are important as a guide to whoever's problem solving.
 
My feeling is you should only need to look at the code to see why something isn't working as an absolute last resort - the HMI should tell the user what is wrong. To this end I generally don't use rungs of ladder logic, instead I use a block that has a request input, 8 condition inputs which must be true for the request to enable the action , 8 help in_outs to signal via the HMI why the request is not actioned, and a timer to remove the help reasons 10 seconds after the request is removed. See an example below. If there are more than 8 conditions required, just call the block several times and parallel up the action outputs to finally drive the real output.

fchelp.JPG
 
ooops no-one picked up my little error, the '=' instruction does not reset the RLO after executed. What you do is start the next logic with 'A' AND, to initialise the RLO.

Not sure what your block's about Simon, but I agree the HMI should give the information required to fault find without looking at the code.

In my experience though, the real world is not always so helpful, depends on the complexity of the machine functions and logic to solve that.

When a problem raises its ugly head and the HMI does not help, then the tech will revert to the code for help and assistance.

In the perfect world the code will handle everything, in the real world a hardware failure may cause signals to be out of sync and if the code is not robust enough locks up.

I'm sure some people will say it should never lock up, I've not whitnessed many examples of perfect code.
 
I think Simon brought up a more fundamental topic.

The questions I wrestle with is whether to use a FC,FB or multi instance FB. Should I pass the parameters one by one or should I pass a pointer to the parameters. If I decided to use a FC where a FB would do, how should I maintain state. Should I have one FC or FB that does everything or should there be many specific FCs or FB.

Ideally FCs and FBs should be building blocks ( baustein ) which the rest of the program is built. At least this was the intention of how the German engineers hoped the the FCs and FBs would be used. I would think that an experienced programmer would have written many of these building blocks over the years. I would also think that these building blocks would be shared between programmers. Hopefully the maintenance guys should not have to get into the building block type FBs and FCs, just the application specific ones.

I wouldn't use a block like Simon's myself but at least he has a consistent way of writing code and using the same hammer over and over. Once one figures out Simon's building blocks then it should be easy to figure out what the rest of his program does. This should avoid the HUGE FBs or FCs that I have seen in the past where the code looks like endless STL.

So there are FBs and FCs that are used at a higher level to control program execution or organization. These FCs and FBs are very application specific. There is another level of FBs and FCs that are more like tools or building blocks. These should be re-usuable between different applications.

What has bothered me is that there doesn't seem to be a library or user group for Step7 so the building block don't need to be re-invented.

My applications are motion related. I don't write big S7 programs, just the FC or FB interface to our motion controllers. I try to make it look simple similar to Simon's FC. The user shouldn't have to see the hand shaking that goes on over the Profibus. The user should only be concerned with the end result, not the means of achieving the end result.

I have some comments on commenting and naming. We use abbreviations all the time to keep the text from getting to long. We have agreed on these abbreviation so everyone knows what they are. There must be conventions when working with other programmers. If everyone does their own thing then there are serious problems. This is why I think using standard building blocks is good.

You can't comment too much. I tend to write code twice. I prototype the code using Mathcad or Scilab where I prove it works and then translate the algorithm into real time C. Often times I refer to the prototyping document as part of the comments.

Likewise, I tend to write STL code many times. I write little test programs that test concepts. The point is to not invest much time to learn a technique and avoid going down dead ends. Once I find a technique that works then I apply it to a bigger program. I find that in the end I write less code and I have the test program as an example of the technique. The downside is that my project directory has a lot of 'test' projects. When writing STL, I am always thinking that I would do it this way in C, what is the equivalent way in STL?

I know I haven't provided any answers and have asked a few questions just to keep things interesting.
 
PeterW, take the following simple example. There would be no point in monitoring the ladder if the HMI gave the help reasons why the output would not turn on. I have just generalised it using 8 interlocks in my block (the reason why the output would not action is held on for a time to allow the user to get to the HMI).


Cause Interlock1 Interlock2 Output
---| |----| |------------| |---------( )


Cause Interlock1 HelpReason1
---| |----|\|------------------------( )

Cause Interlock2 HelpReason2
---| |----|\|------------------------( )

 
Last edited:
You are, or the Process is, trying to do something... you press a button to do something, or the Automatic Process tries to activate something...

Whatever the something is... it doesn't happen.

The Processor should be be able to detect your intent, or the Process intent, and then if it can't occur, or doesn't occur, the processor should indicate why that particular intent can't occur.

In terms of the Operator activity...

The HMI says "I can see that you are trying to do such-n-such...

Here is why you can not do so..."

In terms of the Process activity...

The HMI says "The Process is trying to do such-n-such...

However, here is why it can not do so..."
 

Similar Topics

Hello all, Just to give you an idea of my background, I'm new to the PLC world with a background in IT and currently pursuing my MSEE. I have...
Replies
3
Views
743
OK, (some of) you guys know by now that I'm not a PLC programmer, so I'm not really familiar with how a well-structured PLC program is typically...
Replies
2
Views
1,474
Program structure - s7-1200 MODBUS RTU Master with multiple slaves & multiple registe I'm having problem to make a appropriate structure of my...
Replies
7
Views
11,251
Hello, I am creating a PLC program for a fresh water pump station which will be based on downstream and upstream pressures. There will be several...
Replies
5
Views
2,105
hi guys I have recently completed a basic S7 course and have started creating my own little programs/solutions to small problems using stl. So...
Replies
1
Views
1,219
Back
Top Bottom