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 ... 25 26 [27] 28 29 ... 34
391
Technical support / Re:Memory after power down
« on: July 12, 2012, 06:42:13 PM »
The EEP commands DO NOT work on the simulator.

The EEP commands only work on real hardware.

The simulator is very rudimentary.  Unfortunately, there are other things that the simulator cannot handle.  

A good hint is that the simulator does not ask your what PLC you are using, what options you have installed or what revision firmware is running on the PLC.  All of these things would be needed to be "known" by the simulator for it to do a better job.

Sorry,

Gary D.

392
Technical support / Re:Sequencing question
« on: June 20, 2012, 11:00:42 AM »
The following are the 2 custom functions that manage the down
counting of a variable and set/clear a RELAY to indicate the state
of the software counter.



' LoadLoopCntr - Custom function to load loop counter with HMI value
'
' The RELAY LoopCntrZero is used to control Seq1
'
' LoopCntr is defined as DM[1] using the #Define mechanism - Down counter used to control Seq1
' HMICnt is defined as DM[2] useing the #Define mechanism - This value is from the HMI

IF (HMICnt > 0)
???LoopCntr = HMICnt
ELSE
???LoopCntr = 5???' Default loop count
ENDIF

CLRIO LoopCntrZero





' DecLoopCntr - Custom function to decrement LoopCntr
' The RELAY LoopCntrZero is used to control Seq1
'
' LoopCntr is defined as DM[1] using the #Define mechanism - Down counter used to control Seq1


LoopCntr = LoopCntr - 1
IF (LoopCntr <= 0)
???SetIO LoopCntrZero??????' The counter has hit ZERO!
ENDIF





I can send you a running PLC program that you can run in simulation if you provide me an email address.  My email address is in my forum profile.  You can contact me via that address.

Gary D.

393
Technical support / Re:Sequencing question
« on: June 20, 2012, 10:56:28 AM »
This is the ladder logic portion of the state machine.  

I chose not to use a ladder-logic COUNTER because of your requirement to have the loop count adjustable.  I chose to use custom functions to manage a software counter that sets a RELAY, LoopCntrZero, to indicate when the loop count has expired.

I would have used a ladder logic COUNTER if the loop count is always the same.

Gary D

394
Technical support / Re:Sequencing question
« on: June 20, 2012, 10:53:10 AM »
I will give you a bullet-proof approach to using the Sequencers for you issue.  I will spread it across a couple of these messages.

The idea is to implement a Moore State Machine (computer science 101).  I have used this approach to build very complex PLC projects.

The following diagram is what I intend to build.

Gary D

395
Technical support / Re:Control outputs using DM
« on: June 01, 2012, 05:32:20 PM »
A couple of questions:

Is the PUMP OUTPUT used in any of your ladder logic?  

How is your custom function, that contains the code that is supposed to control PUMP, invoked from the ladder logic?  What ladder logic code triggers the custom function? Is the custom function run periodically, say every second?

Gary d

396
Travis,

Excelent bit of sicence to get a handle on the magnitude of the problem.

A 0.25% error is very small!  If you look up the specs for a nice Fluke DVM, say the model 179 that retails for almost $400 you'll find that its only a 1% meter when measuring 60 Hz AC voltage!  With DC voltage its spec'd at 0.09% + 2 counts.

I agree with your decision to stay with simple code!

Gary D


397
The periodic interrupt approach is an excellent mechanism for polling the I-7017s.  

Once again if your code wastes time waiting for the response from the i7017, the ladder logic bits may run slow.  If you use the periodic interrupt mechanism you should also use it to keep track of "time" by incrementing a variable on each call to the interrupt routine.

The use of the Netcmd$ function is convenient, but it ties up the PLC until the I-7017 responds.  If you find that this is where the time is spent (and this messes up the PLC behavior), then you can build your own version, a non-blocking version, that does not tie up the PLC.

A "non blocking" version of netcmd$, requires two or more special functions and some ladder logic.  

The first special function sends the request to the I-7017 and then sets a RELAY to indicate that a response is expected. This function will be very fast and will exit probably before the first character is transmitted.

Using ladder logic you will start a timer that will run for about 100ms and the invoke the second custom function.  The assumption is that 100ms is long enough for the Plc to send the request, the I7017 to process the request, the I7017 to transmitt the response and for the Plc to accept the transmitted response.  

The second function parses the response.  It does not wait for a response, the response data will already be available. Note that I have not even mentioned a retry mechanism, you'll probably need one.

This is pretty complicated stuff but it allows the PLC to be very responsive because your special function code is never wasting time waiting serial data to be sent or waiting for a response from the i7017.  The ladder logic will not miss fast clocks and will remain responsive to inputs.

398
Travis,

In response to your question about approaches to make delayed clocks.  I've included another version of code that I have used in one of my PLC projects.

This version uses only a single COUNTER, but using the Sequencer mechanism that is available only to the first 8 counters in the PLC.  The other version used a RELAY for each state and chews up more of the PLC resources.

This version divides the incoming clock by 5.  Each output runs at 1/5 the input clock rate and each output is delayed in phase from each other by one input clock.

If you want a one second output clock, run this circuit from the 0.1sec contact and change the Set Value of Seq1 to 9 (divide by 10).


Gary D.

399
Travis,

I glad you are making such good progress.

The ladder logic snippet is how I make delayed versions of clocks. I just use a string of RELAYS to generate delayed version of the system clock. This way I can distribute CPU intensive stuff across different scans of the ladder code.

Changing the BAUD rate will reduce the time that is required to communicate with the I-7017, however it will have no affect on the amount of time that the I-7017 takes to respond to the request for data.  So speeding up the BAUD rate by 4X will not cut the time for the special function to 1/4.

The issue with polling dead hardware: if the I-7017 goes off-line because it dies, the RS-485 cable is gets un-plugged or any of several doomsday possibilities, is with the NETCMD$() function.

This function builds a string based on the arguments that you provide, packs this string into a buffer that transmits the characters out the serial port and then waits for something to reply to the message.  

If your I-7017 doesn't reply in a few seconds the NETCMD$() will timeout and return some sort of error status.  The amount of time that the NETCMD$() waits is not specified, but I've found that it will wait at least 3  seconds. Your special function will hang up until the NETCMD$() times out.  If you retry the NETCMD$() 10 times in a single special function, this code may take 30 seconds to complete (actually fail).

The idea with the ADCError was to set this RELAY if the I-7017 appears to go dead.  I post error messages to get someone to troubleshoot the problem.  The ADCError is also used by other code in the PLC program to do what ever I can to keep the system working safely without the use of the I-7017 data (limp-home mode for a car).

I set the ADCError on the 1st.Scan of the ladder logic and then initialize the serial port (set the baud rate) and initialize the I-7017.  If the I-7017 responds correctly after initialization, only then do I clear the ADCError RELAY.

Another approach to deciding how often to poll your flow sensors is to ask your self, "how accurate is the output of the sensors?". Don't be surprized if they are spec'd at +/- 5%.  The I-7017 will add some error.  You may pick up a little error with the integer math on the PLC. No matter how often you sample the input data, your results can never be more accurate than your raw data, the results will always be worse.  Just figure out how much uncertainty you and the customer can tolerate.

Gary D



400
Travis you have to be very careful with the coding of custom functions to ensure that they execute very quickly becuase the ladder logic scanning mechanism can not proceed until the function completes.

I didn't like the sample HMI code because of the polling of the keyboard I/O every 0.1s.  My version uses ladder logic to detect if a single key is pressed, and then and only then invokes a custom function.  Why waste time in a custom function when there is no key pressed, therefore there can't be anything to do.  

The the PLC comunicates with the I-7017 over RS-485 and the NETCMD$() function has to wait for the serial mesage to be transmitted to the I-7017, then processed by the I-7017 and then wait for a message to be send by the I-7017.  This whole process could easily take 100ms.  If you are talking to 3 I-7017s on the same scan your could be tying up the PLC for close to a 1/4 second every second!

I'd suggest that you poll I-7017 at the lowest rate that that makes sense.  Do any of your analog inputs change much in 1 second or 10 seconds or 100 seconds?  I worked with an 400 gallon aquarium that took about an hour to change 1 degree C with the heaters running full blast.  There is no point in checking it's temperature once a second.  I checked it once every minute and that was serious overkill.

For sake of arugument, lets say that you could safely poll your I-7017 once every 10 seconds.  Poll the first one at 10 seconds, the second one at 11 seconds, the third one at 12 seconds...

The following is the code that I use for a single I-7017.  The code is a little more complicated than the example code.  This code is much more robust that the example code and provides methods to allow the PLC to continue to function even if the I-7017 dies.

The Simulation RELAY is checked to see if I am running the code in simulation vs. real hardware.  The simulator doesn't simulate NETCMD$().  The ADCError is a RELAY that is set if the I-7017 quits responding or has not been successfully initiated.  I do not want my PLC to lock up polling dead hardware.  

I have a retry mechanism that will wait and resend the NETCMD$().  I found that this improved the reliability of the system tremendously.  I kept track of how many retries were required and it was less than 1 every week on my system.  The retry was much better than having the system fail once a week.

The for next loop at the end of the code extracts the ADC value for each channel and then scales it to enginerring values that are easier to read.  It's easy, even for my old brain, to read 370 and think that means 37.0 C. The scaling components are stored as a set of 3 integer values in DM.

Writing to the LCD was done on the next ladder scan.



' ReadAllADC - function to read, scale and format all 8 analog value from I-7000
'
IF (TestIO(Simulation) = 0) AND (TestIO(ADCError) = 0)
???' Read all available ADCs from a I-7000 device
???' NETCMD$ is used to send command and wait for response
???' using the suffix "~" to suppress the FCS computation

???I = 4?????????' Retry count
???W$ = NETCMD$(3,"#01"+CHR$(13)+"~")
???WHILE (LEN(W$)= 0) OR (ASC(W$,1)<> 62)
??????I = I - 1
??????IF (I = 0)
?????????SetIO ADCError : RETURN??????' Still not working
??????ENDIF

  ??????'   Retry command
??????'
??????DELAY 10
??????W$ = NETCMD$(3,"#01"+CHR$(13)+"~")  
???ENDWHILE

???' Extract all numerical digits from the response but omit the
???' decimal point. Each data fragment is represented as a percent of
???' the A/D fullscale (+100.00 to -100.00). Full scale input is 250mV.
???' "+xxx.yy" or "-xxx.yy".
???' Extracted integer integer data will be returned in DM[201] to DM[208]
???
???FOR I = 0 to 7
???   ???T = VAL(MID$(W$,2+I*7,4)+MID$(W$,7+I*7,2))  ' Get the digits w/o the period

??????' Scale the data to engineering units
??????'
??????T = T * DM[41+I*3]
??????IF (DM[42+I*3])
?????????T = T / DM[42+I*3]
??????ENDIF
??????T = T + DM[43+I*3]
 ???  ???DM[201+I] = T????????????????????????' Store Scaled result for this channel
???NEXT

ENDIF


[/color]

Gary D

401
Technical support / Re:Logical Comparison Limit
« on: May 01, 2012, 11:28:07 AM »
You can use very long statements in TBASIC.  I suspect that their may be a limit to the number of ASCII characters in a single line that TBASIC can handle.  If there is a maximum line length, I have not found it, yet.

As an example, this statement complies with TBASIC and appears to work:

IF A=B AND B=C AND c=d and d=e and e=f and f=g and g=h and h=i and i=j and j=k and k=l and l=m and m=n and n=o and o=p and p=q and q=r and r=s and s=t and t=v and v=w and w=x and x=y and y=z and A=B AND B=C AND c=d and d=e and e=f and f=g and g=h and h=i and i=j and j=k and k=l and l=m and m=n and n=o and o=p and p=q and q=r and r=s and s=t and t=v and v=w and w=x and x=y and y=z then DM[1]=1 else DM[1]= 0 endif
[/color]
Personally, I think that if you need to do this many logical operations in a single TBASIC statement, you might want to rethink your approach.  Code this complex is impossible to read, impossible to trouble shoot and impossible for the next guy to maintain.

Gary D.



402
Technical support / Re:MSB LSB
« on: April 11, 2012, 09:21:21 AM »
Marcus,

Welcome to fun with trying to build a 32bit value from two 16bit pieces.  TBASIC treats everything in DM[] as 16 bit signed integers.

More accurately, TBASIC, only works with 32bit signed values.  Fortunately, the TRiLog guys have thrown in some support to help deal with the assembling a 32 bit value from 16bit values in the form of SETHIGH.  A similar problem is how to disassemble a 32 bit value into 16bit words is solved with GETHIGH.

The following example shows how to assemble a 32bit value from a pair of 16 bit chunks.  The first version is what I'd recommend, the second version shows how it could be done w/o the use of SETTHIGH.


' Assemble32b - build 32bit value in A from two 16bit
'  words stored in DM[1..2]
'
'
' Value in DM[1] is the least significant word
' Value in DM[2] is the most significant word

'
' If DM[1] is greater than or equal to &h8000 it will be treated as a negative number
'  and sign extended when assigned to the 32bit variable A.  So if DM[1] was &H8001, then
'  A will become &HFFFF8001 after the assignment.
'
' The SETHIGH16 statement will overwrite the most significant 16 bits of A with the value held
'  in DM[2].
'
' The order of the following statements is critical...
'

A = DM[1]????????????' least significant word (with sign extension)?????????
SETHIGH16 A,DM[2]??????' most significant word.

' This code is how it could be done without the
'    use of the SETHIGH function.
'
'
B = DM[2]               ' most significant word, first
B = B * &H10000         ' 16bit left shift to get msw into position
B = B + (DM[1] & &HFFFF)   ' least significant word placed
                           '   without messing up the msw

[/color]

Gary D

403
Technical support / Re:MPU Input
« on: April 02, 2012, 06:36:01 PM »
Marcus,

If you make a table in DM with paired values. One of the pairs being the RPM and the other being the Step value you can do a linear search through the table.

I prefer to build a single table with paired values because it is easier to maintain then two separate tables.  The issue is that if you add a new entry to a table you must remember to do this in two places.

I use a "end of table value" to mark the end of the table.  This way your code does not have any idea how many entries are in the table.  If you add or subtract entries, the code that does the searching does not need to be changed. The end of table value must be larger than any possible RPM value.

The following custom functions builds the table in DM[].  In your production code you might want to save the table in EEPROM and just copy it into DM[] or you could access it in the EEPROM (as in one of the earlier suggestions).

For test purposes, I invoke this code with a 1st.Scan contact in the ladder logic.


' RPM / Step Look up table.
'
'  First entry in each pair is the RPM
'  Second entry is the step value for that RPM
'  The table is in ascending RPM values. There can not be any duplicate
'  RPM values.  Step values can be duplicates.
'
' The last RPM entry is used to mark the end of the table
' this way if you add entries to the table the algrithms will
' adjust automatically

'   ???RPM?????????????????????  Step
'
DM[TableBase + 0]  = 2??????: DM[TableBase + 1]  = 1
DM[TableBase + 2]  = 6??????: DM[TableBase + 3]  = 5
DM[TableBase + 4]  = 8??????: DM[TableBase + 5]  = 8
DM[TableBase + 6]  = 10??????: DM[TableBase + 7]  = 9
DM[TableBase + 8]  = 16??????: DM[TableBase + 9] = 14
DM[TableBase + 10] = 18??????: DM[TableBase + 11] = 30

' end of table marker is the largest positive intger that can
' be represented with 16 bits
'
DM[TableBase + 12] = &H7fff???: DM[TableBase + 13] = 100???
[/tt]

The following is the code to search though the lookup table in DM[]


' CalculateStep
'
' On entry R holds the RPM value
' On exit S  holds the Step value, I is changed.
'
' TableBase is the offset to the table in DM for the paired RPM/Step values
'    TableBase uses the #Define mechanism. This allows you to put the table
'    anywhere in DM without having to fix every usage in every custom function.

'
' The following is a brute force linear search through the RPM/Step lookup
' table.  

I = TableBase

WHILE R > DM??????
???I = I + 2 ??????' RPM in the table is measured RPM so...
                       ' try the next entry pair???
ENDWHILE

' RPM is just right, now return the step value for this RPM
'
S = DM[I+1]

[/tt]

Best of luck,

Gary D

404
Technical support / Re:MPU Input
« on: April 01, 2012, 01:20:40 PM »
Marcus,

If you are still struggling I would be happy at taking a whack at algorithms.  

As was mentioned, if you have a linear relationship between RPM and your magic step number, then a lookup in DM[] is often a good solution.

But, the data you presented is linear.  The equation y= 1000/1550*x describes your problem.  Since TBASIC only work with integers you have to be a little careful with the order that you perform your arithmetic.

With X as your RPM value then you can solve for Y (step):

  Y = (X * 1000) / 1550

Simple, no tables.

Gary d

405
Technical support / Re:Way to advance the time/date in the simulator
« on: March 23, 2012, 05:06:40 PM »
The simulator Time/date variables are normally loaded with the time/date of the PC when the simulation is started.

You can change the simulators time/date variables when you have the if you click on the "VIEW" button in  them simulator.

Click on the "Edit" button to bring up the "View Variables - Integers" dialog.

If you want to set the simulator time to 23:59:00 you will have to type "TIME[1]=23" and press enter to set the hours to 23.

TIME[2] sets the minutes and TIME[3] accesses the seconds.

DATE[1..4] allows you to change the Year, Month, Day and Day of Week values.

Please be aware that the TIME[] and DATE[] registers can change as your is reading them.  If the time is 23:59:59 it is possible for your TBASIC code may read it as 23:59:59 but if you are unlucky you may read the time as 23:59:00.  Newer PLC families have addressed this issue with the STATUS(18) mechanism.

You may want to look at some sample code that I shows how to set/clear RELAYS base on the RTC without getting glitches.


http://www.tri-plc.com/trilogi/RTCAppByGDK.zip

Please note that the sample code did not worry about the date.  You should take the same precautions with the DATE[] values as I did time the TIME[] values.


Gary D

Pages: 1 ... 25 26 [27] 28 29 ... 34