Pic16f877a rb0 interrupt is not working

Thread Starter

hjeij2000

Joined Jan 8, 2022
2
Hello, I have a problem with my pic16f877a.
It is working absolutely fine with quartus But whenever i try to build the circuit on the breadboard the rb0 interrupt does not work and i am sure everything is connected right( Vdd, Vss, Oscillators , pin1……)
A51EEF70-F3AE-42A7-BD31-BA59B584250D.jpeg
The code:

Code:
#include "P16F877A.INC"


cblock        0x20  
    temp
    tempp
    tempph ;temporary register to store the highest 2 bits of the potentiometer
    temppl ;temporary register to store the lowest 8 bits of the potentiometer
    tempequal ;counter to check if equal
    temph
    templp  
    temphp
    templ1 ;temporary register to store the lowest 8 digital bits inside the first LDR
    temph1 ;temporary register to store the highest 2 digital bits inside the first LDR
    templ2 ;temporary register to store the lowest 8 digital bits inside the second LDR
    temph2 ;temporary register to store the highest 2 digital bits inside the second LDR
    templ3 ;temporary register to store the lowest 8 digital bits inside the third LDR
    temph3 ;temporary register to store the highest 2 digital bits inside the third LDR
    templ4 ;temporary register to store the lowest 8 digital bits inside the fourth LDR
    temph4 ;temporary register to store the highest 2 digital bits inside the fourth LDR
    flag1
    flag2
    flag3
    flag4
    counter
    onepres ;to direct to the first LDR incase it holds the highest value
    twopres ;to direct to the second LDR incase it holds the highest value
    threepres ;to direct to the third LDR incase it holds the highest value
    fourpres ;to direct to the fourth LDR incase it holds the highest value
    TMRCNT
    search_hold_counter ;to determine the mode of operation based on the value inside this register. 0x00 Hold 0xFF Search
    delay_counter
    timer125
    track1
    counterequalreg ;counter to detect if equal value is present upon comparisin. Incase there is a highest value this counter turns zero
    counterhighestreg
    cnt1
    cnt2
    cnt3
    cnt4
endc



    ORG 0X000
    GOTO main
    ORG 0X004
    GOTO isr

;*
initial
    BANKSEL    TRISD
    CLRF    TRISD        ;PORTD & PORTB( bit 1-7) as outputs , PORTB(bit 0) as input
    MOVLW    b'00000001'
    MOVWF    TRISB
    MOVLW    b'00000111'
    MOVWF    TRISE
    MOVLW    b'00101110'
    MOVWF    TRISA
    BANKSEL INTCON      
    BSF        INTCON, GIE    ;Enable global Interrupts
    BSF     INTCON, INTE;rb0 interrupt
    BCF     INTCON, INTF;internal flag clear
    MOVLW    0XD3
    BANKSEL    OPTION_REG     ;PSA assigned to TMR0, Prescalar = 16, TMR0 clock source
                           ;is the internal
    MOVWF   OPTION_REG     ;instruction cycle clock, External interrupt is on the
                           ;rising egde         
    BANKSEL search_hold_counter
    CLRF    search_hold_counter ;clear the counter that test for search/hold, this counter would be filled with 0xFF and would be complemented each time the button is pressed
return

;**
isr  
    BCF        INTCON, T0IE    ;This was causing a problem when pressing the button so we added it here
    BTFSC    INTCON, INTF    ;External interrupt has highest priority - tests where the interrupt is coming from
    goto    search_hold    ;if the interrupt is from the button, goto search_hold, if not, just return
    RETFIE

;*
main  
        CALL    initial
mainloop
        goto    hold
start
        MOVLW   88H    ;10001000         
          MOVWF   ADCON1 ;define all pins analog and vref- & vref+ (see adcon1 reg)        
          Banksel PORTA      ;BANK 0
        CALL    adc
retest       
        CALL    compareWithP    ;are all above p?
        bcf        STATUS,Z        ;clear status
        movf    counter,1        ;test the counter result from compareWithP, update status
        btfsc    STATUS,Z        ;test value in the counter
        CALL    loading            ;if counter is zero, then all values are below threshold, so go to loading screen
        CALL    comparehighest    ;compares the highest value between LDR's and fills a counter that we can test later to see if there are equal values above threshold
        btfsc    counterequalreg,0;this is the counter that we test to see if there are any equal values above threshold
        goto    outequal        ;if the counter bit zero is set, it means that more than one value is equal and above threshold -> display '8'
        goto    masterdisplay    ;if there are no equal values above threshold, go to the master display subroutine to display highest value
        CALL    delay
          GOTO    start          ;Do it again
;**
search_hold        ;this is the search/hold code. we come here only when an external interrupt happens. Every time we complement a counter so one time we hold the other we start, one time we hold the other we start, etc.
    BCF        INTCON, INTF            ;Clear the rb0 flag
    BSF        INTCON, GIE                ;set the global interrtupt enable
    CLRF    PORTB    ;turn off any soungs
    CLRF    PORTD    ;turn off display
    COMF    search_hold_counter,1    ; Toggle the state of the search/hold
    btfsc    search_hold_counter,1
    goto    start   
    goto    hold
Return
;*
hold    ;this is the hold code, it will stay in this infinite loop until an interrupt happens
    movlw    b'11110110'         ;Infinte loop until the push butoon is pressed
    movwf    PORTD        ;put the letter H in portd
rep
    nop
    goto    rep

;**
comparehighest ;in this code, we test for the highest value between all four LDR's, we also fill a counter if we have two equal values AND above the threshold so we can test it later when we return from the subroutine

    movlw    0x00
    movwf    counterequalreg
    movwf    tempp ;this is a temporary value
    movwf    tempph    ;this is a temporary high value
    movwf    temppl    ;this is a temporary low value
                    ;we use the tempph and temppl values to save the low and high values of the higheset LDR so we can test them later when we want to display them

compare12H ;we are comparing the high values of LDR1 & LDR2
        bcf        STATUS,C ;in case there is a previous value in status
        movf    temph1,0
        subwf    temph2,0 ;H2-H1
        btfsc    STATUS,Z ;test Z
        goto    comp12L ;if zero, go test low bits
        btfss    STATUS,C ;if its not zero, compare carry
        goto    takeone ;if there is carry, take LDR1
        goto    taketwo ;if there is no carry, take LDR2
      
comp12L ;if the high values are equal, we come here to compare the low values of LDR 1 & 2
        bcf        STATUS,C ;again, in case
        movf    templ1,0
        subwf    templ2,0 ;L2-L1
        btfsc    STATUS,Z ;test if zero
        goto    equalcounter12
        btfss    STATUS,C ;if not zero, test carry
        goto    takeone ;if there is carry, take LDR1
        goto    taketwo ;if there is no carry, take LDR2

equalcounter12 ;tests if counter 1&2 are equal
        movlw 0xFF
        movwf counterequalreg
        goto  taketwoequal


takeone ;takes one if it is higher
        movf    temph1,0
        movwf    tempph ;save H1 on tempH
        movf    templ1,0
        movwf    temppl ;save L1 on tempL
        incf    counterhighestreg
        goto    comparePrev3H
taketwo ;takes two if it is higher
        movf    temph2,0
        movwf    tempph ;save H2 on tempH
        movf    templ2,0
        movwf    temppl ;save L2 on tempL
        incf    counterhighestreg
        goto    comparePrev3H
taketwoequal ;if both values are equal, we can save any, it won't matter
        movf    temph2,0
        movwf    tempph ;save H2 on tempH
        movf    templ2,0
        movwf    temppl ;save L2 on tempL
        goto    comparePrev3H
  
  
comparePrev3H ;compare the highest value between the last comparision, with LDR 3, and repeat the same process
        bcf        STATUS,C
        movf    tempph,0
        subwf    temph3,0
        btfsc    STATUS,Z
        goto    compPrev3L
        btfsc    STATUS,C
        goto    takethree
        goto    takeold
      
compPrev3L
        bcf        STATUS,C
        movf    temppl,0
        subwf    templ3,0
        btfsc    STATUS,Z
        goto    equalcounter13
        btfsc    STATUS,C
        goto    takethree
        goto    takeold

equalcounter13
        movlw 0xFF
        movwf counterequalreg
        goto  takeold

  
takethree
        movf    temph3,0
        movwf    tempph
        movf    templ3,0
        movwf    temppl
        clrf    counterequalreg
        incf    counterhighestreg
        goto    comparePrev4H
  
takeold;if the prevous values are larger, don't take LDR3, do nothing
;no need to do anything, old value already in tempph,temppl  
  

comparePrev4H ;compare the highest value till now with LDR4, adn repeat the same processs
        bcf        STATUS,C
        movf    tempph,0
        subwf    temph4,0
        btfsc    STATUS,Z
        goto    compPrev4L
        btfsc    STATUS,C
        goto    takefour
        goto    takenewold
      
compPrev4L
        bcf        STATUS,C
        movf    temppl,0
        subwf    templ4,0
        btfsc    STATUS,Z
        goto    equalcounter14
        btfsc    STATUS,C
        goto    takefour
        goto    takenewold

equalcounter14
        movlw 0xFF
        movwf counterequalreg
        goto  takenewold

takefour
        movf    temph4,0
        movwf    tempph
        movf    templ4,0
        movwf    temppl
        clrf    counterequalreg
        incf    counterhighestreg
        goto    comparisondone
  
takenewold
        ;also no need to do anything  
  



comparisondone

return
      

;*
loading ;this is the loading code, how it works is the following, after each dash, we add a delay of a randome time we chose on the delay_long subroutine, then we test again by doing the conversion and testing if the LDR's are higher than the threshold. If not, we stay inside the loading code, if one became higher, we go and test to see which one is higher

        banksel TRISD
        clrf TRISD ;make portd outpout
        banksel PORTD
  
    search
  
    movlw B'00000001' ;choose first 7seg dash
    movwf PORTD            ;display on portD
    CALL    delay_long    ;longer delay
        call    retest_adc     ;retest, we are using another subrouting (not the same one as in the main subroutine), since we need this to be independent. Using the one in the main will keep restarting the loading screen and we would only see the first loading dash, since every time it's repeating the testing and going to the loading subrouting and displaying only the first dahs
        bcf        STATUS,Z ;in case clear status
        movf    counter,1 ;test counter again
        btfss    STATUS,Z ;skip if all are below zero
        goto    endloading ;if counter is not zero, exit loading
  
    movlw B'00000010'
    movwf PORTD
    CALL    delay_long
        call    retest_adc
        bcf        STATUS,Z
        movf    counter,1
        btfss    STATUS,Z
        goto    endloading
  
    movlw B'00000100'
    movwf PORTD
    CALL    delay_long
        call    retest_adc
        bcf        STATUS,Z
        movf    counter,1
        btfss    STATUS,Z
        goto    endloading
  
    movlw B'00001000'
    movwf PORTD
    CALL    delay_long
        call    retest_adc
        bcf        STATUS,Z
        movf    counter,1
        btfss    STATUS,Z
        goto    endloading
  
    movlw B'00010000'
    movwf PORTD
    CALL    delay_long
        call    retest_adc
        bcf        STATUS,Z
        movf    counter,1
        btfss    STATUS,Z
        goto    endloading
  
    movlw B'00100000'
    movwf PORTD
    CALL    delay_long
        call    retest_adc
        bcf        STATUS,Z
        movf    counter,1
        btfss    STATUS,Z
        goto    endloading
  
        goto search
  
    endloading

return

;**
retest_adc ; this is used to continuously test the input values for the loading subroutine

    MOVLW   88H             
      MOVWF   ADCON1         
      Banksel PORTA               ;BANK 0
    CALL    adc
    CALL    compareWithP

return

;*
compareWithP ;here we compare all values with the threshold to see if all are lower, we do this by defining a counter and putting in it the value 4. every time we find a value that is lower than the threshold, we decrease the counter. If all values are lower than the threshold, the counter will have a zero inside it. We can test this when we go out of the subroutine

        movlw    .4
        movwf    counter ;this is the counter mentioned earlier

                    ;we test each value with by by comparing the high values, if they are equal, we move to comparing the low values.
    compare1p
        movf    temphp,0
        subwf    temph1,0 ;H1-Hp
        btfsc    STATUS,Z ;test if zero
        goto    compl1 ;if zero, goto compare low 1
        btfsc    STATUS,C ;test carry
        goto    final1    ;if there is carry, then P is larger than 1, so
        decf    counter,1 ;decrease the counter
        goto    final1
      
    compl1
        movf    templp,0 ;low potentiometer
        subwf    templ1,0 ;L1-LP
        btfsc    STATUS,C ;test carry
        goto    final1 ;if no carry
        decf    counter,1 ;if carry, decrease the counter
      
    final1
        movwf    onepres; save value in onePres, this is not used, just a temporary value
;repeat  
    compare2p
        movf    temphp,0
        subwf    temph2,0
        btfsc    STATUS,Z
        goto    compl2
        btfsc    STATUS,C
        goto    final2
        decf    counter,1
        goto    final2
      
    compl2
        movf    templp,0
        subwf    templ2,0
        btfsc    STATUS,C
        goto    final2
        decf    counter,1
      
    final2
        movwf    twopres    ;just a temporary value
;repeat
    compare3p
        movf    temphp,0
        subwf    temph3,0
        btfsc    STATUS,Z
        goto    compl3
        btfsc    STATUS,C
        goto    final3
        decf    counter,1
        goto    final3
      
    compl3
        movf    templp,0
        subwf    templ3,0
        btfsc    STATUS,C
        goto    final3
        decf    counter,1
      
    final3
        movwf    threepres    ;just a temporary value
;repeat
    compare4p
        movf    temphp,0
        subwf    temph4,0
        btfsc    STATUS,Z
        goto    compl4
        btfsc    STATUS,C
        goto    final4
        decf    counter,1
        goto    final4
      
    compl4
        movf    templp,0
        subwf    templ4,0
        btfsc    STATUS,C
        goto    final4
        decf    counter,1
      
    final4
        movwf    fourpres     ;just a temporary value

return

;**
adc
    adcp
        MOVLW     09H ;00001001 choose AN1 input (see adcon0 reg)
        MOVWF     ADCON0 ;move values to adcon0
        CALL      delay
        BSF       ADCON0,GO    ;start conversion
    waitp
          BTFSS     PIR1,ADIF     ;keep testing the ADIF flag until the conversion is complete
          GOTO      waitp
        bcf          PIR1, ADIF    ;clear ADIF when conversion is done
        Banksel   TRISA
          MOVF     ADRESL,W
        Banksel   PORTA
        MOVWF     templp    ;save adresl to temp register             
        MOVF    ADRESH,W
        MOVWF    temphp        ;save adresh to temp register
  
    adc1                    ;choose an4
        MOVLW     21H
        MOVWF     ADCON0
        CALL      delay
        BSF       ADCON0,GO
    wait1
          BTFSS     PIR1,ADIF
          GOTO      wait1
        bcf          PIR1, ADIF
        Banksel   TRISA
          MOVF     ADRESL,W
        Banksel   PORTA
        MOVWF     templ1             
        MOVF    ADRESH,W
        MOVWF    temph1
  
    adc2                    ;choose an5
        MOVLW     29H
        MOVWF     ADCON0
        CALL      delay
        BSF       ADCON0,GO
    wait2
          BTFSS     PIR1,ADIF
          GOTO      wait2
        bcf          PIR1, ADIF
        Banksel   TRISA
          MOVF     ADRESL,W
        Banksel   PORTA
        MOVWF     templ2             
        MOVF    ADRESH,W
        MOVWF    temph2
  
    adc3                    ;choose an6
        MOVLW     31H
        MOVWF     ADCON0
        CALL      delay
        BSF       ADCON0,GO
    wait3
          BTFSS     PIR1,ADIF
          GOTO      wait3
        bcf          PIR1, ADIF
        Banksel   TRISA
          MOVF     ADRESL,W
        Banksel   PORTA
        MOVWF     templ3             
        MOVF    ADRESH,W
        MOVWF    temph3
  
    adc4                    ;choose an7
        MOVLW     39H
        MOVWF     ADCON0
        CALL      delay
        BSF       ADCON0,GO
    wait4
          BTFSS     PIR1,ADIF
          GOTO      wait4
        bcf          PIR1, ADIF
        Banksel   TRISA
          MOVF     ADRESL,W
        Banksel   PORTA
        MOVWF     templ4             
        MOVF    ADRESH,W
        MOVWF    temph4

return

;**
masterdisplay
        movlw    .30
        movwf    timer125

        clrf    cnt1    ;to use as a counter
        movf    tempph,0; move highest high to working register to copamre
        subwf    temph1,0;subtract the highest high from ADRESH of LDR1 to check if equal
        btfsc    STATUS,Z;to check if the ADRESH of LDR1 equals to the highest measered high of LDR1
        incf    cnt1; increase counter
        movf    temppl,0; move highest low on working register to compare
        subwf    templ1,0
        btfsc    STATUS,Z;to check if the ADRESL of LDR1 equals to the highest measered low
        incf    cnt1; increase counter
        btfsc    cnt1,1; afetr increasing on high and low we are know sure that LDR1 is the highest measured
        goto    out1;
      
        clrf     cnt2; same as above
        movf    tempph,0
        subwf    temph2,0
        btfsc    STATUS,Z
        incf    cnt2
        movf    temppl,0
        subwf    templ2,0
        btfsc    STATUS,Z
        incf    cnt2
        btfsc    cnt2,1
        goto    out2

        clrf    cnt3; same as above
        movf    tempph,0
        subwf    temph3,0
        btfsc    STATUS,Z
        incf    cnt3
        movf    temppl,0
        subwf    templ3,0
        btfsc    STATUS,Z
        incf    cnt3
        btfsc    cnt3,1
        goto    out3

        clrf    cnt4; same as above
        movf    tempph,0
        subwf    temph4,0
        btfsc    STATUS,Z
        incf    cnt4
        movf    temppl,0
        subwf    templ4,0
        btfsc    STATUS,Z
        incf    cnt4
        btfsc    cnt4,1
        goto    out4

        goto    start
outequal
    MOVLW    B'11111111'
    MOVWF    PORTD
    clrf    track1 ;this is to clear the counter that tests if we are on one of the values so we don't get a sound twice in a row for one value

    GOTO    start

out1
speaker1
    bcf        track1,3
    bcf        track1,4
    bcf        track1,2
    MOVLW    B'10000110'
    MOVWF    PORTD  
    btfsc    track1,1;this is a counter we use so we don't output the sound twice in a row if the highest value didn't change
    goto    start
    MOVLW    .81 ;each delay is 154.4micro seconds long, in the out1 code, we use it twice every time, so we multiply it by 81 to get around 0.5 seconds
    MOVWF    delay_counter      
start1  
    BSF     PORTB,RB1 ;to generate a square periodic wave with deferent frequencies
    bsf        track1,1
    Call delay ;here we use the delay twice to generate a square wave. we do the same with out 2,3,4 but we use the delay more times to get other sounds
    BCF        PORTB,RB1
    Call delay
    decfsz delay_counter
    GOTO    start1
    goto start

out2
speaker2
    bcf        track1,1
    bcf        track1,3
    bcf        track1,4

    MOVLW    B'11011011'
    MOVWF    PORTD
    btfsc    track1,2
    goto    start
    MOVLW    .40 ;each delay is 154.4micro seconds long, in the out2 code, we use it four times every time, so we multiply it by 40 to get around 0.5 seconds
    MOVWF    delay_counter
start2
    BSF        PORTB,RB1
    bsf        track1,2
    Call delay
    Call delay
    BCF        PORTB,RB1
    Call delay
    Call delay
    decfsz delay_counter
    GOTO start2
    goto start

out3
speaker3
    bcf        track1,1
    bcf        track1,4
    bcf        track1,2

    MOVLW    B'11001111'
    MOVWF    PORTD
    btfsc    track1,3
    goto    start
    MOVLW    .27 ;each delay is 154.4micro seconds long, in the out3 code, we use it six times every time, so we multiply it by 27 to get around 0.5 seconds
    MOVWF    delay_counter
start3
    BSF PORTB,RB1
    bsf    track1,3
    Call delay
    Call delay
    Call delay
    BCF PORTB,RB1
    Call delay
    Call delay
    Call delay
    decfsz delay_counter
    GOTO start3
    goto start
out4
speaker4
    bcf        track1,1
    bcf        track1,3
    bcf        track1,2

    MOVLW    B'11100110'
    MOVWF    PORTD
    btfsc    track1,4
    goto    start
    MOVLW    .20 ;each delay is 154.4micro seconds long, in the out4 code, we use it eight times every time, so we multiply it by 20 to get around 0.5 seconds
    MOVWF    delay_counter
start4
    BSF PORTB,RB1
    bsf    track1,4
    Call delay
    Call delay
    Call delay
    Call delay
    BCF PORTB,RB1
    Call delay
    Call delay
    Call delay
    Call delay
    decfsz delay_counter
    GOTO start4
    goto start

return
;**
delay
      MOVLW    0xFF
      MOVWF    temp
L1     DECFSZ   temp,1
      GOTO     L1
      RETURN

delay_long
    MOVLW    0X2F            ;specify counter value (times we want to repeat the normal delay), this is an assumption that the delay is repeated 2F times
    MOVWF    delay_counter
repeat_delay
    Call    delay            ;keep calling normal delay until counter is zero
    decfsz    delay_counter
    goto    repeat_delay
return

;*

end
MOD EDIT: code tags-JohnInTX
 
Last edited by a moderator:

djsfantasi

Joined Apr 11, 2010
9,163
Please learn to use code tags. By clicking on the ellipsis icon, you’ll find a code selection. Click on it and it will insert code tags. Paste your code between the ][ in the tags.
 

JohnInTX

Joined Jun 26, 2012
4,787
@hjeij2000
The way you are using the interrupt will cause stack overflow, likely on the first button press as it bounces.

You GOTO search_hold from the interrupt routine, do some things then GOTO back to the main loop. That never pops the stack from the interrupt and on the next interrupt, the stack will be pushed again. That may work on the simulator but not on the chip. The chip will overflow the stack.
Treat ANY interrupt routine as a hardware generated CALL. You must return from that 'call' at one and only one point via RETFIE to keep the stack in order.
You are enabling GIE in that extended interrupt routine. You can't do that. After an interrupt, the ONLY way to finish the service routine is with RETFIE.
You don't save any context during the interrupt. That probably is not an issue here since you are using the interrupt to sense the switch but is a bad practice.
Your use of the interrupt as a switch sensor is a common mistake. Mechanical switches bounce and that means multiple interrupts per press. A better method is to poll the switch using a timer interrupt, debounce it, then post the result in a flag that the main (non-interrupt) code can sample as it needs to.

As written, it is not going to work on a real chip regardless of what the sim says.
I didn't go any further.

Good luck and welcome to AAC!
 
Last edited:
Top