Exit interrupt

General discussion on mikroBasic PRO for PIC.
Post Reply
Author
Message
a1exei1987
Posts: 8
Joined: 19 Aug 2014 09:56

Exit interrupt

#1 Post by a1exei1987 » 08 Dec 2017 12:17

Hi all! :)
Please help me to get out of interrupts when you press the button invertion PORTB, 1. Here is my code:

Code: Select all

program TMR0
Dim i as byte

sub procedure start
    nop
end sub

sub procedure interrupt
    if Button(PORTB, 0, 5, 1) then
       SetBit(PORTB, 7)
       delay_ms(5000)
       ClearBit(PORTB, 7)
       for i = 0 to 4
              Sound_Play(880, 1000)
              delay_ms(1000)
       next i
    else if Button(PORTB, 1, 5, 1) then
         goto start
    end if

    ClearBit(INTCON, 2)
    INTCON = 0xA0
end sub

main:
     TRISB = 0x01
     PORTB = 0x00
     INTCON = 0xA0
     OPTION_REG = %11000101
     TMR0 = 0x00
     Sound_Init(PORTE, 1)
     nop
     nop
     
     start:
           goto start
end.
Want to make a program that 1 in every 5 MS (approx) polls the state of buttons invertion PORTB,0 and invertion PORTB,1.
If pressed invertion PORTB,0, enables invertion PORTB,7 for 5 seconds. If at this time was pressed invertion PORTB,1, the time delay stops and again are state of buttons

The compiler gives lots of errors, I can not understand, although previously programmed in VB6/VB.NET :(

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#2 Post by dangerous » 08 Dec 2017 14:35

Hi, You don't tell us the PIC you use or the speed, but it has to be a 16F or 12F to have option reg for Prescaler I think.

You have assigned PS to tmr0 at divide by 64 and Tmr0 to 00 start. At 255 Tmr0 rolls over and sets the interrupt off as you have set INT0IE to true.

Tmr0 will time out in about 16.4mS with a 4MHz clock (1us x 64 for each tick, then 256 ticks). This is clock speed dependent.

Your program sits in the interrupt routine for about 5 seconds which will cause issues since as soon as you leave the routine it will re-interrupt immediately and during the delay will not check the state of the other button as GIE is disabled during interrupt and no interrupts will occur until the ISR is exited.

Dependent on the chip, the option exists to check for change on portb and generate the interrupt from there. That may be better than using the timer. 5mS is very short for a button push. That would normally be about 30mS to de-bounce

Something like this for the timer use maybe:

Code: Select all

dim flags0, flags1 as byte


sub procedure interrupt  'ISR
    
    If INT0IF_Bit then
        if Button(PORTB, 0, 5, 1) then  ' check the button
            flags0 = true      ' set every TMR0 interrupt
            flags1 = false
        end if
       if Button(PORTB, 1, 5, 1) then  ' check the button
            flags0 = false   
            flags1 = true
        end if
        TMR0 = 0x00  'get as much out of the timer as  you can!
    end if   
   INTCON = 0xA0  'clears INT0IF and  any other rogue interrupts, leaves INT0IE & GIEset
end sub

    'part of main

     if flags0 then     
         flags0 = false   'just loops unless we clear it here
          SetBit(PORTB, 7)
          delay_ms(5000)
          ClearBit(PORTB, 7)
          for i = 0 to 4
              Sound_Play(880, 1000)
              delay_ms(1000)
          next i   
    end if 
    if flags1 then      ' allows other button to stop routine
       flags1 = false
       goto start()  
    end if 

To check the state of Button(PORTB, 1, 5, 1) put both buttons in the interrupt routine and use two flags. Respond if flag0 is set for ON or if flag2 is set for OFF, but get out of the interrupt as soon as possible, to allow the check to take place every TMR0 interrupt.

If you need to use other interrupts beware that any interrupts that occur will set their flags even if the interrupt enable is disabled. I spent quite a while chasing my tail when Tmr0 int kept happening even though INT0IE was clear, so test the specific flag and the state of the enable if you are using other interrupts as well

a1exei1987
Posts: 8
Joined: 19 Aug 2014 09:56

Re: Exit interrupt

#3 Post by a1exei1987 » 11 Dec 2017 11:58

Yes, sorry, I forgot to say that I use part no PIC16F877 on EasyPIC7 debugging Board. The frequency of the quartz resonator of 4 MHz. Further I want to rewrite the program for PIC12F629/675

a1exei1987
Posts: 8
Joined: 19 Aug 2014 09:56

Re: Exit interrupt

#4 Post by a1exei1987 » 11 Dec 2017 12:35

dangerous wrote: Tmr0 will time out in about 16.4mS with a 4MHz clock (1us x 64 for each tick, then 256 ticks). This is clock speed dependent.
When the divider 1:64 the following: Fosc = 4 MHz, T = 4/Fosc = 4/4MHz = 1 µs.
Ttmr0 = 256*1 MS = 256 µs.
T"tmr0 = 64*256 µs = 16384 µs => F"tmr0 = 1/T"tmr0 = 1/16384 µs = 61 Hz
Here is a screenshot from the oscilloscope :)
dangerous wrote:Your program sits in the interrupt routine for about 5 seconds which will cause issues since as soon as you leave the routine it will re-interrupt immediately and during the delay will not check the state of the other button as GIE is disabled during interrupt and no interrupts will occur until the ISR is exited.
In the interrupt routine are a little more than 15 ms, according to the calculations, and the waveform

P.S.: thanks for the replies and help! :) I thought no one in mikroBasic already uses..
Attachments
1717268607.jpg
1717268607.jpg (182.79 KiB) Viewed 3719 times

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#5 Post by dangerous » 12 Dec 2017 10:22

Want to make a program that 1 in every 5 MS (approx) polls the state of buttons invertion PORTB,0 and invertion PORTB,1.
You are getting about 16mS with a 4 MHz clock as you see on the scope & your calculations.

Code: Select all

sub procedure interrupt
    if Button(PORTB, 0, 5, 1) then
       SetBit(PORTB, 7)
      '******delay_ms(5000)******
       ClearBit(PORTB, 7)
       for i = 0 to 4
              Sound_Play(880, 1000)
              delay_ms(1000)
       next i
    else if Button(PORTB, 1, 5, 1) then
         goto start
    end if

    ClearBit(INTCON, 2)
    INTCON = 0xA0
end sub
Starred line above will keep the program inside the interrupt service routine for about 5 seconds if button 0 is activated, as GIE is disabled by default when the interrupt occurs and remains disabled until the PIC sees a RETFIE instruction. It will suspend any TMR0 interrupts until the ISR exits.

That is why I suggested that you check the button states in the ISR but do the Start and Stop play functions externally. That way the buttons are checked every TMR0 period.

An alternative is to use the interrupt on change of portb to see which button was pressed and then call the start and stop routines from the interrupt.

Do you have to use the interrupt? Just poll the state of the buttons in a while true ........ wend loop, and act on the state of them.

Lots of possibilities to achieve the same result, it depends if the rest of the program needs other interrupts and what has most importance.

For 12F629 you can use the internal 4MHz clock - it is accurate enough for this.

PORTB = GPIO and the ports are 0 thru 5. All are available if you use the internal reset (MCLR) and internal clock, but remember that GPIO.3 is input only.

Read the datasheet to find out how to use the ports, internal clock and reset. It is fairly straight-forward compared with, say, an 18F24K22 which has lots of peripheral functions.

Good luck. Let us know how you get on with this project.
Last edited by dangerous on 12 Dec 2017 12:14, edited 1 time in total.

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#6 Post by dangerous » 12 Dec 2017 12:12

Just to clarify further, I suspect that the pulses you see on the scope will vanish once button 0 is pressed until the 5 sec delay (delay_mS(5000) ) has finished and the ISR is exited.
This means that button 1 only gets checked outside the 5 sec delay.

I am not sure if the call

Code: Select all

 else if Button(PORTB, 1, 5, 1) then
         goto start
    end if
would work anyway as it is a jump out of the ISR with no RETFIE command to the PIC. This is the assembler code that is produced by the compiler, and that is what re-starts the interrupt by setting the GIE bit, which is disabled on entry to the interrupt call.

Until that is reset, all interrupts are ignored (although the INT0IF bit will still be set as TMR0 is still running and rolling over) but it will not initiate a new the call to the ISR until the bit GIE is re-enabled i.e. after the ISR has exited so if you jump out of the ISR, it will never re-enable GIE bit and it will hang in the start procedure for ever or wander off into never-never land doing NOPS.

a1exei1987
Posts: 8
Joined: 19 Aug 2014 09:56

Re: Exit interrupt

#7 Post by a1exei1987 » 12 Dec 2017 13:33

Thanks again! :) I do not understand how to get out of the time delay delay_ms (5000) when you click invertion PORTB,1 :(
Rewrote the code, but until I understand how to use the timer 0. It is easy to track the state of the buttons..

Code: Select all

program TMR0_WHILE
Dim flags_RB0, flags_RB1, i as byte

sub procedure interrupt
    if SetBit(INTCON, 2) then
       if Button(PORTB, 0, 5, 1) then
          flags_RB0 = true
          flags_RB1 = false
       end if
       if Button(PORTB, 1, 5, 1) then
          flags_RB0 = false
          flags_RB1 = true
       end if
    end if
    INTCON = 0xA0
    TMR0 = 0x00
end sub

main:
     TRISB = 0x03
     PORTB = 0x00
     INTCON = 0xA0
     OPTION_REG = %11000101
     flags_RB0 = false
     flags_RB1 = false
     TMR0 = 0x00
     nop
     nop
     
     start:
          while flags_RB0
             SetBit(PORTB, 7)
             delay_ms(5000)
             ClearBit(PORTB, 7)
             flags_RB0 = false
             INTCON = 0xA0
             TMR0 = 0x00
          wend
          
          while flags_RB1
                ClearBit(PORTB, 7)
                flags_RB1 = false
                INTCON = 0xA0
                TMR0 = 0x00
          wend
          goto start
end.

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#8 Post by dangerous » 12 Dec 2017 14:28

Hi,

I think that the While true wend loop is in the wrong place:

Code: Select all

 
         while flags_RB0
             SetBit(PORTB, 7)
             delay_ms(5000)
             ClearBit(PORTB, 7)
             flags_RB0 = false
             INTCON = 0xA0
             TMR0 = 0x00
          wend

        
          while flags_RB1
                ClearBit(PORTB, 7)
                flags_RB1 = false
                INTCON = 0xA0
                TMR0 = 0x00
          wend
Try to simplify it as much as possible

Code: Select all

  
sub procedure interrupt
  ' if you use the Microchip Bit names it saves confusion, will work with less confusion and means the same thing:

    If TMR0IF_bit then                                'implied "= True" It will only do this branch if TMR0IF is set by call to interrupt
       if Button(PORTB, 0, 5, 1) then
          flags_RB0 = true
          flags_RB1 = false
       end if
       if Button(PORTB, 1, 5, 1) then
          flags_RB0 = false
          flags_RB1 = true
       end if
    end if
    INTCON = 0xA0  'clears any  unintended interrupts
    TMR0 = 0x00  'resets timer0 to compensate or lost counts during interrupt
end sub

' by putting the called routines in sub procedures it becomes easier to follow and to debug with the ICD
Sub procedure start_btn()
             SetBit(PORTB, 7)
             delay_ms(5000)
             ClearBit(PORTB, 7)
             'This will light portB,7 for 5 sec
end sub
Sub procedure stop_btn()
          ClearBit(PORTB, 7)
          'this clears portb,7 unconditionally even inside 5 sec delay
end sub

'part of main after startup

 while true
    if flags_RB0 then
           flags_RB0 = 0    ' = clear (flags_RB0) 
           start_btn()         
    end if
    if flags_RB1 then
         flags_RB1 = 0
         stop_btn()
    end if
    NOP  'This is useful as a break point if you are using the IC debugger 
   'The program will loop forever unless the interrupt occurs. It will then react according to the button state on return from interrupt, but the ISR has to reset the timer to keep accurate  running.
   'It will always loose about 4 system ticks as the interrupt takes a finite time to execute, but a few uS is not critical here, but can be or some applications.
  'The trick is to reload the timer with a higher value to compensate for lost time in the ISR
  wend

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#9 Post by dangerous » 13 Dec 2017 10:45

Still wrong, now I am in front of the EasyPic7!

You need to be able to break out of the 5Sec delay, so the answer is probably to do the delay differently to allow that. You still need to start it outside the ISR otherwise as stated before the GIE bit never gets set.

So long as you can accept a short delay in exiting the routine, this should do the trick.
Use a shorter delay, say 20mS and count the loops, check in between loops for the status of Button 1 The program below starts the portb.7 lit routine and exits if button 1 is pressed. The delay is the loop time (delay_mS(20)) for the loop to exit as the RB1 flag is only checked every 20mS.

I did not have a 16F877 to hand but I tried it with a 18F45K22 set to 4MHz and it does do what I think it should. I modified it back to 16F877 code below:

Code: Select all

 

program MyProject
dim flags_RB0,flags_RB1,i as byte


 sub procedure interrupt
  ' if you use the Microchip Bit names it saves confusion, will work with less confusion and means the same thing:

    If TMR0IF_bit then                                'implied "= True" It will only do this branch if TMR0IF is set by call to interrupt
       if Button(PORTB, 0, 5, 1) then
          flags_RB0 = true
          flags_RB1 = false
       end if
       if Button(PORTB, 1, 5, 1) then
          flags_RB0 = false
          flags_RB1 = true
       end if
    end if
    INTCON = 0xA0  'clears any  unintended interrupts
    'TMR0L = 0x00   '18F45K22
    TMR0 = 0x00  '16F877, resets timer0 to compensate or lost counts during interrupt
end sub

' by putting the called routines in sub procedures it becomes easier to follow and to debug with the ICD
Sub procedure start_btn()
          SetBit(PORTB, 7)
            flags_RB0 = 0                  'Clear flag 
            for i = 1 to 250                    ' gives about 5 sec, try changing for shorter delays
                delay_ms(20)                 ' as above but this time also is the worst case response to the RB_1 flag time
               if flags_RB1 then
                   flags_RB1 = false
                  goto leave_loop          'ends loop within 20mS of button 1 press
           end if
      next i
leave_loop:
           ClearBit(PORTB, 7)  'always clears portb.7 at end of time-out or on end button pressed
end sub


main:
      'OSCCON = 0x50                '4MHz int clock with 18F45K22
     ' ANSELB = 0                      'commented lines are not relevant to 16F877 and will be ignored
     ' ANSELA = 0
     ' PLLEN_Bit = false
     TRISB = 0x03
     PORTB = 0x00
     INTCON = 0xA0
     OPTION_REG = %11000101  '16F877
    'T0CON = 0xC5   '18F45K22
     flags_RB0 = false
     flags_RB1 = false
    ' TMR0L = 0x00     '18F45K22
     TMR0 = 0x00       '16F877
     nop
     nop
 while true
    if flags_RB0 then
           start_btn()           'starts delay routine
    end if

    NOP  'This is useful as a break point if you are using the IC debugger
   'The program will loop forever unless the interrupt occurs. It will then react according to the button state on return from interrupt, but the ISR has to reset the timer to keep accurate  running.
   'It will always loose about 4 system ticks as the interrupt takes a finite time to execute, but a few uS is not critical here, but can be or some applications.
  'The trick is to reload the timer with a higher value to compensate for lost time in the ISR
  wend
end.
Paste the whole code and try it. It seems fine with the 18F chip.

a1exei1987
Posts: 8
Joined: 19 Aug 2014 09:56

Re: Exit interrupt

#10 Post by a1exei1987 » 15 Jan 2018 13:55

dangerous, I get such a program

Code: Select all

program LED_UVH
Dim i, j, k as Integer

Sub procedure Start_UVH(dim ms as word)
    SetBit(PORTB, 7)
    for i = 1 to 28500
        Vdelay_ms(ms)
        if Button(PORTB, 2, 20, 1) then
           ClearBit(PORTB, 7)
           goto EOP
        end if
    next i
    
    ClearBit(PORTB, 7)
    for j = 1 to 5
        Sound_play(880, 1000)
        delay_ms(1000)
    next j
    exit
    
    EOP:
        for k = 1 to 5
            Sound_play(880, 100)
            delay_ms(100)
        next k
        exit
end sub

main:
     TRISB = %00000101
     TRISE = %00000000
     PORTB = %00000000
     PORTE = %00000000
     
     Sound_Init(PORTE, 1)

     start:
           While TRUE
                 if Button(PORTB, 0, 20, 1) then
                    Start_UVH(10)
                 end if
           wend
end.
Rewrote under the PIC12F629 microcontroller (originally planned to use the scheme) and get the following program:

Code: Select all

program LED_UVH
Dim i as word
Dim j, k as byte

Sub procedure Start_UVH(dim ms as word)
    SetBit(GPIO, 1)
    for i = 1 to 28500
        Vdelay_ms(ms)
        if Button(GPIO, 2, 20, 1) then
           ClearBit(GPIO, 1)
           goto EOP
        end if
    next i

    ClearBit(GPIO, 1)
    for j = 1 to 5
        Sound_play(880, 1000)
        delay_ms(1000)
    next j
    exit

    EOP:
        for k = 1 to 5
            Sound_play(880, 100)
            delay_ms(100)
        next k
        exit
end sub

main:
     OPTION_REG = %00000000
     INTCON = %00000000
     TRISIO = %00000101
     GPIO = %00000000
     Sound_Init(GPIO, 4)

     start:
           While TRUE
                 if Button(GPIO, 0, 20, 0) then
                    Start_UVH(10)
                 end if
           wend
end.
Library use is Sound, the microcontroller ends ROM :) Probably will have to write code in assembler :)

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#11 Post by dangerous » 15 Jan 2018 17:47

Hi,

You need to set CMCON to 0x07 for digital in startup routine.

At default startup only GPIO.2 is digital, GPIO.0 & 1 are analogue. The 12F629 datasheet Comparator module has the info. You may get unintended results otherwise.

If you use 12F675 ANSEL has to be set to 0 as well - See A-D module in same datasheet.

Does the program work at all?

Did you sort the interrupt out on your original post?

dangerous
Posts: 748
Joined: 08 Mar 2005 16:06
Location: Nottinghamshire, UK

Re: Exit interrupt

#12 Post by dangerous » 16 Jan 2018 11:15

Hi I see your problem, there is not enough ROM space when compiled. It may not fit in assembler either. The 12F675/629 has only 1K available.

Compiling for the 12F1572 gives 1056 program words used, that could be the best answer.

More ROM (2KB). You have to change GPIO to PORTA and TRISIO to TRISA.

Set ANSELA = 0 to make inputs digital.

Same pins, same formats, similar working, but read the datasheet especially on A-D converter, oscillator set up and I/O port operation.

To write to outputs use LATA = 0xYY, to read use inport = portA etc.

If you need even more ROM, look on the microchip website, parametric search for 8 bit, 8 pin devices: http://www.microchip.com/ParamChartSear ... nchID=1012

For 7KB memory there is the 12F1840 for virtually the same price as the 12F629. Read the datasheet. There are subtle differences between very similar devices, especially on disabling the A-D and comparator modes to have digital inputs and how to set the oscillator mode & frequency.

usefrosted
Posts: 1
Joined: 22 Jan 2024 02:18

Re: Exit interrupt

#13 Post by usefrosted » 22 Jan 2024 02:25

This way works for me. Many thanks.coreball

Post Reply

Return to “mikroBasic PRO for PIC General”