PDA

View Full Version : Multiple Interrupts using TMR0 and Interrupt On Change (IOCB) simultaneously



flotulopex
- 1st August 2014, 00:48
Hi there,

Here's one more thread about multiple interrupts use (...) but after hours of reading, I still can't find THE information I'm looking for or in other words, the info I can understand.

I know Darrel made everyone's life much easier with his routine, but I would like to understand how multiple interrupts are to be handled "in a perfect world".

I have made a program (see code hereunder) where I have involved two interrupts: TMR0 and an IOCB (Interrupt on Change) on PORTB.6 .

As the TMR0's interrupt seems to work perfectly (= it toggles every second as it has to), the IOCB will work too but in a fuzzy way. In fact, the IOCB will sometimes light the IOCB_LED shortly, sometimes this LED will remain ON, sometimes it won't even light.

Maybe I need to trigger the rising or falling edge of the push-button's action and also if and how to debounce it especially in an interrupt handler.

Does my interrupt handling routine make sense? How can it be done a cleaner, simpler way?

Any info?


' PIC 16F690
@ __config _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF &_PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT

'-------------------------------------------------------------------------------
' Registers 76543210
OPTION_REG = %00000101 'PORT A&B Pull-Ups / TMR0 prescaler
OSCCON = %01100000 'Internal RC set to 4Mhz - not to be used with XTal
INTCON = %00101000 'INTerrupts CONtrol
ANSEL = %00000000 'Disable analog inputs Channels 0 to 7
ANSELH = %00000000 'Disable analog inputs Channels 8 to 11
ADCON0 = %00000000 'A/D Module is OFF
CM1CON0 = %00000000 'Comparator1 Module is OFF
CM2CON0 = %00000000 'Comparator2 Module is OFF
WPUA = %00000000 'Weak pull-ups
IOCA = %00000000 'interrupt on change
TRISA = %00000000 'Set Input/Output (0 to 5)
PORTA = %00000000 'Ports High/Low (0 to 5)
WPUB = %01000000 'Weak pull-ups
PORTB = %00000000 'Ports High/Low (4 to 7)
IOCB = %01000000 'interrupt on change
TRISB = %01000000 'Set Input/Output (4 to 7)
TRISC = %00000000 'Set Input/Output (0 to 7)
PORTC = %00000000 'Ports High/Low (0 to 7)

DEFINE OSC 4

'-------------------------------------------------------------------------------
' Variables
Ticks VAR BYTE
Ticks = 0
Old_bits VAR BYTE
New_bits VAR BYTE
P_Button VAR PORTB.6
TMR0_LED VAR PORTA.4 'indicates a TMR0 INTerrupt
IOCB_LED VAR PORTA.5 'indicates a IOCB INTerrupt


'————————————————————————————————————————————————— ——————————————————————————————
' Start program
'————————————————————————————————————————————————— ——————————————————————————————

ON INTERRUPT GOTO ISR

MAIN:
Old_bits = PORTB
' do some things here
GOTO MAIN


'-------------------------------------------------------------------------------
' Interrupt routine
'-------------------------------------------------------------------------------
ISR:
DISABLE

' TMR0
IF INTCON.2 = 1 THEN
INTCON.2 = 0
TICK_INT:
Ticks = Ticks + 1
IF Ticks < 61 THEN DO_NOTHING
Ticks = 0
TOGGLE TMR0_LED
DO_NOTHING:
ENDIF

' IOCB
IF INTCON.0 = 1 THEN
INTCON.0 = 0
New_bits = PORTB
IF (New_bits.6 <> Old_bits.6) THEN 'PORTB.6 has changed
TOGGLE IOCB_LED
ENDIF
Old_bits = New_bits
ENDIF

RESUME
ENABLE
END

richard
- 1st August 2014, 02:00
with a quick look I can see these issues


from the data sheet


For enabled interrupt-on-change pins, the present
value is compared with the old value latched on the last
read of PORTB to determine which bits have changed
or mismatch the old value. The ‘mismatch’ outputs are
OR’d together to set the PORTB Change Interrupt flag
bit (RABIF) in the INTCON register (Register 2-3).
This interrupt can wake the device from Sleep. The user,
in the Interrupt Service Routine, clears the interrupt by:
a) Any read or write of PORTB. This will end the
mismatch condition.
b) Clear the flag bit RABIF.
A mismatch condition will continue to set flag bit RABIF.
Reading or writing PORTB will end the mismatch
condition and allow flag bit RABIF to be cleared. The latch
holding the last read value is not affected by a MCLR nor
Brown-out Reset. After these Resets, the RABIF flag will
continue to be set if a mismatch is present.

since you are continually reading portb in your main loop the mismatched condition is probably being masked.

and secondly according to the manual




DISABLE should go here
ISR:
DISABLE not here
' TMR0
IF INTCON.2 = 1 THEN
INTCON.2 = 0
TICK_INT:
Ticks = Ticks + 1
IF Ticks < 61 THEN DO_NOTHING
Ticks = 0
TOGGLE TMR0_LED
DO_NOTHING:
ENDIF

' IOCB
IF INTCON.0 = 1 THEN
INTCON.0 = 0
New_bits = PORTB
IF (New_bits.6 <> Old_bits.6) THEN 'PORTB.6 has changed
TOGGLE IOCB_LED
ENDIF
Old_bits = New_bits
ENDIF

RESUME
ENABLE
END

rsocor01
- 1st August 2014, 02:02
Hi,

Why don't you use Darrel's interrupts? It's a lot easier than ON INTERRUPT GOTO ISR.

Also, it is much easier to include a line in your MAIN routine that monitors the state of a switch. You can use the pullup resistors in PORTB, a switch, and a line of code with an IF statement to do what you want. Of course, you need to de bounce the switch.

Jerson
- 1st August 2014, 05:10
If you look into the PBP manual, you will notice that PBP does not handle interrupts like they are meant to be. They are polled. So, there is a lot of latency involved.


"Using ON INTERRUPT, when an interrupt occurs PBP simply flags the event and immediately goes back to what it was doing. It does not immediately vector to your interrupt handler. Since PBP statements are not re-entrant (PBP must finish the statement that is being executed before it can begin a new one) there could be considerable delay (latency) before the interrupt is handled."

You should get used to using assembler interrupts in PBP. Much more power and deterministic. Read "interrupts in Assembler" in the manual. Better still, use Darrels' interrupt code as suggested by rsocor01

Jerson
- 1st August 2014, 05:11
If you look into the PBP manual, you will notice that PBP does not handle interrupts like they are meant to be. They are polled. So, there is a lot of latency involved.


"Using ON INTERRUPT, when an interrupt occurs PBP simply flags the event and immediately goes back to what it was doing. It does not immediately vector to your interrupt handler. Since PBP statements are not re-entrant (PBP must finish the statement that is being executed before it can begin a new one) there could be considerable delay (latency) before the interrupt is handled."

You should get used to using assembler interrupts in PBP. Much more power and deterministic. Read "interrupts in Assembler" in the manual. Better still, use Darrels' interrupt code as suggested by rsocor01

flotulopex
- 3rd August 2014, 10:36
Thanks a lot for your info.

For the time being, I'll try to keep it as simple as possible, correct my current code according to Richard's and Roscor's remarks ;)