Shop OBEX P1 Docs P2 Docs Learn Events
Best way to actively monitor the state (high/low) of an input pin? — Parallax Forums

Best way to actively monitor the state (high/low) of an input pin?

JeremyJJeremyJ Posts: 30
edited 2011-09-02 16:47 in Propeller 1
What's the most efficient way to actively monitor a pin for a high/low state? I've tried using a "repeat while" loop comparing two local variables in my method (1 of which calls another method that measures the pin's state, monitoring for changes). This seems way too complicated to do something so simple. Any suggestions?

Comments

  • HShankoHShanko Posts: 402
    edited 2011-08-31 17:44
    You might look into using ViewPort. It provides, among other operations, a logic analyzer view of the I/O lines, all 32.

    Of course, we have no idea at what rate the lines are changing. Using two cogs provides you with 20 MHz sampling time; 50 nsec resolution;
  • JeremyJJeremyJ Posts: 30
    edited 2011-08-31 18:06
    At the moment I'm just trying to monitor a pin connected to a potentiometer and control the pwm duty cycle on another pin. For example, a low pin setting applies a 10% duty cycle and a high pin setting applies a 90% duty cycle. Pretty simple stuff. I'd like to use the Propeller's counter modules and have the pin being monitored by a single cog, but not sure how to use the counter control registers to do this.
  • Mike GMike G Posts: 2,702
    edited 2011-08-31 18:18
    The INA register provides read only access to PIN states. See the Propeller Education kit page 48. Propeller Tool -> Help -> Propeller Education kit

    Check the state of PIN 0 for a high.
    repeat
      if INA[0] == 1
        'Do somehting
    
  • kwinnkwinn Posts: 8,697
    edited 2011-08-31 20:28
    There is also waitpne/waitpeq if there is nothing to do until the pin state changes.
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-09-01 00:28
    as you haven't posted any code.

    Is your Opinion that something like the code below
    CON
      InputPin = 9
      Low      = 0
      High     = 1
    
    VAR
      long DutyPercent
      
    repeat
      if ina[InputPin] == Low
        DutyPercent := 10
        
      if ina[InputPin] == High
        DutyPercent := 90
    
      SetDutyPercent(DutyPercent) 
    

    is too complicated for a simple thing like this?

    Would you like to solve this through using the hardwarecounters without a codeloop involved to change between
    duty 10% and 90%?

    write more about what your doing in your project. In minimum 50% of all cases if the forum has the overview about a project completely different and much better solutions to problems will be found.
    keep the questions coming
    best regards

    Stefan
  • JeremyJJeremyJ Posts: 30
    edited 2011-09-01 09:31
    Thanks for the replies. I started out like Mike G suggests above, but my code wasn't working and I didn't really know why. I think now that the problem is that I'm calling a second method (from within the 'main' method) that involves another loop, mainly pwmGen(). It seems to me that the 'main' method is executing, making a decision whether or not the pin is high or low, and then executing the pwmGen() method with the appropriate duty cycle selected. This second loop is never interrupted for the propeller to go back to the 'main' method and repeat the looped code telling telling the propeller to re-evaluate the pin state. This is what I see when I execute the code - I can detect the initial state of the pin, but when I change the state with the potentiometer, the duty cycle does not change as desired.

    I'm thinking that what I should do in this case - for processor/program efficiency - is to launch a cog to continually monitor the state of my input pin. The idea being that this cog can keep looping and return a state variable that can be fed into a method to generate a pwm signal that also involves a loop.

    Does this make sense?

    PUB main | stateCheck
     
    DIRA[pwmPin]~~ 'pin that outputs pwm signal
    DIRA[potPin]~  'detection pin connected to potentiometer
     
    repeat
      stateCheck := INA[potPin]
      IF stateCheck == 0
         pwmGen(pwmPin, 10) 'method to generate pwm output
      IF stateCheck == 1 
         pwmGen(pwmPin, 90)
    

    I am trying to build a command signal to control a motor. I'll ultimately program A/D conversion (Chpt 7 of the Prop Education Kit explains methods to do this without a external A/D converter) to give me more discrete steps, versus just two, but trying to start simple.
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-09-01 14:43
    HI Jeremy,

    I would code it his way:

    as the PWM-signal is something that should be created continously all the time with the same duty exept for changing the duty
    the creating of the PWM-signal should run it its own cog that does nothing else but creating the PWM-signal.

    The check of the potentiometer can then be done in the "main"-cog. If the state of the pot-pin changes the main-cog changes the variable
    controlling the duty. (or if you use one of the PWM-objects from the OBEX the main cog does call a SetDuty-method (method=subroutine)

    keep the questions coming
    best regards

    Stefan
  • JeremyJJeremyJ Posts: 30
    edited 2011-09-01 15:03
    Thanks Stefan,

    I understand your idea, and I think I'm thinking the same thing, but I'm still a little hazy on execution. Could you put up some code to give me an example or maybe point out a specific file in the OBEX library to review?

    Jeremy
  • AribaAriba Posts: 2,690
    edited 2011-09-01 18:36
    I find it much simpler to include a short PWM-methode into the same object than using a dedicated PWM object.
    In the follwing code this methode can generate 2 PWMs, but the second one is commented out.
    It also shows in a commented out line how you can query the pin and calculate the PWM duty within a single line.
    You need to add your pin numbers in the CON section.
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    VAR
      long cog
      long pwm1, pwm2, period
      long stack[20]
    
    PUB Main | pin
      period := clkfreq / 10_000                 ' 10kHz PWM frequency  
      cog := cognew(pwm_cog,@stack)
      
      repeat
        if ina[potPin]
          pwm1 := period * 90 / 100
        else
          pwm1 := period * 10 / 100
    '    pwm1 := (ina[potPin] * 80 + 10) * period / 100   'the same in one line
     
    PUB pwm_cog : time                           ' 2 x 10kHz PWMs in own cog
      'Configure counter modules.
      ctra[30..26] := %00100                     ' Set ctra to NCO mode
      ctra[5..0] := pwmPin                       ' Set ctra's APIN
    '  ctrb[30..26] := %00100                     ' Set ctrb to NCO mode
    '  ctrb[5..0] := pwmPin2                      ' Set ctrb's APIN
      frqa := 1                                  ' high pulse
    '  frqb := 1
      dira[pwmPin] := 1                          ' Set pins to output
    '  dira[pwmPin2] := 1
      time := cnt + period
      repeat
        waitcnt(time)
        phsa := -pwm1                            ' pwm values: 0..period
    '    phsb := -pwm2
        time += period                           ' next cnt time 
    

    Andy
  • kwinnkwinn Posts: 8,697
    edited 2011-09-01 19:15
    Perhaps I am a cog scrooge, but I would not use 2 cogs for this unless the required PWM frequency was high enough to require it, and even then I would use the counters if possible. There is usually time enough to read an input pin between changing the state of the PWM pin.
  • JeremyJJeremyJ Posts: 30
    edited 2011-09-02 00:55
    Andy....nice! Thank-you.

    Very helpful for learning how to use the counter modules....

    I'm going to try to modify this with a DAC...
  • AribaAriba Posts: 2,690
    edited 2011-09-02 07:11
    Ahh, so you don't need a PWM, but an Analog voltage.
    Then you can use the counter in DUTY mode, which needs no second cog:
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      potPin  = 0
      pwmPin  = 7
    
    PUB Main | percent
      percent := $FFFF / 100                     ' 1 percent
      ctra := %00110 << 26 + pwmPin              ' Set ctra to DUTY mode
      dira[pwmPin] := 1
      
      repeat
        if ina[potPin]
          frqa := (90 * percent)<<16             ' DUTY to 90%
        else
          frqa := (10 * percent)<<16             ' DUTY to 10%
        waitcnt(clkfreq>>3 + cnt)
    
    With an R-C filter at the pwmPin you get a clean analog voltage, the values of R and C depends on the needed speed, you can try 10k and 1uF if you have only slow changes.

    Andy
  • JeremyJJeremyJ Posts: 30
    edited 2011-09-02 13:49
    kwinn/Andy - I'm confused by the comment about 2 cogs. How are you using two cogs? I think I'm missing something....
  • AribaAriba Posts: 2,690
    edited 2011-09-02 16:47
    My first example uses two cogs. At begin of the Main methode the pwm_cog methode is started in a new cog (with cognew).
    So the pwm_cog runs independant parallel to the main loop and generates the PWM signal. The interface is the global variable pwm1 which is set in the main methode and read in the pwm_cog methode.

    Andy
Sign In or Register to comment.