Log in

View Full Version : Help Needed with Darrel's Interrupt on Change Routine



Aussie Barry
- 3rd January 2013, 12:26
Hi All,

I have been going around in circles all day trying to get Darrel's Instant Interrupt routine (Interrupt on Change) working on two PORTB pins of a PIC16F1826. I want to increment or decrement a byte size variable (Level) between 1 and 8 using switches on RB1 and RB2. Each pin has a 10k pull down resistor and I have tried to set the IOCBP register to read rising edge triggers. The variable is displayed on a 16 x 2 LCD using LCDOUT command. I can display the variable (default is 3) but cannot get the switches to work.

My code is as follows:



#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_OFF & _BORV_25 & _LVP_OFF
#ENDCONFIG

DEFINE OSC 32 'Internal RC Oscillator with PLL

' Connect LCD DB4 to RA0 (Pin 17)
' Connect LCD DB5 to RA1 (Pin 18)
' Connect LCD DB6 to RA2 (Pin 1)
' Connect LCD DB7 to RA3 (Pin 2)
' Connect LCD R/S to RA6 (Pin 15)
' Connect LCD E to RA7 (Pin 16)
' Connect Reset Button to MCLR (Pin 4)
' Connect Up Switch to RB1 (Pin 7) with 10k pulldown resistor
' Connect Down Switch to RB2 (Pin 8) with 10k pulldown resistor


INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler IOC_INT, _PortBInterrupts, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE IOC_INT ; enable PortB change interrupts


' Define LCD registers and bits
Define LCD_DREG PORTA
Define LCD_DBIT 0
Define LCD_RSREG PORTA
Define LCD_RSBIT 6
Define LCD_EREG PORTA
Define LCD_EBIT 7
Define LCD_BITS 4
Define LCD_LINES 2

INTCON = %10001000 'Enable Global Interupts and IOC interrupt
OSCCON= %11110000 'PLL enabled, Internal RC-8MHz and PLL x 4

CM1CON0.7 = 0 'Disable comparator 1
CM2CON0.7 = 0 'Disable comparator 2

PORTB = 0:PORTA=0 'Set all outputs to 0
TRISB = %00000110 'Set PORTB.1 & 2 as digital input
'All other PORTB pins as digital outputs
TRISA = %00100000 'Set PORTA.5 as digital inputs
'All other PORTA pins as digital outputs
'(PORTA.5 can only be an input)

ANSELA = %00000000 'Disable PORTA analog inputs
ANSELB = %00000000 'Disable PORTB analog inputs

ADCON0 = %00000000 'Enable ADC and select AN9


FVRCON = %00000000 'Disable FVR
IOCBP = %00000110 'Set IOC on rising edge for RB1 & RB2
IOCBN = 0 'Disable IOC falling

;-- Place a copy of these variables in your Main program -------------------
;-- The compiler will tell you which lines to un-comment --
;-- Do Not un-comment these lines --
;---------------------------------------------------------------------------
wsave VAR BYTE $20 SYSTEM ' location for W if in bank0
;wsave VAR BYTE $70 SYSTEM ' alternate save location for W
' if using $70, comment wsave1-3

' --- IF any of these three lines cause an error ?? ------------------------
' Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using --
wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
;wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3


Level var byte 'Level setting 1 - 8
Level = 3 'Set starting level to 1

pause 1000 'Pause 1 second
LCDOUT $FE, 1 'Clear screen

Again:
lcdout $FE, $80, "Level = ", dec Level, " "'Display Level

goto Again


PortBInterrupts:

if IOCBF.1 = 1 then
Level = Level + 1
If Level > 8 then
Level = 8
endif
endif

if IOCBF.2 = 1 then
Level = Level - 1
If Level < 1 then
Level = 1
endif
endif

@ INT_RETURN
end



I have used the Instant Interrupt routine before (with some help from other forum members) but this time it has me perplexed. The process of commenting out variable wsave etc confuses me as on this occasion the compiler gives no error messages. I have tried a number of different combinations - all to no avail. I must admit, I have been clutching at straws for the last few hours!

Can somebody please look at the code and tell me what I am doing wrong?

Cheers
Barry
VK2XBP

HenrikOlsson
- 3rd January 2013, 13:32
Hi,
One thing with IOC is that you need to read the port in the ISR to clear the mismatch condition. This chips IOC feature seems a bit more complicated than the "standard" though and it looks like you don't actually have to do it but I'm not 100% sure.

Being different than the IOC implementation on older chips it's possible that the Instant Interrupt Routines doesn't handle this new IOC implementation properly. I'm not saying that is the case but it's possible. Hopefully Darrel sees this and will set the record straight.

I don't have any of these new 16F1xxx chips so I can't test but one thing you can try is to manually clear the IOCBF.1 or IOCBF.2 bits before exiting the interrupt service routines.

/Henrik.

Darrel Taylor
- 3rd January 2013, 17:33
In the case of IOCIF, the hardware does not allowing clearing that bit.
As long as any of the IOCAF or IOCBF are set, the IOCIF bit will remain set too.

DT_INTS does not clear the IOCAF or IOCBF flags, since there's no way to know which of the 16 flags should be cleared for your application.
It is up to you to clear those flags.

This particular chip doesn't have an IOCAF register, so ...
In your case, ... IOCBF = 0 will fix your problem.

Aussie Barry
- 3rd January 2013, 21:06
So close and yet so far....

Thanks for the input guys. I added the IOCBF=0 line to the ISR and, after adding a slight pause to debounce the switch, all is now working properly.

Two things confuse me though:

1/. Without the IOCBF=0 statement, why didn't my initial code get to the ISR the first time a switch was pressed? I would have expected the ISR to be called once (changing Level from 3 to 4 or 3 to 2 depending which switch was pushed) but then halting due to the IOCBF not being reset.

2/. What should I expect regarding the commenting-out of the variables (wsave etc) when first compiling the Instant Interrupt routine? It compiles with all lines commented out. Is this right and if so, why?

Cheers
Barry
VK2XBP

Darrel Taylor
- 3rd January 2013, 21:44
It would have called the ISR the first time.
But it would have never made it back to the main program to display the change.
As soon as it exits the ISR, it immediately triggers an interrupt again because the flag wasn't cleared.
.
The 16F1's do automatic context saving.
You do not need any wsave variables.

Which is why it didn't tell you to uncomment any of them.

Aussie Barry
- 3rd January 2013, 21:52
Thanks Darrel.

I understand now.

Onwards and upwards! Time to add your Elapsed Timer routine to this project :)

Cheers
Barry
VK2XBP