Author Topic: TBASIC Input On/Off Question  (Read 293 times)

MatrixMan

  • Newbie
  • *
  • Posts: 7
    • View Profile
TBASIC Input On/Off Question
« on: December 07, 2019, 08:19:19 PM »
I am new to TBASIC.  I want to write a simple program that looks to see if a switch is on or off, but when I wrote it in i-TriLOGI 6.x for my FMD88 I found that the Input
  • =0 treats this as an integer instead of a boolean 0 or 1.  I guess I don't understand how the system generates the integer to know what bit to read to see when it is on or off.  Here is the code I used:


IF Input[10]=0 Then SetTimerSV 9, GetTimerSV(16)
Else SetTimerSV 9, GetTimerSV(15)
ENDIF
RETURN

The simulator seems to always return 0 whether the switch is on or off so the code doesn't work.  Also, if it is the first time I run it then it might have a 1 until I run it again and then it is back to 0 even though the switch position didn't change.  I think it has something to do with refreshing, but I am not sure.  I appreciate any help.  Thanks.

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: TBASIC Input On/Off Question
« Reply #1 on: December 08, 2019, 03:18:50 AM »
 Input[10]. Allows read/write access to  groups of 16 input bits.

Boolean: TBASIC does not have a Boolean numeric type.  All arithmetic work is done with 32-bit sighed values. PLC data can be stored as 32-bit signed, 16-bit signed or 8-bit sign values.  The Fx / Smart Tile adds 32-bit floating values.  No Boolean.

The INPUTs can be accessed by TBASIC as a group of 16 INPUTs using the INPUT[n]. You are accessing an array of inputs in groups of 16.  The same access is available for RELAYS[] and many other PLC internals.

Accessing groups of INPUTs as an integer:

A = Input[1].     ' copy the state of Inputs 1..16 to the variable a.

The argument in the square brackets determines which group of inputs that you are accessing:
Input[1] accesses physical INPUTS 1..16 as an integer.
Input[2] accessed physical INPUTS 17..32 as an integer
   .
   .  There is a pattern to this
   .
Input[10] accesses physical INPUTS 145...160 as an integer.  I BET YOU DON'T CARE ABOUT THESE INPUTs!

So if INPUTS 145..160:
    a = Input[10]    ' a will have the value of &h00000000
If INPUT #145 was ON, only:
    a = Input[10]    ' a will have the value of  &h00000001
If INPUT #146 was ON, only: 
    a = Input[10]    ' a will have the value of  &h00000002
If INPUT #160 was ON, only:
    a = Input[10]    ' a may have the value of  &h00008000 or &hffff8000
                            '    Complicated answer follows

TBASIC does all arithmetic as 32-bit signed numbers.  Input[10] only represents 16 bits, but TBASIC promotes 16 bit things to 32 bit values.  The integer variables a..z are 32 bit signed variables so  the assignment, a = Input[10], will result in a 16 bit signed value being promoted to a 32-bit signed value that is assigned to the variable a.

The rules of signed integer arithmetic says that when going from 16 to 32 bits, the most significant bit in the 16 bit value will be propagated in to the most significant 16 bits of the 32-bit value.  This how &h8000 can end up as &hffff8000.  The most significant bit determines if the number is negative.

The reason that I worry you, is that TRI does not consistently document the behavior of how it deals with 8 and 16 bit stuff.  They have Improved their documentation a lot.  When in doubt write test code and run it in both simulation and on real hardware to be sure.

Accessing INPUTs as a single bit:

If you want to "see" if a single INPUT is ON, I would suggest using the "TestIO(n)" function where "n" is the name you assigned to the INPUT.  Testio() returns a 0 if the bit is off.  TestIO() returns a non-zero value if the bit is ON. Let's save that you named physical INPUT #10 "Stop",  the you can write TBASIC code that looks like this:

if TestIO(Stop)
    ' Stop is ON
    '
else
    ' Stop is Off
    '
endif

There are statements to set and clear 1 bit things.  SetI0 and ClrIO.  Look them up.

I have no idea what you are attempting to do with the SetTimerSV and GetTimerSV stuff.  Try something simpler.  Connect a relay to a timer in ladder logic then set the relay in your CF and then when the CF terminate you can watch the Timer count down.


Gary Dickinson
« Last Edit: December 08, 2019, 04:11:25 PM by garysdickinson »

support

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3102
    • View Profile
    • Internet Programmable PLCs
Re: TBASIC Input On/Off Question
« Reply #2 on: December 10, 2019, 04:58:31 AM »
Hi Gary,

Thanks for the excellent explanation. We couldn't have done it any better than what you did.

Just add a note to someone new to TBASIC - the variables represented by INPUT[] and OUTPUT[] are stored in internal memory and they are normally only synchronized to the physical I/Os at the end of the ladder logic scan. So it will be a mistake to monitor an input inside a TBASIC loop because these internal memory do not change state:

E.g.
WHILE 1
   IF TESTIO(IN5) EXIT: ENDIF
ENDWHILE

The PLC program will be stuck in the WHILE loop because IN5 will never be turned ON.  You can force the internal I/O to be updated using the REFRESH statement:

WHILE 1
   IF TESTIO(IN5) EXIT: ENDIF
   REFRESH
ENDWHILE

REFRESH statement will update the memory INPUT[] to the states of the associated 16 physical inputs. There is a penalty of I/O scan time being used each time you run the REFRESH statement (about 2ms for a FMD or Fx PLC, shorter for Nano-10) so you want to use it only when necessary.  Letting the ladder logic monitor changes in input and use it to trigger custom functions for TBASIC processing will normally be a lot more efficient than monitoring it inside a WHILE loop.

« Last Edit: December 10, 2019, 05:36:49 AM by support »
Email: support@triplc.com
Tel: 1-877-TRI-PLCS

MatrixMan

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: TBASIC Input On/Off Question
« Reply #3 on: December 10, 2019, 08:14:19 AM »
Hi Gary,

Thanks again for your input.  It was very helpful.  I am still trying to get my densifier to change the grinder time depending on the position of the high/low switch.  The ladder code you gave me on the other posting didn't work.  There is just too much stuff going on at the same time and it caused other problems.  I got the TBASIC code to work.  Well, mostly.  I used the existing ladder code, but added some custom TBASIC to it.  See the attached ladder code.  The problem is that no matter what I type in TBASIC, it still saves that last value when you turn the switch on.  In other words, when you go from Low to High it runs the Low timer one more cycle and then runs the High timer from then on.  I tried changing the timer to 0.  Clearing the IO for that timer and refreshing.  It still does it.  What is weird is that the I/O table shows the correct values (I added pauses in for each step), but the simulator still holds that timer value one last time.  Here is what I wrote:

SetTimerSV 9,0
CLRIO GrndrTmr
Refresh
IF TestIO(SWHigh)
    Then SetTimerSV 9,0
          CLRIO GrndrTmr
Refresh
Else SetTimerSV 9,0
CLRIO GrndrTmr
Refresh
ENDIF
IF TestIO(SWHigh)
   Then CLRIO GrndrTmr
      Refresh
        SetTimerSV 9, GetTimerSV(15)
Refresh
Else CLRIO GrndrTmr
Refresh
     SetTimerSV 9, GetTimerSV(16)
Refresh
ENDIF
RETURN

I know it has a lot of overkill in it, but it still didn't work.  I am new to this so I am probably doing something wrong.  9 is GrndrTmr.  15 and 16 are the Low and High timers.  Thanks again for your help.  Take care.

Jeff

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: TBASIC Input On/Off Question
« Reply #4 on: December 10, 2019, 04:28:06 PM »
Jeff,

I don't think that I can help you out of the hole you are digging. 

This is what I understand
  • Your original code was written in 100% ladder logic and apparently worked on a T28.
  • You swapped out the T28 for a newer, more capable PLC. 
  • The old code was ported to your newer PLC.  And operated correctly???
  • You tried to make a "small" change using ladder logic but you were not successful.
  • You then attempted to make the change using a custom function. And this didn't work.

Nothing in your custom function makes any sense.

My best advice at this point:
  • Delete your custom function.
  • Document exactly what the original PLC program does.  It is based on 2 "drum sequencers" using Seq1 and Seq2.  Figure out exactly what is controlled at each state.  Figure out exactly why and when the sequencers change state. Document all of the time delays.  Document all inputs/outputs.
  • Go back to 100% ladder logic and add the new feature.
          OR
    Now that you have fully documented the program and understand how it works, it should be easy to rewrite it.

Gary Dickinson
« Last Edit: December 10, 2019, 05:08:46 PM by garysdickinson »

support

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3102
    • View Profile
    • Internet Programmable PLCs
Re: TBASIC Input On/Off Question
« Reply #5 on: December 10, 2019, 06:28:10 PM »
Without fully understand your program, we would like to jump in with some comments about using SETTIMERSV - this command changes the Set Value of the timer when it is activated, but does not activate the timer when it is executed.

On Nano-10 and FMD PLC we don't recommend sprinkling this function all over your TBASIC program as the set value change are not backed up in flash memory unless specifically forced to do so by the program. Timers' and counters' are normally preset during program transfer but TBASIC allows you to perhaps use a HMI to make changes when needed, but it is not meant to be changed all the time by a program.

If you want to two different timer values for an action you could use two separate timers. Alternatively, you can start a timer with a desired count down value anytime by assigning the time-out value to the TIMER[n] variable and clearing the timer contact. You do not need to change its Set Value using the the SETTIMERSV command.  Please check the following FAQ thread for explanation:

https://triplc.com/smf/index.php?topic=1046.0
Email: support@triplc.com
Tel: 1-877-TRI-PLCS

MatrixMan

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: TBASIC Input On/Off Question
« Reply #6 on: December 10, 2019, 10:46:24 PM »
Thank you all for your help.  I am posting this in case someone needs help in the future with this.  Here is the final code I wrote that works exactly like I wanted:

rem 'First clear the value for GrndrTmr
TIMERPV[9] = -1
CLRIO GrndrTmr
Refresh
rem 'Determine if the switch is on (High) or off (Low) and set the timer value
IF TestIO(SWHigh)
    Then SetTimerSV 9, GetTimerSV(15)
Else
     SetTimerSV 9, GetTimerSV(16)
ENDIF
RETURN

This code, along with the ladder I attached, allows you to have a timer that you can change based on if a switch is on or off.   

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: TBASIC Input On/Off Question
« Reply #7 on: December 11, 2019, 11:19:34 PM »
Jeff,

Good to see that you got something that works for you.

If this code is something that has to be maintained, I’d suggest using the "names" of things rather than the numbers.  As an example TIMER #9 was assigned the name "GndrTmr" in the "I/O Table tab in the i-TRiLOGI app.

So TimerPV[9] and TimerPV[GndrTmr] are equivalent.  The second version makes more sense.  The other reason for using the Itepms name rather than the number is that it is possible to re-arrange the Timers in the I/O and then TimerPV[9] may no longer refer to the GndrTmr.

The same goes for GetTimerSV(15).  Which timer is #15?  Use the name and not the number.

You will find that this convention of numbers and names for references includes things like custom functions, COUNTERS, TIMERs and several other things.

The use of “then" is optional.  It was probably put into TBASIC for the same reason as was the optional "let" keyword.  I suspect that this made TBASIC look more like Dartmouth BASIC from 1964 or Apples integer BASIC from the 1970s...  There is no reason to include this useless keyword.

The use of the "refresh" statement is interesting.  TRI has only documented the refresh statement in terms of updating both the internal copy of the physical INPUTs and making the internal copy of the OUTPUTs become the physical OUTPUTS.  This is normally handled by the before the first line of ladder logic is executed (INPUTSs) and after the last line of ladder logic is executed for the OUTPUTs. 

There is no mention  in TRIs documentation about refresh affecting the State of RELAYs.  You may be on to something!

Gary D