Trapping a flag/state change (rapidly)


Closed Thread
Results 1 to 10 of 10
  1. #1
    Join Date
    Mar 2009
    Posts
    653

    Default Trapping a flag/state change (rapidly)

    So, I'm learning about HPWM...and for this project just using a few LEDs to set some simple patterns running.

    I'm using DT's interrupts to trap a button being pressed, in the interrupt routine I increment a 'pattern' variable for each button press. This bit all works fine, so no problems there.

    So the interrupt returns to the main program loop ....but the variable (flag) change is not trapped until the program gets to the point where it tests the variable. Once it tests the variable, it jumps to a new loop (to change the LEDS sequence).

    Ok, here's the problem....

    For the sake of example, lets say Pattern 1 is a chaser (leds lighting up/extinguishing in sequence) & pattern is all LEDS on. What's happening here is that Pattern1 is running (leds sequencing),then the button gets pressed....but after the button is realeased it takes a finite time for the variable change to be picked up upon (trapped) in the main loop ...so the LEDs still continue to 'sequence' until the pattern change is trapped in the main loop - it then jumps to the new Pattern routine (all LEDS on) just fine. It's this lag between the button being pressed & the main loop picking up on it, that's causing me troubles...it's not a huge lag, but it is discernible & I'm sure there a slicker way

    I'm conscious that I'm still very much in the n00b camp & there must be a better way of having a program act in a zippy way to variable/flag changes.
    Last edited by HankMcSpank; - 29th April 2011 at 09:54.

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Hi Hank,
    I'm not sure I can give you a general way of doing it.

    One (obvious but not elegant) way is to simply check the flag several times as you go thru the main loop.

    Another way, assuming you're using some kind of counter/index variable to "step" thru the individual states of each pattern, is to also reset that counter in the ISR thus forcing the "cycle" to start over. If the first thing you do in the "cycle" is to check the "pattern variable" then you'll get an imidiate switch of patterns.

    I'm sure there are several other ways of handling it.

    /Henrik.

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Quote Originally Posted by HenrikOlsson View Post
    Hi Hank,
    I'm not sure I can give you a general way of doing it.

    One (obvious but not elegant) way is to simply check the flag several times as you go thru the main loop.
    Hi Henrik,

    That's the way I'm doing it now, but it eats up program space!

    Previously, (to save repetition) I made the mistake of using a GOSUB to check the 'pattern' variable regularly throught all my program segments & if it had changed, to point it to a different part of the program ....whoah schoolboy error, my pic started reseting (becuase I wasn't returning cleanly out of the gosub).

    I'm not sure I'm understanding your other recommendation.

    For anyone not sure what my issue is, here's a high level flow of what's going on

    Code:
    pattern1:
    HIGH LED1
    PAUSE 100
    LOW LED1
    PAUSE 100
    HIGH LED2
    PAUSE 100
    LOW LED2
    PAUSE 100
     
    rinse, repeat....
     
    if pattern = 2 then goto pattern2
    goto pattern1
     
    pattern2:
    flash some other LED pattern
    if pattern = 1 then goto pattern1
    goto pattern2
     
    ISR:
    If a Switch is pressed in increment pattern variable

    you can clearly see that in pattern1, unless I check the variable called 'pattern' after every LED state change, that -especially with a few LEDS in play - it could be a while before the pattern variable change is picked up.
    Last edited by HankMcSpank; - 29th April 2011 at 12:12.

  4. #4
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Hank, I think the hangup for you is how you generate the pattern.

    If you use some counters to "decide" when and what led to light up, instead of hanging your program for .4 seconds, you will see the flag check much faster.

    Maybe have your interrupt be a time base, like .1mS or something. Then while in the ISR, check for button press and inc your "led counters"

    I know this is vague, but all I have time for right now.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Hi,
    There are many different ways of doing it and the "right" one depends on what you'll actually intend to do with it - in the end.... It's not uncommon to post something that does what's currently 'at hand' only to get something like OK, that works, now I want it to do this and that which, if it had been known from the start might have warranted another solution.

    Anyway, here's an example of what I was trying to explain earlier:
    Code:
    Pattern VAR BYTE
    StepInPattern VAR BYTE
     
    Main:
    Select Case Pattern
        Case 0 : Goto Pattern1
        Case 1 : Goto Pattern2
    Goto Main
     
    ' ------ Subroutine for pattern 1 ------
    Pattern1:
    Select Case StepInPattern
        Case 0
            High LED1
            StepInPattern = 1   'Next time, next step
        Case 1
            LOW LED2
            StepInPattern = 2
     
        Case 2
            HIGH LED2
            StepInPattern = 3
     
        Case 3
            LOW LED 2
            StepInPattern = 0   'Next time, start over
    END SELECT
    Pause 100
    Goto Main
     
    ' ------ Subroutine for pattern 2 ------    
    Pattern2:
    Select Case StepInPattern
        Case 0
            HIGH LED1
            LOW LED2
            StepInPattern = 1   'Next time, next step
     
        Case 1
            LOW LED1
            HIGH LED2
            StepInPattern = 0   'Next time, start over
    END SELECT
    Pause 50
    Goto Main
    Basically it's two statemachines "driven" by the Pattern and StepInPattern variables. In your interrupt routine you can simply reset the StepInPattern variable and set Pattern to what ever pattern you want and it will start that pattern from the beginning. There will be a delay up to the longest Pause time that you've got in there but it won't have to complete the full cycle.

    This is not very code effective but it illustrates what I meant.

    On a project of mine I have single LED indicating various states of the device. I have a set of patterns defined something like this:
    Code:
    Status_LED_Pattern_OK  CON %0000000011111111
    Status_LED_Pattern_Fault CON %1010101010101010
    Status_LED_Pattern_Wait CON %1111000011110000
    I can then select which pattern I want by doing:
    Code:
    Pattern = Status_LED_Pattern_OK
    And in my main interrupt I have counter (PatternPointer) incrementing every 1/10th of a second which "points into" the pattern variable and sets the output driving the LED to the state of that bit, like:
    Code:
    PortB.0 = Pattern.0[PatternPointer]
    Obviosuly the interrupt code needs to make sure that "pointer" only counts from 0-15 and then starts over or strange things WILL happen.

    /Henrik.

    Disclaimer: The above is from the top of my head to illustrate the tecnique, it may or may not work exactly as written.

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Quote Originally Posted by cncmachineguy View Post
    Hank, I think the hangup for you is how you generate the pattern.

    If you use some counters to "decide" when and what led to light up, instead of hanging your program for .4 seconds, you will see the flag check much faster.

    Maybe have your interrupt be a time base, like .1mS or something. Then while in the ISR, check for button press and inc your "led counters"

    I know this is vague, but all I have time for right now.
    Hi Bert,

    You're bang on ...using pauses is not optimum, as obviously while it's erhm pausing it ain't doing anything else.

    the problem here is I'm already using two timers in my same testbed program here (one for a special event trigger & another to control HPWM) ...ok, so I've 3 timers left (16f1824 has 5 timers) , but I need a whole heap of different pauses (& some quite longish...I've always had an epic fail when I've tried to use timers for long pauses!) ....now I realise I could just reset the timer preload value accordingly each time I need a different pause, but ....aaargh ....brainache. I guess that's what it comes down to... a solution that avoids brainache ...it's a fair cop, I'll get me coat!


    Henrik,

    Many thanks for the comprehensive examples...I shall study them later tonight.

    Cheers,
    Hank

  7. #7
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Henrik, I LOVE THAT!!!!!

    Hank, I think I like Henrik's idea better, but may or may not work for your app. Are any of the current 2 timers you have ISR's or are they just being used? Cuz if either of them have ISR, you can use that for the timebase. Increment counters there and check for button.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  8. #8
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    If you use TMR2 as the PWM timebase you can use its postscaler as "divider" between the PWM frequency and interrupt frequency. If you have, say, 16kHz PWM frequency and set the postscaler to 1:16 you'll get an interrupt rate of 1kHz which you can use as a timebase if nothing else you already have running is suitable for that.

    Again, there are many ways.....

    /Henrik.

  9. #9
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Quote Originally Posted by HankMcSpank View Post
    ...You're bang on ...using pauses is not optimum, as obviously while it's erhm pausing it ain't doing anything else.
    If you want to use a PIC (or any MCU for that matter) efficiently, one of the most important things to learn to do - after you have accomplished your first blinky program - is to wean yourself off using pause (blocking) type commands completely.
    Why pay for overpriced toys when you can have
    professional grade tools for FREE!!!

  10. #10
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default Re: Trapping a flag/state change (rapidly)

    Quote Originally Posted by HankMcSpank View Post
    ....but I need a whole heap of different pauses (& some quite longish...I've always had an epic fail when I've tried to use timers for long pauses!) ....now I realise I could just reset the timer preload value accordingly each time I need a different pause, but ....aaargh ....brainache. I guess that's what it comes down to... a solution that avoids brainache ...
    Here is pseudocode that blinks 2 LEDs at different speeds (1Hz and 2Hz) and does not use any pause (blocking delay) type commands. You can easily expand it to any number of LEDs (or tasks) with no performance degradation. It uses a single hardware timer to provide a system tick (also known as a heartbeat). It can be used as a template to create simple multitasking applications.
    Code:
    sub timer1 interrupt
      inc(cyctick1)
      inc(cyctick2)
    
      if cyctick1 > 500      ' 500mS delay, 1st. counter
        cyctick1 = 0         ' reset counter
        cycflag1 = 1         ' set flag        
      endif
      if cyctick2 > 250      ' 250mS delay, 2nd. counter
        cyctick2 = 0         ' reset counter
        cycflag2 = 1         ' set flag 
      endif
    end sub  
    
    sub usrfunction1
      toggle LED0
    end sub
    
    sub usrfunction2
      toggle LED1
    end sub
    
    main:
      cyctick1=0:cyctick2=0 ' Initialize variables
      ccyflag1=0:cycflag2=0 '         "
      
      timer1 = 1000         ' set up timer1 to interrupt every 1mS
    
      while true
        if cycflag1=1 then  ' check if 500mS has expired
          cycflag1 = 0      ' reset flag 1
          do userfunction1
        endif
        if cycflag2=1 then  ' check if 250mS has expired
          cycflag2 = 0      ' reset flag 2
          do userfunction2
        endif
      wend
    Last edited by rmteo; - 4th May 2011 at 01:20.
    Why pay for overpriced toys when you can have
    professional grade tools for FREE!!!

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts