Having problems with external interrupt on PIC16F886

Discussion in 'Embedded Systems and Microcontrollers' started by Barnaby Walters, May 26, 2011.

  1. Barnaby Walters

    Thread Starter Member

    Mar 2, 2011
    103
    4
    Hello All,

    I'm having problems getting the external interrupt to trigger on my robot. The output of a 38kHz IR detector is fed into RB0 — the signal is high unless a wave is detected, in which case it drops down to low. I have tried to set the interrupt to trigger on a falling edge. I've tried using the weak pull up resistor, I've added context save/restore even though my program doesn't need it, and I'm stuck.

    The ASM is below:

    Code ( (Unknown Language)):
    1. ;
    2. ;   Author: Barnaby Walters
    3. ;   Created: 27th March 2011
    4. ;  
    5. ;   For PIC: 16F886
    6. ;   Default Radix: Hex
    7. ;
    8. ;   Description:    Contains the IR enable/detect loop. Lights different LEDs to indicate which direction an object is seen in
    9. ;                   Runs at 4MHz   
    10. ;  
    11. ;   Currently:      The interrupt handler is never called. The rest of the program seems to function fine, but no matter what I do
    12. ;                   I can't get the handler routine called.
    13. ;
    14. ; * * * * * * * * * * * * * * * *
    15.  
    16. list p=16f886
    17. include p16f886.inc
    18.    
    19.     ; Set up 16F886 Config Registers
    20.     __CONFIG    _CONFIG1, _MCLRE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BOR_ON & _CP_OFF & _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _CPD_OFF
    21.                 ; For Config Bank 1: No MCLR Reset, no WDT, int. Osc no clkout, BOR On, Code protection, Low voltage protection — essectially, very few features.
    22.     __CONFIG    _CONFIG2, _BOR40V
    23.                 ; Set the BOR voltage to 4v
    24.    
    25. ; Reserve Variables
    26. tmr1    equ 20h
    27. tmr2    equ tmr1 + 1
    28. tmr3    equ tmr2 + 1
    29. IRData  equ tmr3 + 1        ; IRData structure: 7:4 = N/A; 3 = Signal right; 2 = Signal Left; 1 = Right Lit; 0 = Left Lit
    30. w_temp  equ IRData + 1
    31. status_temp equ w_temp + 1
    32.  
    33. ;firstAvailableRegister equ 0x20
    34.  
    35.     org 0h
    36.     nop                     ; Allows ICD2 Debugger to work - not that I'm using that.
    37.     goto    main            ; Start main program
    38.     nop
    39.     nop
    40.    
    41. ; Interrupt Service Routine
    42.     movwf   w_temp
    43.     movf    STATUS,w
    44.     movwf   status_temp     ; Save context
    45. ; Actual ISR
    46.     movlw   b'11111001'
    47.     movwf   PORTC           ; Light up most of PORTC, including the indicator LED @ RC3
    48.     bcf     INTCON,INTF     ; Clear ext. int. flag
    49.    
    50.     movf    status_temp,w   ; Restore context
    51.     movwf   STATUS
    52.     swapf   w_temp,f
    53.     swapf   w_temp,w
    54.     retfie                  ; Return
    55.    
    56. ; * * * * * * * * * * * SUBROUTINES * * * * * * * * * * * * * * *
    57.  
    58. ; Initalisation Routine
    59. init
    60.     clrf    PORTA
    61.     clrf    PORTB
    62.     clrf    PORTC
    63.     banksel OSCCON          ; switches to bank 1. We need to be here to mess about with TRIS registers
    64.     movlw   b'01100001'     ;
    65.     movwf   OSCCON          ; Osc Config: 0 (un) , 110 (4Mhz) , 000 (Rd Only) , 1 (Use internal Clk)
    66.    
    67.     movlw   b'00000000'     ;
    68.     movwf   TRISA           ; PORTA = all outputs. A0 = Right indicator A1 = Left Indicator
    69.     movlw   b'00000001'     ;
    70.     movwf   TRISB           ; PORTB 0:3 used. B1 = Right Enable B2 = Left Enable B0 = Sensor Input
    71.     movwf   WPUB            ; Weak pull-up on RB0
    72.     movlw   b'00000000'     ;
    73.     movwf   TRISC           ; PORTC = outputs. C3 = HB LED. Motors not used in this app (yet)
    74.     movlw   b'1000'
    75.     movwf   TRISE           ; PORTE 3 (MCLR) = Input
    76.    
    77.     banksel OPTION_REG
    78.    
    79.     bcf     OPTION_REG,NOT_RBPU ; Enable RB Pull Ups
    80.     bcf     OPTION_REG,INTEDG   ; Interrupt triggered on falling edge @ RB0
    81.    
    82.     movlw   b'10010000'
    83.     movwf   INTCON          ; Enable unmasked interrupts, Enable interrupt on RB0
    84.    
    85.     banksel PORTA       ; Switch to bank 0 so we can move on with the program
    86.     return                  ; Return to the program
    87.  
    88. ; Delay Routines:
    89.  
    90. D30IRCycles                 ; Delays program flow for 30 cycles @ 38kHz — 'On' time for IREDs
    91.     movlw   d'2'
    92.     movwf   tmr2
    93.     movlw   d'195'          ; 30 IR Cycles = 780 instruction cycles. GOTO = 2 instruction cycles
    94.     movwf   tmr1            ; This timer will have to be completely decremented two times for the full 780 cycles
    95. D30IR_Delay
    96.     decfsz  tmr1,f
    97.     goto    D30IR_Delay     ; Cycle 195 times
    98.     movwf   tmr1
    99.     decfsz  tmr2,f
    100.     goto    D30IR_Delay     ; Go back and cycle twice
    101.     return
    102.    
    103. D15IRCycles                 ; Delays program flow for 15 cycles @ 38kHz — 'Off' time for IREDs
    104.     movlw   d'195'          ; GOTO = 2 cycles. 2 * 195 = 390 instructions = 15 IR Cycles
    105.     movwf   tmr1
    106. D15IR_Delay
    107.     decfsz  tmr1,f
    108.     goto    D15IR_Delay
    109.     return 
    110.    
    111. ; * * * * * * * * * *   Main Program    * * * * * * * * * *
    112.  
    113. main
    114.     call    init            ; Set up ports, etc
    115.     ; Program structure: Constantly alternate between IR LEDs. Each one on for 30 cycles, the off for 15 cycles as per datasheet
    116.    
    117. sensorPollLoop
    118.  
    119.     clrf    IRData          ; Clear data from last sensor poll loop execution
    120.    
    121.     call    D15IRCycles     ;  — — — — — — — Hold LEDs off for the required time — — — — — — —
    122.    
    123.     bsf     PORTB, 2        ; Turn on the left IRED (Robot perspective)
    124.     bsf     IRData, 0       ; Left IRED currently emitting.
    125.    
    126.     call    D30IRCycles     ; Hold it on for a certain amount of time
    127.    
    128.     bcf     IRData, 2       ; Left IRED not currently emitting
    129.     bcf     PORTB, 0        ; Turn off the left IRED
    130.    
    131.     call    D15IRCycles     ;  — — — — — — — Hold LEDs off for the required time — — — — — — —
    132.    
    133.     bsf     PORTB, 1        ; Turn on the right IRED (Robot perspective)
    134.     bsf     IRData, 1       ; Right IRED currently emitting
    135.    
    136.     call    D30IRCycles     ; Hold it on for a certain amount of time
    137.    
    138.     bcf     IRData, 1       ; Right IRED not currently emitting
    139.     bcf     PORTB, 1        ; Turn off the right IRED
    140.    
    141.     ;   — — — — — — — One complete sensor poll finished — — — — — — —
    142.     ; Now: See what data we have. For the moment, that means copying the data in IRData 3:2 to PORTA 3:2. How convenient…
    143.    
    144.     movf    IRData, w       ; Pop value of IRData into the W. Reg…
    145.     movwf   PORTA           ; …and copy it into PORTA. Sorted!
    146.    
    147.     goto    sensorPollLoop
    148.    
    149.     end
    I would greatly appreciate it if you could have a look through and see if there's anything obvious that I'm missing. I have verified that the signal is arriving nicely at the pin, and I've even manually applied high/low voltages to the pin, to no avail.

    This is the first time I've used a hardware interrupt, I've only used TMR overflows before, so I may well have left out some obvious step.

    Just for reference: The program constantly alternates between lighting two IREDs, and the interrupt should fire when a detector receives signal from one of them.

    Thanks a lot,
    Barnaby
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,607
    Add the following into your init routine:

    bcf ANSELH,4

    Of course, check you are in the correct bank.

    RB0 shares function as an A2D analog input, and all inputs get power-on initialized to the analog function if it exists.
     
    Barnaby Walters likes this.
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,607
    BTW, that just makes the interrupt work, I did not check other I/Os for the same conflict.

    But I bet you will now. ;)
     
  4. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    You should keep this because the interrupt modifies W, and part of your main loop uses W.
    You wouldn't want the interrupt to occur between these lines if it didn't do context saving.
    movlw d'2'
    movwf tmr2
     
    Barnaby Walters likes this.
  5. Barnaby Walters

    Thread Starter Member

    Mar 2, 2011
    103
    4
    Hello,

    Thanks for the help — Mark you are absolutely right, I had forgotten that I was changing the wreg in my ISR. It seems to be a good idea to include it anyway.

    Ernie — The interrupt fired perfectly after I added in your line! When I was debugging the code, I read through the datasheet pretty thoroughly, and saw no mention of the fact that selecting RB0 as a AD channel was needed for the interrupt to work. How did you you know that it was needed?

    Thanks a lot,
    Barnaby
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,607
    Well... I should have thought of it first,as it is a common problem everyone runs into constantly. I myself spent have spent many bad days wondering why my I/O lines were not working only to remember the analog functions.

    But this hasn't happened to me since.... last Wednesday.

    Some of the data sheets put together all the resisters that can affect the I/O lines, so when you see the ANSEL in there you know to worry. Not all do. The PIC32 sheets may be the worst, only way I've found is to check the pin functions at the front of the data sheet and look each one up.

    But I missed all of that to find yours. You posted the entire asm file, so I just wizzed my way into a fresh MPLAB project and pasted your code into it, then built it. That took a minute or two. Then open a Stimulus workbook to simulate hitting RB0. When I attempted to change RB the SIM tab told me:

    (5960) SIM-N0001 Note: Asynchronous Stimulus Toggle RB0 fired.
    IOPORT-W0001: Pin(s) (0x01) on PORTB can not be stimulated due to being controlled by the A/D converter

    It was pretty obvious from that. ;)
     
Loading...