Change On Interrupt, PIC16F884


Closed Thread
Results 1 to 18 of 18
  1. #1
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65

    Red face 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
    Attached Images Attached Images

  2. #2
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    One major problem is you're not switching to the proper register banks when attempting to
    write to various registers.

    Why not just let PBP handle all this for you? ADCON0=xx, OSCCON=xx, it's very easy. If you
    prefer to do this all in assembler, you'll need to get very familiar with bank switching, and
    read the datasheet so you know which banks things are located in.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  3. #3
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Default Solved!



    Bruce,

    Thank you! I completely forgot about bank switching! Here is the revised code if it helps anyone. I assume I don't need to worry about bank switching for the config settings.

    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.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
    LOW PORTE.0
    b0 = PORTB ' temp is some variable
    INTCON.0 = 0 ' Clear the interrupt-on-change flag
    RESUME Done ' Go to Main routine
    ENABLE ' Enable all active interrupts
    '************************************************* ************************************************** ***
    Done:

    END

  4. #4
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    This can cause a lot of headaches sometimes due to read-modify-write;

    HIGH PORTE.1 ' reads whole port, flips this bit, writes whole port
    LOW PORTE.0 ' same, but if RE1 isn't high yet, RE1 is read & writen back as 0

    Try just toggling the LED on RE1 to verify that you're entering the interrupt routine.

    Another potential show-stopper is directing RESUME to Done, which halts everything.

    Try something like this;
    Code:
    INITIALIZE:  ' Initialize Routine
        IOCB = %00000001   ' Enable interrupt-on-change on RB0
        INTCON = %10001000 ' Global & interrupt-on-change on Port b enabled
    '************************************************* 
    On Interrupt goto Halt ' on interrupt go to the Halt 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
        WHILE PORTB.0=0 ' wait for button release & end mismatch condition on portb 
        WEND          
        TOGGLE PORTE.1
        INTCON.0 = 0  ' Clear the interrupt-on-change flag
        RESUME        ' Go to Main routine
        ENABLE        ' Enable all active interrupts
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  5. #5
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Default

    Bruce,

    Thank you. It acts a little flaky, e.g., sometimes the LED on porte.1 would stay on two consecutive button presses or off, due to debounce. I looked at some other threads and found a 50ms pause. Here is the code again with the debounce which is working like a charm. Thank you for your help.

    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 = %00000001 ' Enable interrupt-on-change on RB0-RB3
    PORTE.1 = 0 ' Make sure LED on PORTE.1 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
    WHILE PORTB.0=0 ' wait for button release & end mismatch condition on portb
    WEND
    PAUSE 50 ' Debounce delay
    TOGGLE PORTE.1 ' Toggle LED on PORTE.1
    INTCON.0 = 0 ' Clear the interrupt-on-change flag
    RESUME ' Go to Main routine
    ENABLE ' Enable all active interrupts

  6. #6
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Default 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

  7. #7
    Join Date
    Apr 2006
    Location
    New Hampshire USA
    Posts
    298


    Did you find this post helpful? Yes | No

    Smile Just an idea...

    Hi elec_mech,
    Posting code directly into the text portion of the forum makes it difficult to follow.
    Quote Originally Posted by Mister_e
    [code] paste your code here [/code]
    One step better but a lot more work:
    Quote Originally Posted by Darrel Taylor View Post
    Show us your Colors.
    Quote Originally Posted by elec_mech View Post
    define osc 8 ' tell the program the oscillator is running at 8 mhz
    Quote Originally Posted by PBP 2.50 manual
    4.16. DEFINE may be used to change the predefined oscillator value...
    These definitions must be in all upper case, exactly as shown.
    If not, the compiler may not recognize them.
    No error message will be produced for defines the compiler does not recognize.
    Code:
    DEFINE OSC 8
    -Adam-
    Last edited by Pic_User; - 13th November 2008 at 18:20. Reason: Changing formatting
    Ohm it's not just a good idea... it's the LAW !

  8. #8
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Default

    Adam,

    I see what you mean with the DEFINE, oops! Thanks for the catch. I see what you mean with colors. Is this better?
    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

  9. #9
    Join Date
    Apr 2006
    Location
    New Hampshire USA
    Posts
    298


    Did you find this post helpful? Yes | No

    Thumbs up the real question

    Quote Originally Posted by elec_mech View Post
    Adam,
    I see what you mean with the DEFINE, oops! Thanks for the catch. I see what you mean with colors. Is this better?
    It is better! But the idea is to copy from your editor, paste into a code box. So the indents and formatting look more like the original. Sometimes the forum changes the formatting. I was not sure the lowercase define was in your original or being changed by the forum. It changes a lot of things “for you” I wish I knew more about PBP to really help you on your real question.
    -Adam-
    Ohm it's not just a good idea... it's the LAW !

  10. #10
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    with code bracket
    I type
    [code]
    i now paste my code here
    then i type [/code]

    we got
    Code:
            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
    
            define OSC 8        ' Tell the program the oscillator is running at 8 MHz
            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
    
            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
    
            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
            
            ADCON0.0 = 0        ; Make all analog pins digital I/Os
            CM1CON0.7 = 0       ; Disable comparator C1
            CM2CON0.7 = 0       ; Disable comparator C2
            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
            
            INCLUDE "modedefs.bas"
    
    '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
    
    
    '*************************************************************************************************** *
    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
           
            INTCON.0 = 0            ' Clear the interrupt-on-change flag
            RESUME                  ' Go to Main routine
            ENABLE                  ' Enable all active interrupts
    with colors, following the following thread
    http://www.picbasic.co.uk/forum/show...ht=show+colors

    we got
    Code:
    <font color="#000000">        <font color="#000080">ASM </font><font color="#008000">; The following code is assembly, not Basic
                    </font><font color="#000080">__CONFIG _CONFIG1, _INTOSCIO &amp; _WDT_OFF &amp; _PWRTE_ON &amp; _CP_OFF &amp; _BOR_OFF &amp; _IESO_OFF &amp; _FCMEN_OFF &amp; _LVP_OFF
                    </font><font color="#008000">; Use internal oscillator &amp; 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
            </font><font color="#000080">ENDASM </font><font color="#008000">' End assembly code
    
            </font><font color="#000080">DEFINE </font>OSC 8        <font color="#008000">' Tell the program the oscillator is running at 8 MHz
            </font>OSCCON.6 = 1        <font color="#008000">; Set the internal oscillator to 8MHz
            </font>OSCCON.5 = 1        <font color="#008000">; Set the internal oscillator to 8MHz
            </font>OSCCON.4 = 1        <font color="#008000">; Set the internal oscillator to 8MHz
    
            </font>PORTA = $00         <font color="#008000">' Set all port a pins to low
            </font>PORTB = $00         <font color="#008000">' Set all port b pins to low
            </font>PORTC = $00         <font color="#008000">' Set all port c pins to low
            </font>PORTD = $00         <font color="#008000">' Set all port d pins to low
            </font>PORTE = $00         <font color="#008000">' Set all port e pins to low
    
            </font>TRISA = %00000000   <font color="#008000">' Make all port a pins outputs
            </font>TRISB = %00001111   <font color="#008000">' Make port b pins 0-3 inputs and the rest as outputs
            </font>TRISC = %00000000   <font color="#008000">' Make all port c pins outputs
            </font>TRISD = %00000000   <font color="#008000">' Make all port d pins outputs
            </font>TRISE = %00000000   <font color="#008000">' Make all port e pins outputs
            
            </font>ADCON0.0 = 0        <font color="#008000">; Make all analog pins digital I/Os
            </font>CM1CON0.7 = 0       <font color="#008000">; Disable comparator C1
            </font>CM2CON0.7 = 0       <font color="#008000">; Disable comparator C2
            </font>WDTCON.0 = 0        <font color="#008000">; Disable the watchdog timer
            </font>ANSEL = %00000000   <font color="#008000">; Set all analog pins on port a to digital I/O
            </font>ANSELH = %00000000  <font color="#008000">; Set all analog pins on port b to digital I/O
            
            </font><font color="#000080">INCLUDE </font>&quot;modedefs.bas&quot;
    
    <font color="#008000">'Variables*****************************************************************************************
            </font>b0 <font color="#000080">VAR BYTE         </font><font color="#008000">' Required byte variable for toggle button
    
    
    '**************************************************************************************************
    </font>INITIALIZE:                 <font color="#008000">' Initialize Routine
            </font>INTCON.0 = 0        <font color="#008000">' Clear the interrupt-on-change flag
            </font><font color="#000080">ON INTERRUPT GOTO </font>Halt <font color="#008000">' Once an active interrupt port is enabled, go to the Halt routine
            </font>INTCON = %10001000  <font color="#008000">' Enable global interrupts, Enable interrupt-on-change on Port b
            </font>IOCB = %00000011    <font color="#008000">' Enable interrupt-on-change on RB0-RB3
            </font>PORTE.1 = 0         <font color="#008000">' Make sure LED on PORTE.1 is off
            </font>PORTE.2 = 0         <font color="#008000">' Make sure LED on PORTE.2 is off
    
    
    '*************************************************************************************************** *
    </font>MAIN:
            <font color="#000080">HIGH </font>PORTE.0
            <font color="#000080">PAUSE </font>500
            <font color="#000080">LOW </font>PORTE.0
            <font color="#000080">PAUSE </font>500
            <font color="#000080">GOTO </font>MAIN
    
    
    <font color="#008000">'*************************************************
            </font><font color="#000080">DISABLE         </font><font color="#008000">' do NOT place interrupt checking code below
            
    </font>Halt:   <font color="#008000">' Halt Routine
            </font><font color="#000080">IF </font>PORTB.0 = 0 <font color="#000080">THEN
                    WHILE </font>PORTB.0=0 <font color="#008000">' wait for button release &amp; end mismatch condition on portb
                    </font><font color="#000080">WEND
                    PAUSE </font>20        <font color="#008000">' Debounce delay
                    </font><font color="#000080">HIGH </font>PORTE.1
                    <font color="#000080">LOW </font>PORTE.2
                    <font color="#000080">ENDIF
                    
            IF </font>PORTB.1 = 0 <font color="#000080">THEN
                    WHILE </font>PORTB.1=0 <font color="#008000">' wait for button release &amp; end mismatch condition on portb
                    </font><font color="#000080">WEND            
                    PAUSE </font>20        <font color="#008000">' Debounce delay
                    </font><font color="#000080">LOW </font>PORTE.1
                    <font color="#000080">HIGH </font>PORTE.2
                    <font color="#000080">ENDIF
           
            </font>INTCON.0 = 0            <font color="#008000">' Clear the interrupt-on-change flag
            </font><font color="#000080">RESUME                  </font><font color="#008000">' Go to Main routine
            </font><font color="#000080">ENABLE                  </font><font color="#008000">' Enable all active interrupts
    </font>
    Read your datasheet about Interrupt on change. I haven't done myself, but I bet you should read the whole, save it to a variable, then play with this variable.

    Probably not a bad idea, to do the same thing before ON INTERRUPT.. read the whole port, save it to a dummy variable, etc.

    HTH
    Last edited by mister_e; - 13th November 2008 at 20:54.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  11. #11
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Default Closer . . .

    Alright, I got smart and have an LED coming on whenever the interrupt routine is entered and guess what? The program always goes into the interrupt routine whenever I press a button. The bad news is that the program doesn't seem to be able to determine which switch is pressed fast enough. Again, if I hold the switch down for a second or more, it knows which switch is pressed. But more often than not, I just press the button as anyone would and I see the LED come on indicating the interrupt routine was entered, but the other LEDs don't toggle most of the time. I suspect that the program is dragging somewhere, but I don't know why the program can pick up a change on PORTB but doesn't have the time to determine which input was tripped. Any suggestions? Modified code below.

    '************************************************* ************************************************** *
    MAIN:
    ' HIGH PORTE.0
    PAUSE 500
    LOW PORTE.0
    ' PAUSE 500
    GOTO MAIN
    '*************************************************
    DISABLE ' do NOT place interrupt checking code below
    Halt: ' Halt Routine
    HIGH PORTE.0
    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

    INTCON.0 = 0 ' Clear the interrupt-on-change flag
    RESUME Main ' Go to Main routine
    ENABLE ' Enable all active interrupts

  12. #12
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    You have 500mS delays before your interrupt can even be processed. Unless someone
    presses & holds a button, it may be quite a long time before you enter your interrupt
    handler.

    Reduce your pause times by using a loop with PAUSEUS until your 500mS delay period
    expires. Then you only have a few uS before PBP will jump to your int handler, and you
    can read the whole port in the first line, save it to a variable, then make a decision on
    which switch was pressed.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  13. #13
    Join Date
    Sep 2005
    Location
    Campbell, CA
    Posts
    1,107


    Did you find this post helpful? Yes | No

    Default

    Just a suggestion - use Darrel Taylor's Instant Interrupts. If you use that, you don't have to worry about PAUSE. The interrupt routine will be entered whenever the button is pushed - even in the middle of a PAUSE routine. In the end, it is a much cleaner solution than ON INTERRUPT GOTO - believe me.
    Charles Linquist

  14. #14
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Talking

    Ahh, I was wondering if that might impact it. So, an external interrupt will not interrupt the program while executing a pause command? Is that due to the way PBP works? If I were to go so far as to program in assembly, it's been a while, I would assume I could interrupt a timer function with an external interrupt. Okay though, I see what you mean.

    Alright, I gave it shot and eureka, it works! Thank you Bruce! Here's the updated code.

    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
    i var word
    temp var byte
    '************************************************* ************************************************** *
    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
    FOR i = 1 to 5000
    PAUSEUS 100
    NEXT
    LOW PORTE.0
    FOR i = 1 to 5000
    PAUSEUS 100
    NEXT
    GOTO MAIN
    '*************************************************
    DISABLE ' do NOT place interrupt checking code below
    Halt: ' Halt Routine
    temp = PORTB
    IF temp.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 temp.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
    INTCON.0 = 0 ' Clear the interrupt-on-change flag
    RESUME ' Resume wherever program left off at
    ENABLE ' Enable all active interrupts
    Sorry, I tried the Save As in html to get the color, but I can't save it as html from MPLAB.

    I assume the while loop and 20ms debounce pause are still good to have.

    Charles, I tried using Darrel Teylor's Instant Interrupts without success. I attempted to use the RBC_INT. It didn't work and I read that that command is only designed for ports b4-7. Then I attempted to use INT0_INT and INT1_INT for ports b0 and b1, respectively, but no luck there either. I'm not sure if I'm doing something wrong or if I need configure something. I love the concept, but I wanted to figure out how to fix the PBP interrupt version I'm familar with before I try figuring out a new method. I'm open to suggestions if you have any. Thank you for the suggestion. I definitely want to play with Darrel's solution once I've got this licked.

  15. #15
    Join Date
    Aug 2006
    Location
    Look, behind you.
    Posts
    2,818


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by elec_mech View Post
    Ahh, I was wondering if that might impact it. So, an external interrupt will not interrupt the program while executing a pause command? Is that due to the way PBP works? If I were to go so far as to program in assembly, it's been a while, I would assume I could interrupt a timer function with an external interrupt. Okay though, I see what you mean.

    Alright, I gave it shot and eureka, it works! Thank you Bruce! Here's the updated code.


    It's due to PBP interrupts being a Psudo interrupt, it detects the hardware interrupt, puts a request on the stack and waits for an opportunity, Whereas an assembly interrupt is like cops, break in and announce it's arrival.
    If you do not believe in MAGIC, Consider how currency has value simply by printing it, and is then traded for real assets.
    .
    Gold is the money of kings, silver is the money of gentlemen, barter is the money of peasants - but debt is the money of slaves
    .
    There simply is no "Happy Spam" If you do it you will disappear from this forum.

  16. #16
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Question 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.

    '************************************************* ************************************************** ***
    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
    '************************************************* ************************************************** ***

  17. #17
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    Not a good idea to me to use label with RESUME as you never know where the program was before to jump in the ISR. You should jump (goto) at the end if your ISR, then your program will return where he was before.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  18. #18
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Thumbs up

    Steve,

    I'd be lying if I said I completely understood what you meant, but I noticed that I was forcing the program to resume at the start of the Main routine and allowed it to just resume at the end of the ISR. It works! Thank you for your advice. I still have one of the digits going off whenever I press a button, but I'll investigate that further. Likely a hardware issue.

    '************************************************* ************************************************** ***
    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 ' Resume program running before interrupt occurred
    ENABLE ' Enable all active interrupts
    '************************************************* ************************************************** ***

Similar Threads

  1. A Simple IOC Routine (Interrupt On Change)
    By lugo.p in forum mel PIC BASIC Pro
    Replies: 6
    Last Post: - 8th March 2010, 20:53
  2. Won't go back to SLEEP after 1st Interrupt
    By jellis00 in forum mel PIC BASIC Pro
    Replies: 32
    Last Post: - 29th June 2009, 10:00
  3. Can't ID interrupt source with this IntHandler??
    By jellis00 in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 3rd June 2009, 03:35
  4. NEWBIE: Some basic questions using interrupts
    By JackPollack in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 8th March 2006, 03:59
  5. USART interrupt not interrupting right
    By Morpheus in forum mel PIC BASIC Pro
    Replies: 12
    Last Post: - 6th March 2005, 02:07

Members who have read this thread : 1

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