Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - garysdickinson

Pages: 1 2 [3] 4 5 ... 33
Documentation for Stack.PC6

Technical support / Implementation of a Stack or LIFO in TBASIC
« on: January 06, 2020, 03:31:35 PM »
This post shows how to implement a stack or Last In First Out data structure in TBASIC.

This example builds the stack in DM32[]. 
The size and location of the stack is controlled by entries in the #Define table.
Separate custom functions to initialize, push data and pop data are written to be as small and fast as possible.

The Stack.PC6 file is attached to this post. This is test bed code that will run in the i-TRiLOGI  simulator. This code should be easily adaptable for many uses.

The next post will have post a bit of documentation on how the stack operates.

Best regards,

Gary Dickinson

Technical support / Re: TBASIC Input On/Off Question
« on: December 11, 2019, 03:19:34 PM »

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

Technical support / Re: TBASIC Input On/Off Question
« on: December 10, 2019, 08:28:06 AM »

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.
    Now that you have fully documented the program and understand how it works, it should be easy to rewrite it.

Gary Dickinson

Technical support / Re: TBASIC Input On/Off Question
« on: December 07, 2019, 07:18:50 PM »
 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
    ' Stop is Off

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

Technical support / Re: PLC Ignoring Timer
« on: December 05, 2019, 10:48:58 PM »
I can't stop thinking about this. I know that you can't rewrite this thing and just need to get something working.

I suggest that you get rid of both rungs that control the grinder TIMERs. The original and the new one that you added for the longer duration TIMER.

Create a new RELAY with a name that makes sense (i picked GrinderDone) to replace the use of the Grndr_Tmr contact earlier in the program.

Create two new replacement rungs as shown in the attachment.

Maybe this will get things working without a total rewrite.

Gary Dickinson

Technical support / Re: PLC Ignoring Timer
« on: December 05, 2019, 05:16:37 PM »
I took a look at line 44.  It looks a lot like 43.  But it uses a different timer, Grindr_Hi.  However, Grindr_Hi is not used any where else in the program.  So it has no possible affect on the program.

I think I figured out the usage of many of the timers and why the complicated logic around them.

The explanation: 

1.  the program is using the sequencer mechanism as a drum sequencer using the [AVseq] terminal on line 32.

2. The complicated logic  with the time is to use the TIMER going active to create a pulse for the [AVseq]. It does this by advancing the sequencer when the TIMER goes active. This changes the state of Seq1 and this disables the input to the timer.  The end result is a 1 scan time wide pulse when the TIMER runs out. This pulse somehow is used to advance the sequencer to the next state.

I use another approach for sequential logic that simply assigns the next state to the sequencer.  Oddly enough this direct approach is used on line 3 of the program.

The logic in the overall program is exceedingly convoluted.  The Seq:1 states are used to control other RELAYs C2 ... C7 and C14 for no apparent reason.  Perhaps this was done to ensure that no one could ever understand the program.

I assume you have been tasked with maintaining the program. I feel so sad for you.

Gary d


Technical support / Re: PLC Ignoring Timer
« on: December 05, 2019, 08:50:12 AM »
OK I can see sort of what you are trying to do.

I have a question and a suggestion.

Question. Line #43 that controls the TIMER, Gndr_Tmr, uses the contact associated with the TIMER as part of the logic. It looks like you are trying to create some sort of Seal-in circuit. The issue is that the TIMER contact only does not go active until it times out. This would then keep Gndr_Tmr active until either the contact with Seq1:1 goes active of SW_High goes inactive.  Is this what you want?

Can you simplify your program down to 2 or 3 lines and the problem still exists?  This would be a lot easier for me to figure out.

Suggestion:  The use of "_" in the names of the ladder logic elements used to work quite fine. Somewhere in the history of TRI they decided to allow attaching a comment to variable names in the TBASIC programming language that was added to PLCs after the T28.  This idea was stupid and it breaks all sorts of things.  Now in TBASIC the following are all references to the same thing, "A" "A_InputState", "A_A".  Essentially anything including the "_" is ignored.  If you use TBASIC and try to access INPUTs, OUTPUTs, RELAYs, TIMERs and such in TBASIC the "_????" will be ignored.

If you never use TBASIC you can keep the "_" names. If you use TBASIC, then DO not use "_" in any name anywhere. The "_" breaks the parts of the i-TRiLOGI syntax highlighter, also. 

TRI did come up with something that was a lot more powerful and I like a lot, the #define mechanism.  This mechanism does give you useful names for things. However, they didn't get rid of the stupid "_" idea.

Gary Dickinson

Technical support / Re: PLC Ignoring Timer
« on: December 04, 2019, 03:33:15 PM »
There is something wrong with the PC6 file that you attached to the post.  When I download and try to open your file with
i-TRiLOGi 6.52 I get the following error message:
"Open File Error
Error Opening FIle C:\Users\ ...\1500.1.3.5-1.pc6
File Not Found or is is not valid TRiLOBI file"

I opened your file and the first line of the file is as follows:
TRiLOGI Ver 3.0<SUB><LF>

<SUB> has a value of 0x1a  and is named a substitute character<-- I don't know why this character is present
<LF> is an ASCII line feed character this makes sense

The first line of .PC6 files produced by the current version of i-TRiLOGI looks like this

øõTRiLOGI Ver 5.0<LF>

The first two characters are Unicode. I am a 7-bit ASCII guy..

Perhaps your version of i-TRiLOGI has some limitations on what sort of files it can produce.  Tech support at TRI will recognize the problem, easily.

If you can print out your ladder logic to a PDF and either post a link or send it to the email address in my profile, I'd be happy to figure out why stuff is not happening for you.

Best regard,

Gary Dickinson

Technical support / Re: Changing STEPSPEED
« on: October 14, 2019, 12:45:10 PM »
Hello Thierry,

In regards to issuing a StepSpeed command during an active step move command, what I have observed is:
  • The step rate jumps to the PPS specified by the new StepSpeed command
  • The "acc" argument is ignored. There is no ramp. The step output jumps to the PPS value in the new StepSpeed command.

My testing of the StepMove statement is that it is ignored while the stepper is executing a StepMove command.  This approach will not get the behavior that you want.

The PLC stepper motor control hardware/firmware is very simplistic.  It assumes that you just need to move a stepper from one position to another.  The acceleration/de-acceleration and maximum step rate is specified before the StepMove statement executes.

The only thing that you can do while a StepMove is executing is to abort it with a StepStop statement.  This command just shuts down the stepper control system and the steps are abruptly stopped.

I do use the StepStop statement in production PLC code. I use this to stop the stepper system when a switch is closed indicating that the system is in the "home" position. However, the move statement that I use to find the "home" position has the PPS set to a very low rate and no acceleration/de-acceleration is used.

If you are really in need of a variable speed stepper based system you have only a few choices:
  • Stick with the PLC. If you speed changes are great enough for your system to lose steps then you will need to issue several intermediate StepSpeed statements before you get to your next target speed.
  • Look into some sort of motion control system that is external to the PLC. For some motor control needs I use 3 phase motors and VFDs.  The PLC communicates to the VFD via RS-485 (Modbus RTU).  VFDs manage the acceleration profiles to smooth out abrupt speed change requests that the PLC may make.

Best regards,

Gary Dickinson

Technical support / Re: Changing STEPSPEED
« on: October 13, 2019, 04:23:30 PM »

You will have to test this.  I have tested most of the stepper motor hardware and firmware, but have not attempted to change the PPS (step rate) of a running stepper. 

I do use the PWM outputs to generate variable frequency pulses.  The PWM outputs will change frequency while running. I have verified this with a digital oscilloscope and see that the output goes to the new frequency very "cleanly".  You could use a PWM OUPTUT to control a stepper motor and change the frequency, periodically.

The following code has been extracted from one of my products that is in production.  The code is called every 0.1 second (10 Hz rate) and changes the PWM frequency.  The code is used to simulate the output of a flow meter. The physical flow meter outputs a variable frequency signal that is proportional to the flow of fluid through the flow meter.

if (VFDCurrentHz < 5.00)
   ' Main Pump speed is too low to generate meaningful flow values
   SimProductGPM = 0.0
   SetPWM 1, 0, 1         ' 0% duty cycle so output is "OFF"
   ' The main pump is running so we will calculate flows based on VFD frequency
   SimProductGPM    = 0.0007 * VFDCurrentHz * VFDCurrentHz + 0.0194 * VFDCurrentHz + 0.7229

   ' Generate pulse output for flow.
   SetPWM 1, 5000, SimProductGPM / 60.0 * ProductPPG

Best regards,

Gary Dickinson

Technical support / Re:User written Modbus RTU example code
« on: June 19, 2019, 10:45:06 AM »

I try to periodically post PLC software that illustrates an approach to PLC programming that solves a complicated problem without a lot of programming.

As always, I invite people to use this or any other examples that I have posted.

Best regards,

Gary D*ckinson

Technical support / Documentation
« on: June 11, 2019, 05:32:47 PM »
This is the PDF version of the documentation.

Technical support / Slave PLC code for test
« on: June 11, 2019, 05:28:35 PM »
Variations of this Modbus RTU code is currently running 24/7 on over 40 PLCs.  Some of these installations date back 5 years.  This is why I am convinced that the code is reliable.

I extracted the Modbus RTU code out of running production code. I simplified this code for use as a demo.

I needed to test the demo code against a real Modbus RTU slave device. I decided to use a spare TRI PLC as the slave.  This choice solved my my need to test the code and provided an opportunity to explain how the low-level TRI handles Modbus RTU requests.

This posting is the PLC program that I am running on the slave PLC.  This code initializes the serial port on the slave and writes data patterns into DM[] and some of the PLC RELAYS.

The data patterns are used to help me verify that my code running on the master PLC is reading/writing the correct registers in the slave.

The slave PLC responds to the Modbus RTU requests using the TRI written firmware. My software on the slave PLC is NOT handling the Modbus requests.

Have fun,

Gary D*ckinson

Technical support / User written Modbus RTU example code
« on: June 11, 2019, 05:22:29 PM »
I am presenting the code that I have been using for the last 5 years as an alternative to the TBASIC ReadModbus, ReadMB2, WriteModbus and WriteMB2.

This code is supports all possible Modbus function codes.

This code is non-blocking. The PLC does not lock up waiting for a response from the slave device.

This code is an example of a user written communication protocol

This code allows you to see both the Modbus response packet and every byte received from the Modbus slave.  This allows you tremendous debug capability that is not available with the TBASIC Modbus support.

I will post the PLC code and the documentation in pieces to keep them under 200KB


Gary Dickinson

Pages: 1 2 [3] 4 5 ... 33