Shop OBEX P1 Docs P2 Docs Learn Events
Timers, counters, and Cogs Oh My! — Parallax Forums

Timers, counters, and Cogs Oh My!

AshTillotsonAshTillotson Posts: 2
edited 2012-11-12 16:46 in Propeller 1
I’m looking to build a small controller using a Prop that looks at 2 inputs to control an Up/Dn Timer, then outputs a frequency that correlates to the Timer Value.

For demonstration Purposes I am using a “Dribble” technique to open and close a linear valve that takes 5 full seconds to go from closed to open and vise versa. There is a Product Flow Meter that measures flow in Gallons. This meter is designed for 700 Gallons per minute, so if my Timer is at 2500 mSec then my Valve should be at 50% open which means the meter will output 350 gallons per minute with a frequency of 291.66 hz

MaxTime = 5000 mSec
MaxFlow = 700 Gallons per min
PPG = 50 pulses per gallon

For example,
If Pin1 and Pin2 are High then a Timer counts up to Max Time. (for testing this would be 5000 milliseconds)
If Pin1 and Pin2 are Low then a Timer counts down to Zero.
(This Timer only counts up or down while this condition exists, so If from zero, both pins are high for 1.487 seconds then the Timer is held at 1.487 seconds. If an hour later they are then low for .309 seconds then the new Timer value is held at 1.178)
If Pin1 <> Pin2 then do nothing ‘ added for clarity
FreqOut = (Timer/Maxtime)* (Maxflow * PPG)/60S
Pin 16 = FreqOut


In this example the Timer value represents valve position. (It takes 5 seconds to Fully open and 5 Secs to fully close a valve)
Using 2 inputs in this fashion replicates the function of “Dribble” control.
The output frequency represents the (Timer value/Maxtime*Maxflow*pulses per gallon /60 sec) to create a pulse train (50/50 duty cycle prefered) that correlates to Valve position.
(I am assuming perfect linearization between valve position and flow rate which is virtually impossible, however it will work well for my needs)

If this could fit in one Cog that would be best as I need 4 of these and probably a 4 line LCD in the main Cog. For a total of 5 cogs. The display is not really necessary it’s just an added feature to help the project look a little more professional. For now I would likely use the TV out or the Serial Debug screen.

The Real Reason I want to build this:
I am a Maintenance Technician and The company I work for is giving me some artistic freedom to help build a test lab and If I produce a piece of test equipment that can simulate loading conditions in order to test our own systems then I will be trusted to expand this concept to everything that I do. There will literally be a dozen different controllers in my office used for troubleshooting and testing of various things for years to come with the Propeller Chip.. The best part is, embedded programming is a hobby of mine and I will finally get paid to do what I love! Before I started playing with the Prop Chip, I was creating a 5 chip Microchip platform where 4 (Pic 12f’s) chips were virtual slave Cogs to the main (Pic 18f) using i2c to poll. Half way through my design I discovered the Prop and was blown away, but I haven’t had much time until now to get back into Embedded Programming. But today, I Begin!

Q1. If I’m using 1 Counter for Timer and 1 Counter for FreqOut I think that this little bit of code would fit in one cog as there are two counters per cog. No?
Q2. Our automation system that uses Triacs for its outputs so the inputs are actually 110 VAC (Some bleed Voltage present, even when off) to drive an AC Input Opto coupler to the Prop Chip. Does anyone recommend an optocoupler I should use that wouldn’t be triggered by the leaked voltage from the Triac output? (Should I use a Pull down resister?)
Q3. The pulse train will need to be 12 DC to the automation system and I think I can use a 2n2222 transistor but I was thinking of using an optocoupler for that. Any recommendations?

All opinions are welcome and ANY help with code would be awesome. I would like to program in C however, if Spin is quicker for getting started then that’s fine too. I can always convert later.
Thanks so much,
Ash Tillotson

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2012-11-06 13:39
    For me it looks like you should not use the counter for implementing the timer. There are several problems:
    1. there is no counter mode which supports 2 input pins as you described it (counting up and down)
    2. for the counters there is no limit, they simply go round and round without COG intervention

    So, this means that I would simply implement some code to count up and down and avoid to exceed the limits. But here you have to answer some more questions:
    Is it fine to sample the input pins? Meaning that you simply look at the pins each 1ms and count up/down according to the result?

    Having dedicated code for the timer on the other hand frees a counter to generate the frequency. This way you can have 1 COG to do the counting for 2 timers and output 2 frequencies. So in the end for your 4 units, you'd only need 2 COGs.

    I'd go with SPIN/PASM.
  • kwinnkwinn Posts: 8,697
    edited 2012-11-06 17:25
    If the maximum count frequency is only 2 x 291.66Hz you may be able to use a case statement in spin to increment/decrement/do nothing to the counter. Using PASM this could easily be done for 4 or more counters at that frequency. The counts could be stored in hub ram so a spin program could access them.
  • JonnyMacJonnyMac Posts: 9,108
    edited 2012-11-07 00:01
    You could easily fit two of these into a cog. The key is using a timed loop (set to 1ms) to check your inputs, do the calculation, then update one of the two counters in that cog to output your frequency. Pretty easy, really. This means you could in fact monitor four sets of sensors and have four frequency outputs with just two cogs, leaving four to handle HMI and other chores.

    This is what the main loop in the cog might look like:
    pub main | t 
    
      t := cnt
      repeat
        if (ina[SENSE_2..SENSE_1] == %11)                           ' both high?
          timer := ++timer <# MAX_TIME
          update_freq(timer)  
        elseif (ina[SENSE_2..SENSE_1] == %00)                       ' both low?
          timer := --timer #> MIN_TIME
          update_freq(timer) 
         
        waitcnt(t += MS_001)                                        ' check every millisecond
      
    
    pub update_freq(counts) | freq
    
      freq := (counts / MAX_TIME) * (MAX_FLOW * PPG) / 60_000
      update_freq
    
  • AshTillotsonAshTillotson Posts: 2
    edited 2012-11-12 06:53
    Thanks to all for your reply's.
    I have played with Jonnymac's code and got some success.

    I do have a few issues with "timer := ++timer <# MAX_TIME" For some reason this will not pass the variable "timer" to "pub Product1(counts)".
    When I reverse "<# " to " #>" It does pass the value but of course it will not limit it to Max_Time.

    The other big issue is my main time loop needs to increment "timer" accurately but I'm pretty sure its taking too long. When I hold down both inputs for 5 seconds i usually get about 1200 ms which ultimately affects the Frequency.

    I and using 2 objects found in the demo files of the Spin compiler.
    I can attach if necessary.

    "Synth" - Creates a nice 50/50 duty cycle square wave.
    "Parallax Serial Terminal" - puts my data on the serial terminal.

    Here is the Code: - many thanks to JonnyMac
    I have added many comments and questions to the code for clarity.
  • JonnyMacJonnyMac Posts: 9,108
    edited 2012-11-12 10:57
    You are inserting PST commands into your critically timed loop which is causing problems. When I want to monitor processes like this I put the variables to monitor in the hub (as yours are) and then start another cog that spits out their values on an appropriate schedule. By doing this my critical loop is not affected by temporary debugging code. The .dec() method uses a lot of math and can take quite a long time to execute and you're using in in main and product1.
  • cavelambcavelamb Posts: 720
    edited 2012-11-12 14:26
    Since 110 volt AC line voltage is being used, yeah, isolate everything for safety sake.
    Either opto or transformer.

    Hardware and software can be replaced.
    Wetware can't...


    My industry standards are a (few decades?) out of date, so there may be better solutions out there now.
    But Opto 22 is still making and selling parts.

    http://www.opto22.com/
  • cavelambcavelamb Posts: 720
    edited 2012-11-12 14:29
    JonnyMac wrote: »
    You are inserting PST commands into your critically timed loop which is causing problems. When I want to monitor processes like this I put the variables to monitor in the hub (as yours are) and then start another cog that spits out their values on an appropriate schedule. By doing this my critical loop is not affected by temporary debugging code. The .dec() method uses a lot of math and can take quite a long time to execute and you're using in in main and product1.

    Thanks, Jon.
    A "timely" suggestion (if you'll pardon a bad pun).
    I've been having the same problem.
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-11-12 16:34
    Great product feature JM. Got an extra cog, use it for debug or give your product BIT (built-in test) feature. Adapt to your customers needs when design is ready to go. You probably had to do this anyway, so you get great selling point, cust gets useful feature. Only on the prop can this be done this cleanly far as I know......

    FF
  • JonnyMacJonnyMac Posts: 9,108
    edited 2012-11-12 16:46
    I actually do it as standard practice and if there are no cog requirement issues, leave it in. One time a client company called me and said, "Boy, I'd love to know what the device is seeing in terms of the DMX stream..." Knowing that he had a Prop-Plug I told him to plug it into the board, open PST, then restart everything. He was very happy. This project is a multi-channel DMX lighting controller and I used my monitor cog to validate DMX data coming from an external console (among other things).
Sign In or Register to comment.