Generate a non-blocking pulse with an Interrupt Service Routine
+ Reply to Thread
Results 1 to 16 of 16
  1. #1
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    204

    Default Generate a non-blocking pulse with an Interrupt Service Routine

    Saw a similar thread (http://www.picbasic.co.uk/forum/showthread.php?t=24119) and it was a very timely question. A project I'm working on has a somewhat similar pulse requirement and I have been asking myself how to accomplish it with out tying myself up with PAUSE commands in the ISR.

    In my case, I need to trigger a couple of 500uS pulses on different pins at different intervals.
    I'm using DT INTs and have two 8 bit timers free (TMR0 and TMR2 on a 12F683).

    Currently have a line in the ISR: "pulsout Drive, 50" for a 500uS pulse, but I'm concerned that it's an unnecessary delay.

    Daryl's Blinky example (http://dt.picbasic.co.uk/INT16/BlinkyLED) is close, but with the TOGGLE scheme, when I entered the ISR, it would toggle the pin on and load the ON time, then I would have to toggle it back off somehow. I'm trying to understand how you would do that. The only ways I can think of require that you stay in the ISR ( with the attendant delay) or maybe enter the ISR twice and change the timer preload for ON and OFF times.

    The pulse times are constant, it's just how often I fire them that changes.

    Any suggestions?
    thanks
    bo

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

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    One possible way:
    If 500us is enough granularity for the timing BETWEEN pulses then make your interrupt fire every 500us. In the ISR first clear all outputs - always. Then increment counter(s) for the various outputs and check if it's time to generate a pulse, if so set that output.

    At 2kHz interrupt rate with BYTE sized counter variables the time between pulses can be ~128ms and with WORD sized counter variables as much as 32 seconds.

  3. #3

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    How about, set a flag and set the timer for the delay between pulses. In the ISR, if flag set, set port hi, clear the flag and set the timer to the pulse duration or if flag clear, set port low, set the flag and set the timer to the delay between pulses.
    Last edited by towlerg; - 16th April 2019 at 12:05.
    George

  4. #4
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    204

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Thank you for the ideas. Ill give it a go and see what I come up with.
    bo

  5. #5
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    867

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    If the 8 bit timer suffices for your max pulse timing, you can consider setting the output, firing the timer and on the timer overflow interrupt, turn off the output. This way you can get enough granularity/variability for pulse width.

  6. #6
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    204

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Jerson,
    That's what I'd like to do. I have been trying to figure out how to do just that. I'm not sure how to end it with an interrupt. Time to study up on timer overflow and see how that will work...
    bo

  7. #7
    Join Date
    Feb 2013
    Posts
    542

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Having similar issue, almost...

    Need to generate 0.2-0.5 second pulse on hardware pin, but without stopping main code waiting for that pause. Is there a way to use timer for that? I don't need precise timing (this is just a beep), I'm not using any interrupts in my code either.

  8. #8
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,909

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    It can be done either by a timer and ISR or by a timer and without ISR.

    In the second case, a tight loop is necessary. And no PAUSE command allowed!

    The pulse is regularly generated, e.g. evey 5 seconds or 10 minutes?

    Ioannis

  9. #9
    Join Date
    Feb 2013
    Posts
    542

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Thanks!

    Pulse is generated depending on some conditions (record completed, end reached, button pressed, etc.). I know that I can get a way with standard workarounds, but I thought it might be easier with timers, as it seems, it does not. I need PAUSE and I use it a lot in code.

  10. #10
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,909

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    PAUSE does exactly that. Pauses program execution for the pause time.

    If that is OK with you then go ahead. But if you need to do something in that time, then you have to consider other ways.

    For example, when needed:

    1. make buzzer output high
    2. start timer
    3. check regularly in your main loop for timeout
    4. stop timer
    5. make buzzer output low

    Else you can do that in a ISR routine for a more pro approach.

    Ioannis

  11. #11
    Join Date
    Feb 2013
    Posts
    542

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Actually I can add another variable in main loop, like this:

    Code:
    Maincode:
    'condition
    IF BUTTON=1
    Then
    incr=1
    endif
    if incr>1 then high buzzer
    incr=incr+1
    if incr>200 then
    low buzzer
    incr=0
    endif
    
    
    'some main code here
    
    goto maincode
    Last edited by CuriousOne; - 27th July 2019 at 21:34.

  12. #12
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,909

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Your loop should take at least 50-100 ms for the buzzer to be enabled.

    Ioannis

  13. #13
    Join Date
    Apr 2014
    Location
    Northeast
    Posts
    306

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    CuriousOne, the original poster (boroko) was using a PIC12F683 with only basic Timers 0/1/2. I don't know if you have spare timers to use for such an interrupt, but the newer PIC12_6F1xxxx parts can have upwards of 7 timers.

    To use the ISR approach, calculate how long you want your buzzer making noise as applicable to your Timer2/4/6 and enter that in your PRx register. Configure all your other TMRxCON bits for appropriate Pre/Post scaling, etc, but leave the timer OFF. When you set your buzzer (turn it ON), also do the following:

    - Clear TMRxIF ; Interrupt Flag = 0
    - Clear TMRx ; Clear the counter register
    - Set TMRxIE ; Enable Interrupts
    - Set TMRxCON.ON ; Turn the Timer On in the TMRxCON register
    - Enable GIE ; INTCON.7 = 1 usually

    In your ISR:
    - Clear TMRxIF ; Clear Flag so it doesn't immediately Interrupt again
    - Clear TMRxIE ; Disable TMRx Interrupts
    - Turn buzzer Off ; That's why you're here
    - Disable TMRx ; TMRxCON.ON = 0, Stop Timer
    - [Disable GIE] ; If you have no other Interrupts, you can disable Global Interrupts
    - RETURN/RETFIE/@INT_RETURN ; Whichever is appropriate

    Hope this helps.
    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.

  14. #14
    Join Date
    Feb 2013
    Posts
    542

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    Thanks, that appears to be too hard for me. I'm using PIC16F886 btw

  15. #15
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,909

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    I do not agree. See this example where interrupt by Timer1 happens every 50ms and ISR increments time variable up to 20 and then toggles a LED.

    All this while main loop is doing silly things.

    Ioannis

    Code:
    #config
    Line1 = _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF
    Line2 = _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT
        __CONFIG _CONFIG1, Line1 & Line2
        __CONFIG _CONFIG2, _WRT_HALF & _BOR40V
    #endconfig
    
    
    OSCCON = %01110001 '8MHz Clock
    
    DEFINE OSC 8
    
    INCLUDE "DT_INTS-14.bas"
    INCLUDE "ReEnterPBP.bas"
    
    option_reg=%00000000
    
    wsave   var byte $70 system
    wsave1  var byte $a0 system
    wsave2  var byte $120 system
    wsave3  var byte $1a0 system
    
    T1CON = %00010001    ' TMR1 1:2 prescale, timer1 off
    time    var byte
    LED     var PORTB.0
    dummy   VAR byte
    
    '-------------   INTERRUPTS SETUP   ---------------------
    ASM
    INT_LIST  macro;    IntSource,  Label,      Type,  ResetFlag?
        INT_Handler     TMR1_INT,   _timer,     PBP,    yes
        endm
        INT_CREATE            ; Creates the interrupt processor
    ENDASM
    
    @   INT_ENABLE  TMR1_INT     ; Enable Timer 1 Interrupts  
    
    '-------------   INTERRUPTS SETUP   ---------------------
    
    
    '***********************************************************************
    '*
    '*             Interrupt on Timer 1
    '*
    '***********************************************************************
    timer:                    'Timer 1 tick every 1us x 50000 = 50ms
        t1con.0=0             'time variable inc every 50ms
        if time<20 then       'x 20 = 1sec
            time=time+1
        else
            time=0
            toggle led  'toggle a LED every second
        endif
        
        tmr1l=$70   'reload timer 1  with 16474
        tmr1h=$45   '65536-49062. 49602 was found by trial and error to be close to 50ms
    t1con.0=1   'start timer 1
    
    @ INT_RETURN    
    
    
    main:
    while 1
    dummy=dummy+1         'keep MCU busy
    wend
    
    END

  16. #16
    Join Date
    Apr 2011
    Location
    Portland, Oregon
    Posts
    221

    Default Re: Generate a non-blocking pulse with an Interrupt Service Routine

    I agree with Ioannis, generally, on the use of Pause, but using a loop of short pauses can be a bit of a work around. Rather than pausing for 1 full second, pausing for 1/10 of a second (in a For/ Next loop, for example) allows interrupts to fire more regularly. Be aware that the Loop itself takes time, so you'll either need to shorten your pause or reduce your loop count to maintain timing and, of course any interrupt that fires during the loop will add to the duration of the pause. Still, its a handy to use sometimes.

Similar Threads

  1. Programmatically generate a (false) interrupt?
    By circuitpro in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 28th January 2011, 23:48
  2. Replies: 23
    Last Post: - 23rd September 2008, 18:20
  3. DT interrupt/pulse generator
    By Adrian in forum mel PIC BASIC Pro
    Replies: 14
    Last Post: - 20th August 2008, 21:13
  4. TMR1 100Hz Exactly Interrupt Routine
    By manumenzella in forum mel PIC BASIC Pro
    Replies: 15
    Last Post: - 15th February 2007, 05:51
  5. Blocking problem with 18F252
    By muskut in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 12th October 2005, 21:53

Members who have read this thread : 20

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