Shop OBEX P1 Docs P2 Docs Learn Events
spin help: wait for pins to be stable — Parallax Forums

spin help: wait for pins to be stable

nohabnohab Posts: 96
edited 2008-10-03 20:50 in Propeller 1
Hi,

I want a process to wait until 2 pins are stable at high and then 5 seconds more.
Any dip on any of the pins during this time should start a new 5 second period wait.
In other words, I want a wait until 5 seconds after the last dip.

Can anyone help me with some codelines for this, please!

Nick

Comments

  • hippyhippy Posts: 1,981
    edited 2008-10-02 13:50
    In pseudo code ...

    PRI WaitForPinHighForFiveSeconds
      timeout := now + 5 seconds
      repeat while now < timeout
        if pin low
          timeout := now + 5 seconds
      return
    
    
    


    or

    PRI WaitForPinHighForFiveSeconds
      repeat
        timeout = now + 5 sconds
        repeat while pin high
          if now > timeout
            return
    
    
    



    The only issue there is short period lows on the pin. If they are of shorter duration than you are sampling the pin at you will miss them.

    If you need to handle short period pulses you will need a slightly more complicated approach, using an additional cog.
  • nohabnohab Posts: 96
    edited 2008-10-02 18:23
    I tried the first alternative and it seems to work (ie. the low periods aren't too short)

    Thanks !
    /Nick
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-10-03 04:44
    Hello Nick,

    I enjouyed writing some democode for this

    see attached files

    best regards

    Stefan
  • Beau SchwabeBeau Schwabe Posts: 6,562
    edited 2008-10-03 04:50
    Would a schmitt trigger implementation work here to add hysteresis to the I/O pin?

    If you can spare an extra pin the code is simple....

    1) Read the input pin
    2) Make the output pin equal to what was read in #1


                      1K         10K
    Actual Input >---/\/\---o---/\/\---< From Output Pin
                            |
                            o----------> To Input Pin
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 10/3/2008 4:58:49 AM GMT
  • nohabnohab Posts: 96
    edited 2008-10-03 06:46
    Stefan: Your "elapsed_time_msec" fits perfectly here !
    When using waitcnt, the systemcounter rollover isn't any problem but doing other thing meanwhile, like checking if the pin has changed, makes it a problem. THANKS A LOT for your democode !

    Beau: The idea with schmitt trigger using an extra pin is good, I'll add it to my notes, but doesn't solve the problem in this case.
    Maybe I should have told the whole story directly: I'm building a speedometer for my model railway. The input pins are connected to two IR-detectors sensing a model train passing. The detectors are mounted between the ties together with two IR-diodes mounted upwards, so the IR-beams are reflected by the bottom of the loco or waggons. The reflection isn't constant so the pin will vary high-low as long as the train passes (eg. due to gaps between waggons)
    What I want to achive is waiting for tho whole train to pass and then 5s extra.

    Flow:
    Idle state: waiting for first trig of one of the detectors
    First trig: store counter, wait for the other detector to trig
    Other counter triggered: calculate time and speed, show on display, wait until whole train passed both detectors plus 5 s
    Reset display, back to idle state

    Nick
  • Ken PetersonKen Peterson Posts: 806
    edited 2008-10-03 12:51
    StefanL38: If you modify your elapsed_time_msec function to shift the values right by one bit, then SPIN will treat them all as positive values ranging from·00000000 to 7FFFFFFF.· ·Then you can measure up to 53 seconds but you lose·one bit of precision. If you're rounding off (actually, truncating) to the nearest millisecond you won't miss it.· Your scaling factor to convert to milliseconds will need to be divided by 2 to compensate.

    [noparse][[/noparse]code]

    PUB elapsed_time_msec(p_TimeVar)
    'can measure up to approximately 53 seconds at 80MHz
    · result := ((cnt >> 1) - (p_TimeVar >> 1))&$7FFFFFFF/(clkfreq/500)

    [noparse][[/noparse]/code]
    Essentially what we're doing here is forcing the propeller to do·31-bit unsigned·arithmetic instead of 32-bit signed arithmetic.·

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·"I have always wished that my computer would be as easy to use as my telephone.· My wish has come true.· I no longer know how to use my telephone."

    - Bjarne Stroustrup

    Post Edited (Ken Peterson) : 10/3/2008 1:31:58 PM GMT
  • Ken PetersonKen Peterson Posts: 806
    edited 2008-10-03 13:19
    Not sure why those code tags aren't working

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·"I have always wished that my computer would be as easy to use as my telephone.· My wish has come true.· I no longer know how to use my telephone."

    - Bjarne Stroustrup
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-10-03 13:35
    hello Ken,

    good ! very short coding

    but there was a little bug in it
    the new divider for ClkFreq is 2000
    as it is the divider of a divider its not the half but the double of the divider before

    PUB elapsed_time_msec(p_TimeVar)
    'can measure up to approximately 53 seconds at 80MHz
      result := ((cnt >> 1) - (p_TimeVar >> 1)) & $7FFFFFFF / (clkfreq / 2000)
    
    



    best regards

    Stefan

    Post Edited (StefanL38) : 10/3/2008 1:57:24 PM GMT
  • Beau SchwabeBeau Schwabe Posts: 6,562
    edited 2008-10-03 14:54
    nohab,

    Still up for a hardware solution?

    "...The detectors are mounted between the ties together with two IR-diodes mounted upwards, so the IR-beams are reflected by the bottom of the loco or waggons. The reflection isn't constant so the pin will vary high-low as long as the train passes (eg. due to gaps between waggons)
    What I want to achive is waiting for tho whole train to pass and then 5s extra..."


    Seems like you need something like a "missing pulse detector".· The circuit below will output a HIGH when there is nothing blocking the sensor, and output a LOW when there is something blocking the sensor.· During brief interruptions where the sensor is not blocked, the output will·still remain LOW.
    ·
    Assuming a 1.4V threshold, an R value of 330k and a C value of 10uF provides about a 1 second delay.· Increasing the C value to 47uF provides about a 5 second delay.
    ·
    Since the threshold of 1.4V could vary from Prop to Prop , or another processor such as a BS1, BS2, or SX, it might be good to use a 1Meg pot in place of the 330k resistor so that you can fine tune the timing yourself.· Once you settle on a value that works, you can substitute a fixed value resistor in its place.


    Edit:
    If the supply is 3.3V rather than 5V, then an R value of 180k·instead of 330k will give comparable results ... still assuming that the threshold is about 1.4V

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 10/3/2008 3:19:03 PM GMT
    1107 x 835 - 140K
  • Ken PetersonKen Peterson Posts: 806
    edited 2008-10-03 15:20
    StefanL38: Yes, you are right. The factor is a denominator in a denominator. I'll admit I didn't test the code.....

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·"I have always wished that my computer would be as easy to use as my telephone.· My wish has come true.· I no longer know how to use my telephone."

    - Bjarne Stroustrup
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-10-03 20:50
    Hello,

    @Ken: I would have done the same mistake without testing the code

    @Nick: This is a very good example how different solutions can be found if a project is described in DETAIL.

    first of all: I'm developing software now for 25 years. The last 5 years especially for
    controlling machines. The code below is a result of this experience. So please don't feel
    bad if your code is more complicated or less elegant
    I guess your code is easier to understand.

    Here is a codeversion which I think does what it should to your speedmeasurement.
    I think in a quite short way taking care of the train coming from both directions
    (it doesn't matter if sensor1 or sensor2 is triggered first)
    and takes care of the sensor switching on/off as many times as he likes
    and still measure correct.

    I added methods that give the absolut time since last rollover to zero of the systemcounter
    This code uses the very short and therefore elegant calculating of elapsed_time_msec from Ken

    copy &paste this code to the Propeller-IDE to have the comfort of different colors
    for comments and PUBs etc.

    'Use F11 to store it the EEPROM. If you open the COM-Port
    'with a terminalsoftware this may cause a reset and this reset starts new booting
    'the content of RAM will be overwritten by the still different content of the EEPROM
    'loaded to the RAM by the boot-process
    
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      c_Input  = 0
      c_Output = 1
    
      c_Low  = 0
      c_High = 1
    
      Sensor1_PinNr = 21 '<== IO-Pin number that should be watched to be stable
      Sensor2_PinNr = 1 '<== IO-Pin number that should be watched to be stable
       
      c_WaitPeriod = 5
    
    VAR
      long heart_stack[noparse][[/noparse] 20]
      
      long SS_of_Sensor1  'SnapShot of Systemcounter "cnt" from Sensor1 
      long SS_of_Sensor2
    
      long Et1             'to store elapsedtime of Sensor1
      long Et2
    
      long TimeDiff
    
    
    OBJ
      'heart : "heartbeat" little object from the obex that makes an LED blink
      'that i can see easily bootphase finished after reset and Prop is running  
      debug : "FullDuplexSerial"
    
    PUB Main
      'the FIRST PUB-Method inside a spinfile is ALWAYS the startpoint where the program starts to run    
      'heart.Start(27, 200)
      debug.start(31, 30, 0, 57600)
    
      DIRA[noparse][[/noparse] Sensor1_PinNr] := c_Input ' configure PIN as Input 
      DIRA[noparse][[/noparse] Sensor2_PinNr] := c_Input ' configure PIN as Input 
    
      SS_of_Sensor1 := 0
      SS_of_Sensor2 := 0
    
      repeat
        'every mathemathical calculation that results
        'in a value <> 0 is a logical TRUE
        'so you can use a variable itself as a short kind of "SS_of_Sensor1 <> 0"
        'it's similar for negation not(SS_of_Sensor1) is short for "SS_of_Sensor1 == 0)   
    
        repeat until (SS_of_Sensor1 and SS_of_Sensor2)
          if (INA[noparse][[/noparse] Sensor1_PinNr]) and not(SS_of_Sensor1) 
            SS_of_Sensor1 := cnt       'make SnapShot
    
          'adding "and not(SS_of_Sensor1)" does the following:
          'SS_of_Sensor1 is set to zero before entering the loop
          'as long as SS_of_Sensor1 is zero the condition "not(SS_of_Sensor1) is TRUE 
          'by the first switching of the sensor SS_of_Sensor1 gets a value <> 0
          'then the condition "not(SS_of_Sensor1)" is no longer true 
          'because of this the SnapShot is NOT updated by later switching to high of the sensor   
          'this means: later switchings of the sensor are ignored 
    
          {'for debugging purposes  
          if SS_of_Sensor1          
            debug.str(string(" SS_of_Sensor1="))
            debug.dec(SS_of_Sensor1)
            debug.tx(13)
          }
    
          if (INA[noparse][[/noparse] Sensor2_PinNr]) and not (SS_of_Sensor2) 
            SS_of_Sensor2 := cnt       'make SnapShot
    
            {
          if SS_of_Sensor2          
            debug.str(string(" SS_of_Sensor2="))
            debug.dec(SS_of_Sensor2)
            debug.tx(13)
            }
    
        Et1 := elapsed_time_msec(SS_of_Sensor1)
        Et2 := elapsed_time_msec(SS_of_Sensor2)
        TimeDiff := ||(Et1 - Et2)
    
        'here you add calculating and displaying time and waiting for 5 seconds
    
        if (SS_of_Sensor1 and SS_of_Sensor2)
          debug.str(string(" TimeDiff="))
          debug.dec(TimeDiff)
          debug.tx(13)
          waitcnt(ClkFreq + cnt)
          SS_of_Sensor1 := 0
          SS_of_Sensor2 := 0
          
    
    PUB Absolute_microsec : microsecs 
      microsecs := ((cnt >> 1) & $7FFFFFFF / (clkfreq / 2_000_000))
    
      
    PUB Absolute_msec : millisecs 
      millisecs := Absolute_microsec / 1_000
    
    
    PUB Absolute_sec : seconds 
      seconds := Absolute_microsec / 1_000_000
    
    
    PUB elapsed_time_msec(p_TimeVar)
    'can measure up to approximately 53.7 seconds at 80MHz 
    'remove bit 32 which is the sign "+-" by shift bits one to the right by ">> 1"
      result := ((cnt >> 1) - (p_TimeVar >> 1)) & $7FFFFFFF / (clkfreq / 2000)
    
    '80 MHz = _xinfreq = 5_000_000 with _clkmode = xtal1 + pll16x 
    '5_000_000 = 5 MHz x pll16x = 80 MHz  
    'with lower pll_x-factors than pll16x measuring-range goes up with
    'factor 80MHz / ClkFreq   =    80Mhz / (_xinfreq * pll_x)
    'example: 5 MHz * pll4x   =    20 MHz. measuring-range: 53.7 seconds * (80MHz / 20MHz) =     
    '53.7 seconds * 4 = 214.8 seconds
    
    
    
    



    best regards

    Stefan
Sign In or Register to comment.