Understanding IF statements

Hi,
I know my questions are relatively elementary and have been partly covered in old topics, but I am having trouble making progress. I need multiple input conditions and multiple output actions

Re compound IF/THEN. I take it that the BLOCK IF / ENDIF function is not available? (used by Johnson Control Basic). I am doing som basic tests using several toggle switches for inputs and output monitor blue LEDs.

The poorly formatted example in the T3000 manual (p176) shows conditional branching to different line numbers, with each branch having an END statement. This allows only one scan through the code. (END statements are not recommended so why are they included in an example?).
How would this example look if END was replaced by ???
My main question is how to get the THEN branch to skip over the following ELSE branch. Unless it skips, then both THEN and ELSE branches execute.

I have tried the following:(using local variable A per previous topic). This is a very simple example for test purposes. The desired result is if both inouts are true outputs 1 and 2 both turn on, otherwise outputs 1 & 2 are off and Output 5 is on.

10 IF IN1 AND IN2 THEN A = 1 ELSE 40
20 IF A = 1 THEN OUT1 = 1
30 IF A = 1 THEN OUT2 = 1
40 OUT5 = 1

If both input conditions are true, both outputs 1 & 2 turn on.- OK
If I then turn off either input, line40 executes (OUT5 comes on) but line30 does not execute (OUT2 also stays on)
If I then make both input conditions true again, line 40 still executes and OUT5 remains on

I can get the correct operation using the (inefficient) code:

10 IF IN1 = 1 AND IN2 = 1 THEN A = 1 ELSE A = 0
20 IF A = 1 THEN OUT1 = 1 , OUT2 = 1 ELSE OUT1 = 0 , OUT2 = 0
30 IF A = 0 THEN OUT5 = 1 ELSE OUT5 =0

I seem to have to explicitly reset Outputs if the turn-on logic is not true.

What am I doing wrong here?

IF IN1 AND IN2 THEN START OUT1 , START OUT2
IF NOT IN1 OR NOT IN2 THEN STOP OUT1 , STOP OUT2
IF NOT IN1 OR NOT IN2 THEN START OUT5 ELSE STOP OUT5

Another way would be to create a global VAR which the logic acts upon, then use that VAR to operate on the outputs. I prefer this way since you can place the global var on the screens and trened logs for debugging. Also it keeps things clear having the ‘mode’ logic separate from the ‘output’ logic.

*** Code for the Mode, stored in the global LEDMODE variable ****
IF IN1 AND IN2 THEN LEDMODE = TRUE
IF NOT IN1 OR NOT IN2 THEN LEDMODE = FALSE
*** Code for the outputs ***
IF LEDMODE THE START LED1 AND START LED2
IF NOT LEDMODE THEN STOP LED1 AND STOP LED2
IF NOT LEDMODE THEN START LED5 ELSE STOP LED5

1 Like

More queries about IF statements…

I am using a cascade of IF statements to check for exceptions, and if the exceptions are true I want to skip to a specific line number - or in some cases to the END of program.

I note that inserting a line number after THEN, is not an “absolute reference” - ie if I later edit the program and line numbers change, there is no automatic update of the line number called by THEN. Is there some trick to establish absolute referencing or must I update the references manually? (Just good to know)

Similarly, is it allowed to have THEN call END (of program)?
Often could be a useful shortcut when inputting a new, long program and the last line number is still unknown. Note: in this case I cannot skip to last line of functional code which does not apply - I need to skip to either END or a “no-operation”

Eg
10 IF Exception A = true THEN END
20 IF Exception B = true THEN END
30 actions to take if Exceptions A & B do not apply
40 more actions if Exceptions A & B do not apply
..

This seems to work sometimes when I test, but sometimes when compiling, extra characters (spaces, comma) are added at the end of the line…THEN END so it does not compile. Eg 10 IF … THEN END ,

Again, is there a trick I need to learn?

In case its useful to others, I have verified that an IF..THEN cannot call a REM statement, eg
10 IF… THEN 100
20 etc…(intervening code) …
100 REM
110 etc… more code…
does not work. Program does not execute the call to line 100, so executes both “intervening code” and “more code”. The THEN must call line 110 of “more code”.

Rather than jumping around with the program I like to put the least important lines up top and the overrides further down. The later lines have precedence over the previous lines.

Another rule I like to use is to keep the program simple, one line of logic per line rather than compound statements.

10 IF SCHEUDLE START FAN ELSE STOP FAN
20 IF OVERRIDE THEN START FAN
30 IF SMOKE THEN STOP FAN

Line 10 is the normal schedule logic.
Line 20 is an exception to the normal schedule logic
Line 30 is the smoke interlock, if there’s a fire we absolutely need to turn the fan off.

Its easy to debug with only one concept per line. Lines further down will override the lines above. There’s no need for any gotos or compound statements.

Fandu will work on the line renumbering, it was supposed to be fixed some time ago.

When you click on the “Send” menu, the program will automatically renumber the line numbers. If you want to redefine the line numbers while writing the program, clicking “Refresh” will execute the line number redefinition.

The above functions were released in a previous version. Thank you.

I certainly understand the merits of simple code, however…
in part of my project I need to make a 3-way branch. This seems to make it necessary to “jump around”.

  • if one set of conditions A are true then skip to the END, else continue
  • if a different set of conditions B are true then execute code Block B, else continue
  • if neither A nor B conditions are true then execute code block C
  • after Either block B OR block C execute, proceed to code block D

If I dont use IF/THENs to “jump” to the right place then code blocks B, C & D will all execute - which wont deliver the required result.

Your example has only 1 condition each for normal, exception and smoke and only 1 output (fan). I often have 2,3,4 input conditions as well as 3,4,5 result actions.

I cant see how to avoid compound statements or code-blocks that I need to skip-over/to. Happy to learn!

Yes I have been renumbering using SEND and REFRESH - although these do not work quickly. It often takes several send, refresh, close, reopen cycles to get line numbers updated and all labels discovered.

The problem I tried to describe is that I have IF…THEN [line number] branching, but the [line number] is not anchored to the same line as the original (pre-renumber) line.

Eg I might have say IF … THEN 120, but when program renumbers old line 120 becomes new line 140 - and I have to re-edit the code to the new number.

Its OK if that is just how it is - I only wondered if I have missed something

(EG in Excel when you add a new row or column, all the cell references adjust to suit - but it was not always this way!)

Any complex else if logic can be simplified into the most basic if then logic. Here’s my example: when VAR15 has multiple possible states, I set VAR15 to the MSV (polymorphic mode), which includes states AAA , BBB , CCC , and DDD respectively. The program judges the state of VAR15 and executes the corresponding action. When I manually change the state of VAR15 (to simulate a user operation), the value of VAR16 will change accordingly. This is a programming method for handling multiple conditions.

I am having a bit of bother with the IF TIME-ON (item) [time] THEN statement.

With every IF the THEN result is defined, but you have to consider the ELSE outcome.

As I understand it:

10 IF TIME-ON (OUT1) > 0:0:05 THEN (do something A)
20 do something B

will work as follows:

  • Until the set-time is reached something B happens (the ELSE result)
  • Once the set-time is reached (and thereafter) , something A will occur then something B
    Is this right?

One particular detail I am working on relates to measuring flow (IN6) from a pump, after waiting for say 10sec for conditions to stabilise. If I measure too quickly the measured flow may not be correct. I am testing whether the pump discharge is nearly shut - and if it is, I want to stop the pump. If the flow is sufficient, then keep pump running…

So I my first attempt is…
40 … previous code
50 START PUMP
60 IF TIME-ON (PUMP) < 0:0:10 THEN 80
70 IF IN6 < SETVAL THEN STOP PUMP
80 … remaining code

I think this will work, but maybe it could be smarter?

The program executes the judgment 10 IF TIME-ON (OUT1) > 0:0:05 THEN (perform Action A) every second to check whether OUT1 is turned on 5s. If OUT1 is on 5s, it will (perform Action A). Additionally, the program also executes 20 Perform Action B every second . If the code is written as you did, Action B will be performed every second (without exception).

I will reiterate my earlier suggestion to steer away from GOTOs.

-The program should flow from the first to the last line without jumping around.

-Lines lower down have precedence and will override lines further up.

-When the last line is executed then the program exits and starts again at the top automatically.

50 IF IN6 > SETVAL THEN START PUMP
60 IF IN6 <= SETVAL THEN STOP PUMP
70 IF+ TIME-ON( PUMP ) > 0:0:10 THEN DO SOMETHING ( once, IF+ fires only one time)
80 IF TIME-ON( PUMP ) > 0:0:10 THEN DO SOMETHING (repeatedly, the IF will trigger each pass)

I’m sorry that I am failing to grasp this…

I agree I need to use IF+ & IF- more and IF less. I dont use (explicit) GOTOs, but do use IF-THEN branching (why else have IF-THENs?)

The approach you have outlined basically uses the IF-THEN as a go/no-go condition with a simple output - IF this THEN that (ELSE continue).

I often have situations where I need several things to happen as a result of an IF-THEN, and sometimes different actions after THEN from after ELSE. It seems to me I either have to use a complex-compound THEN/ELSE or set up a section of code that only applies in particular cases - and jump to it or around it as necessary.

Thanks for your example, but I dont understand how it achieves the functionality I described - ie turn the pump on, allow it to run for 10sec, (after this time) compare measured flow to a setvalue, and then decide whether to keep pump running or stop it before moving on to execute other code. Note the flow measured at IN6 is generated by the Pump, so until PUMP is running the flow will be below SETVAL (ie zero).

In your example Pump will never turn on - Line 50 cannot start pump because there will not be any flow until after pump starts. Similarly, line 60 will always keep pump off.

A really simple version of this routine that captures the intention and achieves top to bottom flow (but uses a WAIT which is bad) is:

50 IF+ various preconditions satisfied START PUMP
60 WAIT 0:0:10
70 IF+ IN6 < SETVAL THEN STOP PUMP
80 Unless stopped at 70, PUMP continues to run, carry on …

The only way I can see to replace the WAIT is by an IF+ TIME-ON …THEN function to “jump” past 70 while the timer is running, ie

50 IF+ various preconditions satisfied, START PUMP
60 IF TIME-ON (PUMP) < 0:0:10 THEN 80 (executes every scan until time expires)
70 IF+ IN6 < SETVAL THEN STOP PUMP (only executes after time expires)
80 remaining code …

Can you suggest how to avoid jumps and waits while achieving the required function?

My program is just showing the technique of not using gotos. Instead I use the order of the lines to override earlier statements. There’s only one rule per line which makes the program easy to follow.

One other idea is to use flags, you can encapsulate a lot of logic into the flag variable. Then elsewhere in the program you can act on the flag. This keeps things organized and simple to follow later as well.

10 PUMPTIMER = TIME-ON( PUMP1 )
11 IF PUMPTIMER > 0:00:00 AND PUMPTIMER < 0:00:10 THEN START PUMPFLAG
12 IF PUMPTIMER > 0:0:11 THEN STOP PUMPFLAG
13 IF NOT PUMP1 THEN STOP PUMPFLAG
20 IF PUMPFLAG THEN DO SOME THINGS
30 IF NOT PUMPFLAG THEN DO OTHER THINGS

Thanks again. I am using FLAG variables to some extent. I will study your latest first thing tomorrow.

I have belatedly realised that your coding principles (one action per line, flow in sequence etc) are very similar to ladder-logic.

A noteworthy difference between Control Basic and Ladder is that Ladder can include more contacts per rung than inputs will fit in an IF statement.

Sounds like you need something like a case statement, we can add it to the todo list:

CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
WHEN conditionN THEN resultN
ELSE result
END;