1 Attachment(s)
Change On Interrupt, PIC16F884
Hello Folks,
I'm either missing something amazingly minor or something is going terribly wrong, likely the former. I'm using a PIC16F884 and attempting to use the interrupt-on-change feature. I've hooked up a momentary switch, pulled high and tied to ground when the switch is pressed and connected it to PORTB.0. I have two LEDs, one that blinks constantly and one to let me know when the interrupt routine has been activated. I've attached a simple drawing of the circuit under test. Eventually I want to use four switches on ports B0-B3.
The problem is, I can never seem to get the interrupt to work, i.e. the second LED never comes on. I've gone over the manual and the forum, tried a few things, and have come up nil. Any advice or suggestions is greatly appreciated. Code is below. Thank you in advance.
INCLUDE "modedefs.bas"
PORTA = $00 ' Set all port a pins to low
PORTB = $00 ' Set all port b pins to low
PORTC = $00 ' Set all port c pins to low
PORTD = $00 ' Set all port d pins to low
PORTE = $00 ' Set all port e pins to low
asm ; The following code is assembly, not Basic
__CONFIG _CONFIG1, _INTOSCIO & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF
; Use internal oscillator & make both, OSC pins I/Os, turn off watchdog timer, enable Power-up timer,
; code protection off, brown-out off, disable switch over mode, turn off failsafe monitor,
; low voltage programming off
bcf WDTCON, SWDTEN ; Disable the watchdog timer
bsf OSCCON, IRCF2 ; Set the internal oscillator to 8MHz
bsf OSCCON, IRCF1 ; Set the internal oscillator to 8MHz
bsf OSCCON, IRCF0 ; Set the internal oscillator to 8MHz
bcf ADCON0, ADON ; Make all analog pins digital I/Os
bcf CM1CON0, C1ON ; Disable comparator C1
bcf CM2CON0, C2ON ; Disable comparator C1
MOVLW 0x00 ; Set w = 00000000
MOVWF ANSEL ; Set all analog pins on port a to digital I/O
MOVLW 0x00 ; Set w = 00000000
MOVWF ANSELH ; Set all analog pins on port b to digital I/O
endasm ' End assembly code
define OSC 8 ' Tell the program the oscillator is running at 8 MHz
TRISA = %00000000 ' Make all port a pins outputs
TRISB = %00001111 ' Make port b pins 0-3 inputs and the rest as outputs
TRISC = %00000000 ' Make all port c pins outputs
TRISD = %00000000 ' Make all port d pins outputs
TRISE = %00000000 ' Make all port e pins outputs
PORTA = $00 ' Set all port a pins to low
PORTB = $00 ' Set all port b pins to low
PORTC = $00 ' Set all port c pins to low
PORTD = $00 ' Set all port d pins to low
PORTE = $00 ' Set all port e pins to low
'Variables**************************************** ************************************************** *
b0 VAR byte ' Required byte variable for toggle button
'************************************************* ************************************************** *
INITIALIZE: ' Initialize Routine
INTCON.0 = 0 ' Clear the interrupt-on-change flag
On Interrupt goto Halt ' Once an active interrupt port is enabled, go to the Halt routine
INTCON.7 = 1 ' Enable global interrupts
IOCB = %00000001 ' Enable interrupt-on-change on RB0-RB3
INTCON.3 = 1 ' Enable interrupt-on-change on Port b
GOTO MAIN ' Go to Main routine
'************************************************* ************************************************** *
MAIN:
' PORTB = $00 ' Set all port b pins to low
b0 = PORTB ' temp is some variable
HIGH PORTE.0
PAUSE 500
LOW PORTE.0
PAUSE 500
GOTO MAIN
'************************************************* ************************************************** ***
DISABLE ' Disable all interrupts
Halt: ' Halt Routine
HIGH PORTE.1
b0 = PORTB ' temp is some variable
INTCON.0 = 0 ' Clear the interrupt-on-change flag
RESUME Main ' Go to Main routine
ENABLE ' Enable all active interrupts
'************************************************* ************************************************** ***
END
Detecting Multiple Switches with Interrupt-On-Change
One more question: How about detecting multiple switches with interrupt-on-change? I've tried the modified code below as well as the commented out code on its own. This works, but not reliably. I'm using those momentary red square switches from RadioShack and the LEDs only change about half the time, i.e., the program isn't detecting the button press. I've tried pressing the switches hard (fully down) quickly, but with the same hit rate of half. If I press and hold each button for a second or two, it works fine, but I don't want to force the user to press and hold a switch to do something. I tried playing with the debounce times and even adding a ceramic capacitor, 0.1uF and 0.01uF across the switch contacts with no luck. I tried searching the forum, but the only interrupt examples I've come across are for single button applications. Any suggestions?
INCLUDE "modedefs.bas"
PORTA = $00 ' Set all port a pins to low
PORTB = $00 ' Set all port b pins to low
PORTC = $00 ' Set all port c pins to low
PORTD = $00 ' Set all port d pins to low
PORTE = $00 ' Set all port e pins to low
asm ; The following code is assembly, not Basic
__CONFIG _CONFIG1, _INTOSCIO & _WDT_OFF & _PWRTE_ON & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF
; Use internal oscillator & make both, OSC pins I/Os, turn off watchdog timer, enable Power-up timer,
; code protection off, brown-out off, disable switch over mode, turn off failsafe monitor,
; low voltage programming off
endasm ' End assembly code
ADCON0.0 = 0 ; Make all analog pins digital I/Os
CM1CON0.7 = 0 ; Disable comparator C1
CM2CON0.7 = 0 ; Disable comparator C2
OSCCON.6 = 1 ; Set the internal oscillator to 8MHz
OSCCON.5 = 1 ; Set the internal oscillator to 8MHz
OSCCON.4 = 1 ; Set the internal oscillator to 8MHz
WDTCON.0 = 0 ; Disable the watchdog timer
ANSEL = %00000000 ; Set all analog pins on port a to digital I/O
ANSELH = %00000000 ; Set all analog pins on port b to digital I/O
define OSC 8 ' Tell the program the oscillator is running at 8 MHz
TRISA = %00000000 ' Make all port a pins outputs
TRISB = %00001111 ' Make port b pins 0-3 inputs and the rest as outputs
TRISC = %00000000 ' Make all port c pins outputs
TRISD = %00000000 ' Make all port d pins outputs
TRISE = %00000000 ' Make all port e pins outputs
PORTA = $00 ' Set all port a pins to low
PORTB = $00 ' Set all port b pins to low
PORTC = $00 ' Set all port c pins to low
PORTD = $00 ' Set all port d pins to low
PORTE = $00 ' Set all port e pins to low
'Variables**************************************** ************************************************** *
b0 VAR byte ' Required byte variable for toggle button
'************************************************* ************************************************** *
INITIALIZE: ' Initialize Routine
INTCON.0 = 0 ' Clear the interrupt-on-change flag
On Interrupt goto Halt ' Once an active interrupt port is enabled, go to the Halt routine
INTCON = %10001000 ' Enable global interrupts, Enable interrupt-on-change on Port b
IOCB = %00000011 ' Enable interrupt-on-change on RB0-RB3
PORTE.1 = 0 ' Make sure LED on PORTE.1 is off
PORTE.2 = 0 ' Make sure LED on PORTE.2 is off
GOTO MAIN ' Go to Main routine
'************************************************* ************************************************** *
MAIN:
HIGH PORTE.0
PAUSE 500
LOW PORTE.0
PAUSE 500
GOTO MAIN
'*************************************************
DISABLE ' do NOT place interrupt checking code below
Halt: ' Halt Routine
IF PORTB.0 = 0 THEN
WHILE PORTB.0=0 ' wait for button release & end mismatch condition on portb
WEND
PAUSE 20 ' Debounce delay
HIGH PORTE.1
LOW PORTE.2
ENDIF
IF PORTB.1 = 0 THEN
WHILE PORTB.1=0 ' wait for button release & end mismatch condition on portb
WEND
PAUSE 20 ' Debounce delay
LOW PORTE.1
HIGH PORTE.2
ENDIF
' IF PORTB.0 = 0 THEN
' ' PAUSE 20
' ' IF PORTB.0 = 0 THEN
' HIGH PORTE.1
' LOW PORTE.2
' ' ENDIF
' ENDIF
'
' IF PORTB.1 = 0 THEN
' ' PAUSE 20
' ' IF PORTB.1 = 0 THEN
' LOW PORTE.1
' HIGH PORTE.2
' ' ENDIF
' ENDIF
INTCON.0 = 0 ' Clear the interrupt-on-change flag
RESUME ' Go to Main routine
ENABLE ' Enable all active interrupts
Multiple Resumes not working
Joe, thanks for the info!
Okay, related to interrupts, I've run into another problem. I go into my interrupt routine, detect a button on a port change and then tell the program to resume at a new routine based on which button was pressed. The first button works fine, but whenever I press the second button, it seems to ignore/skip the resume (colored below) and go on to the end of the interrupt routine. I added a toggle to an LED to indicate where the program was going. It works before the colored resume statement and after the end if statement, but not immediately after the resume statement. I also tried it at the beginning of the Score_player2 routine, which of course didn't work. I tried a quick search on the forum, but didn't come across anything similar, at least not yet. Any reason PBP would skip or ignore a resume statement? I've just included the interrupt routine - the rest is very similar to the code posted above.
I don't know if this is an indication of another problem, but I'm multiplexing two seven segment digits and whenever I press either button, one of the digits goes out, sometimes digit A and sometimes digit B regardless of the button pressed, and comes back on whenever I release the button.
Quote:
'************************************************* ************************************************** ***
DISABLE ' do NOT place interrupt checking code below
Halt: ' Halt Routine
temp = PORTB
TOGGLE PORTE.1
IF temp.0 = 0 THEN
WHILE PORTB.0=0 ' wait for button release & end mismatch condition on portb
WEND
PAUSE 20 ' Debounce delay
INTCON.0 = 0 ' Clear the interrupt-on-change flag
RESUME SCORE_PLAYER1
ENDIF
IF temp.1 = 0 THEN
WHILE PORTB.1=0 ' wait for button release & end mismatch condition on portb
WEND
PAUSE 20 ' Debounce delay
INTCON.0 = 0 ' Clear the interrupt-on-change flag
RESUME SCORE_PLAYER2
ENDIF
INTCON.0 = 0 ' Clear the interrupt-on-change flag
RESUME Main ' Go to Main routine
ENABLE ' Enable all active interrupts
'************************************************* ************************************************** ***