Shop OBEX P1 Docs P2 Docs Learn Events
How can I count how long it takes for a pin to change states? — Parallax Forums

How can I count how long it takes for a pin to change states?

P!-RoP!-Ro Posts: 1,189
edited 2008-12-02 06:36 in Propeller 1
I tried getting it to count the time and display the value, but it just freezes when it hits the waitfreq command.
code:
repeat··
····· lcd.cls
······lcd.str(string("wait...", 13))
····· RCTemp := cnt
······waitpeq(%100000, 8, 0)
····· waitpeq(%000000, 8, 0)
····· RCTemp := cnt - RCTemp

···· lcd.cls
···· lcd.dec(RCTemp)
···· waitcnt(clkfreq/1000 *30 + cnt)

However, if I use this in it's place, it will tell me the value with no problem:
· repeat
·· waitcnt(clkfreq/1000 *30 + cnt)
·· lcd.cls
··· if ina[noparse][[/noparse]8]
···· lcd.str(string("1"))
··· else
···· lcd.str(string("0"))

What am I doing wrong?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pi Guy

Comments

  • mynet43mynet43 Posts: 644
    edited 2008-11-08 01:44
    Here's some code that's used to count the time it takes a capacitor to discharge. It's used to sense the position of a pot. I think you can modify some of it to make your first method work.

    ' monitor volume pot and adj vol if needed
      vpin := 26                  ' set volume pot to pin 26
      vmsk := 1<<vpin
    
      outa[noparse][[/noparse]vpin]~~                ' initialize pin state to high
      dira[noparse][[/noparse]vpin]~~                ' set pin to output to charge capacitor
      waitcnt(clkfreq/4 + cnt)    ' wait for cap to charge to 3.3V
    
      c1 := cnt                   ' count when charged
      dira[noparse][[/noparse]vpin]~                 ' toggle pin to input to start cap discharge
      waitpne(vmsk,vmsk,0)        ' wait for pin vpin to go low
      c2 := cnt                   ' store count when discharged to 1.65V
    
      if c2 > c1                  ' skip display if time wraps
    
    



    Hope this helps...
  • AribaAriba Posts: 2,687
    edited 2008-11-08 02:09
    WAITPEQ needs a pinmask as second parameter, not the pin number.
    change your code to this:
    ...
    waitpeq(%1_0000_0000, %1_0000_0000, 0) 'wait until Pin 8 high
    waitpne(%1_0000_0000, %1_0000_0000, 0) 'wait until Pin 8 low
    ...

    Andy
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-08 02:53
    Thanks, guys, I tried it and it works. The only problem is it doesn't seem to be very accurate. Is there a way to fix that?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy
  • Cluso99Cluso99 Posts: 18,069
    edited 2008-11-08 03:09
    you are saving the counter before the pin toggles so move your statement
    RCTemp := cnt
    down 1 line
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-08 03:16
    Heres the updated code:

    ····· waitpeq(%1_0000_0000, %1_0000_0000, 0) 'wait until Pin 8 high
    ····· waitpne(%1_0000_0000, %1_0000_0000, 0) 'wait until Pin 8 low
    ····· RCTemp := cnt
    ····· waitpeq(%1_0000_0000, %1_0000_0000, 0) 'wait until Pin 8 high
    ····· RCTemp := cnt - RCTemp

    It is meant to tell me what the time is between pulses of a spark plug, so that is why I wait for it to go high first, to improve accuracy. What I think part of the problem is, though, is when cnt restarts to zero, giving wrong results. Have any of you found a way to fix this?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy
  • Cluso99Cluso99 Posts: 18,069
    edited 2008-11-08 03:48
    cnt is an endless 32 bit counter which just overflows back to 0.
    What your code is doing is just timing between the pin going low and back to high again - not the whole cycle.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2008-11-08 04:00
    Pi, there's a shorthand for making a pin mask, |<, the first line can be rewritten as
    waitpeq(|<8,|<8,0)

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-08 04:02
    doesn't explain how my numbers can suddenly jump up by 10,000 units and back down almost emmediately after. It also does it in the opposite direction making it very low and back up again. It doesn't do it very often, but I don't really like it doing it period.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy
  • AribaAriba Posts: 2,687
    edited 2008-11-08 06:52
    What is the frequency of the pulses? Perhaps Spin is to slow and loose out one pulse from time to time.

    You can try it with a counter to detect the pulses. This code uses the POSEDGE DETECTOR mode. Every time a pulse occures, the PHSA register will be incremented:
       ctra := %01010 << 26 + 8   'Init PosEdge Detector on Pin 8
       frqa := 1
       ...
       repeat
          phsa~
          repeat until phsa    'wait until first pulse
          RCTemp := cnt
          phsa~
          repeat until phsa    'wait until second pulse
          RCTemp := cnt - RCTemp
          ...
    
    



    Andy
  • mynet43mynet43 Posts: 644
    edited 2008-11-08 16:28
    The problem may be that you didn't account for the CNT wrapping when it fills up the 32 bit register.

    If CNT < RCTemp then skip this loop and reset RCTemp.
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-08 20:14
    I·have an attachment of my code using mynet's and Pauls suggestions. It still doesn't seem to work quite the way I want it to, though, skipping from 24000 to 1300 every once in a while. I'll try Andy's method later and see if it works.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy
  • mynet43mynet43 Posts: 644
    edited 2008-11-10 00:17
    You didn't make it clear what's triggering pin 8, whether it's a constant frequency and what that frequency is...

    It would be easier to help if we knew exactly what you're trying to accomplish. The latest code looks like you're trying to display the half-cycle time of pin 8, every 500 ms.

    Need more info...
  • mynet43mynet43 Posts: 644
    edited 2008-11-10 00:26
    Noticed one more thing.

    You have:
          if T1 > T2
             counter
    
    



    "counter" is the name of the routine you're in. Generally, it's not a good idea to call yourself unless you really know what you're doing.

    It would be better to reverse the logic:
         if T2 > T1
           time := T2 - T1
    
           lcd.cls                                             
           lcd.dec(time)
    
         waitcnt(clkfreq/1000 *500 + cnt)
    
    
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-10 01:25
    mynet43 said...
    You didn't make it clear what's triggering pin 8, whether it's a constant frequency and what that frequency is...

    It would be easier to help if we knew exactly what you're trying to accomplish. The latest code looks like you're trying to display the half-cycle time of pin 8, every 500 ms.

    Need more info...
    The only reason I made it every 500ms is so I could read the results on the lcd. I was hoping to eventually use the time to find out the rpm, but right now I'm wondering if counting the pulses over a set period of time to find the RPM would be better. As for what is triggering the pulse is a wire wrapped around the sparkplug and attached to an npn transistor (on the breadboard). The wire doing this is the green one in the picture, attached to a breadboard with an alligator clip. Every time there is a pulse, the blue led on the breadboard flashes and pin 8 is connected to base.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy
    640 x 480 - 24K
  • Cluso99Cluso99 Posts: 18,069
    edited 2008-11-10 03:58
    Please describe your circuit to pin 8 better. Am I correct in assuming you have connected pin 8 to the base of the transistor? While not a specialist in this area, I would think that the input probe (your wire to the sparkplug) should be connected to the base.

    Further, what protection do you have for the prop input pin (and the transistor for that matter)? I am concerned at what voltage the spike is. You need some form of voltage limiter here. Maybe a resistor (high value) from the input probe to the base of a transistor, and the emitter (presume npn) to ground on the pcb. Place a capacitor and a zener across the base - emitter. I suggest a 0.1uF and 5v zener (or 3v3). You may not even require the transistor at all.

    One of the forum members may care to comment on this circuit as it is not my area. Beau - you there???
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-10 04:35
    I described the schematic better in a different post on a robot I am building, but I posted this question here so I could get better answers on what to do for the programming. You can read this post here. http://forums.parallax.com/showthread.php?p=756088

    I actually stole this picture from parsko's post, but I have been using it to show basically how it is set up.
    circuit.gif
    Besides what is on this picture, I have a 10k ohm resistor connected to 3.3v going to the pin allong with the output of the transistor.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy

    Post Edited (I LIKE PI) : 11/10/2008 4:43:28 AM GMT
  • Cluso99Cluso99 Posts: 18,069
    edited 2008-11-10 06:10
    OK, the circuit looks fine to my way of thinking.

    So, presume your engine can do a max 6,000 rpm, that makes the pulses coming at max 100 rps = 10mS. Therefore, with an 80MHz xtal you should be counting a cycle maximum of 80,000,000 / 100 =800,000. If you have 1000 rpm then 800,000 / 6 = 120,000 clocks approx. This should help you work out what you expect to see.

    Now for your code: As mentioned above, you are only counting half the cyce and probably the spike width is varying quite· deal (not very accurate). So try this..
    waitpeq(|<8,|<8,0) 'wait until Pin 8 high
    waitpne(|<8,|<8,0) 'wait until Pin 8 low 
    
     
    repeat   
          T1 := cnt
          waitpne(|<8,|<8,0) 'wait until Pin 8 low 
          waitpeq(|<8,|<8,0) 'wait until Pin 8 high 
    
          T2 := cnt
    'I think the following will work
          time := t2 - t1
    'but if it does not work when t1 > t2 (wraps around) then use this
    '      if T1 > T2
    '          time := t1 - t2
    '      else
    '          time := T2 - T1           
               
    '     lcd.cls                 '\ <== this may be causing you to miss the next cycle                           
    '     lcd.dec(time)           '/ you may have to use another cog to display the data?? but try this
     
          lcd.dec(time)
          lcd.out($0D)            ' or whatever the display char routine is called for carriage return/line feed
     
    
     
    'remove the following line
    '     waitcnt(clkfreq/1000 *500 + cnt)
    
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-29 02:25
    Sorry I haven't posted here in a while but I've been too busy to mess with code lately. Since I've had a break for·Thanksgiving·I've been reading through the Propeller Manual to understand a little more about the propeller. I'm still confused though, and I'll tell you about that later. First, though, I'll tell you what I now would like·to do with the code.

    Since there are obviously many problems with finding the exact time·between sparks, I would instead like to count them·over a certain amount of time.·I would like to do this by running two cogs, one of them counting the sparks, and a different one timing it then finding the number of sparks fired after the time is up. The only problem is I can't figure out how to do this over the cogs. I know to share variables you must place it in the pub line like this: :variable but other than that I really do not know what else to do. If you could clarify this and maybe give me suggestions for doing·this with the code I would appreciate it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pi Guy
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-11-29 19:26
    Hello Pi,

    PUB NameOfPubMethod : variablename

    is a construction if you want a method to give back a value

    As long as variables are in ONE objectfile (your mainfile or any other objectfile
    the variables that were defined in the VAR-section are global even across COGs

    below there is a short democode to demonstrate this

    MyVar is defined in the VAR-section
    then TWO other cogs where started with different PUB-methods of THE SAME *.SPIN-file
    and they both can change the value of MyVar


    If you want to use variables across OBJECTS (instead of cogs) you have to hand over
    the RAM-adress as a pointer to the other-objects

    you can do this by using the "@"-operator

    VAR
    long MyVar

    PUB give_Other_Object_the_pointer (pointer)

    call of this PUB

    give_Other_Object_the_pointer (@MyVar)

    access of this var

    long[noparse][[/noparse]pointer] := ....

    democode to show access of global variables across cogs

    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      
    VAR
      long CogStack1[noparse][[/noparse] 20]
      long CogStack2[noparse][[/noparse] 20]
      
      long MyTestVar
    
    OBJ
      debug : "FullDuplexSerial"
    
    
    PUB Main
    'the FIRST PUB-Method inside a spinfile is ALWAYS the startpoint where the program starts to run
      debug.start(31, 30, 0, 9600)
      
      MyTestVar := 100
      debug.str(string("Start MyTestVar="))
      debug.dec(MyTestVar)
      debug.Tx(13)
    
      cognew(M1,@CogStack1)
      cognew(M2,@CogStack2)
      
      repeat
        waitcnt(clkfreq + cnt)
        debug.str(string("MyTestVar="))
        debug.dec(MyTestVar)
        debug.Tx(13)
    
    
    PUB M1
      repeat
        waitcnt(ClkFreq * 3 + cnt) 'wait 3 seconds then set MyVar to value 1
        MyTestVar := 1
    
    
    PUB M2
      repeat
        waitcnt(ClkFreq * 5 + cnt) 'wait 5 seconds then set MyVar to value 2
        MyTestVar := 2
          
    
    



    from this democode you should get an output to a serial-terminalsoftware like PST.EXE
    that looks like this

    MyTestVar=100
    MyTestVar=100
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=2
    MyTestVar=1
    MyTestVar=1
    MyTestVar=1
    MyTestVar=2
    MyTestVar=2
    MyTestVar=2
    
    



    by the way: the debugoutput included can make a lot of things clear whats going on in a program
    it uses the same pins as your USB-cable to download the program to the prop. This means it needs
    no additional hardware no LCD, no tv, no vga-monitor, no LED

    best regards

    Stefan
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-11-30 05:04
    Thanks, Stefan. I understand it much better now. I guess I'll work on the code for it tomorrow, then.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    PG
  • P!-RoP!-Ro Posts: 1,189
    edited 2008-12-02 06:36
    I now have accurate code to detect the rpm of my engine. The attachment is below. What I changed in it is I now have a cog doing the counting, and a cog displaying the results every second. Also, I've added an extra pause in it to prevent errors in the counting process. This has made it much more accurate. At 10,000 rpm, I have 6ms to work with between pulses, so my 2ms pause does nothing to lower the results. The current code I have has an accuracy of +-120rpm (1 spark), and I hope to make it even more accurate in the future.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    PG
Sign In or Register to comment.