Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

RB port change interrupt problem

Status
Not open for further replies.

krpz

New Member
i want to enable a RB on port change interrupt, (i have a keypad connected in RB0-RP7 ports)
the project displays a message in first line of a LCD display and after the interrupt enabled from a key pressed on a keypad a new message will be displayed in the second line. my problem is that i make probably something wrong and the interrupt doesnt work.

my code (subroutines for lcd initialization and display message are tested and the messages are displayed on the screen but my problem is that when i press any key no message in the second line occurs and i think my interrupt is wrong coded) :

edit: NEW CODE POSTED BUT INTERRUPT STILL DOESNT WORK
keypad is connects to portb
i use internal pull ups
also pin1,3,5 --> column0,1,2 is connected to 5V through 10K resistors

Code:
List p=pic16f877 
include "P16F877.INC" 
__CONFIG _CP_OFF & _WDT_OFF &_BODEN_OFF & _PWRTE_ON & _HS_OSC & _WDT_OFF & _LVP_OFF & _CPD_OFF 
ERRORLEVEL -302 
 
 
#define E_line 0            ;from wiring  
#define RS_line 1            ;   -//- 
#define RW_line 2            ;   -//-         
#define rbif 0 
#define rbie 3 
#define gie 7 
 
cblock 0x20 
delay_counter1 
delay_counter2 
temp                            ;variable store 8-bit data to send to LCD 
GPR1 
wtemp 
pclathtemp 
statustemp 
endc 
 
status equ 0x03 
portd equ 0x08 
porte equ 0x09 
portb equ 0x06 
porta equ 0x05 
portc equ 0x07 
intcon equ 0x0B 
 
 
org 0h 
goto portIni 
org 04h         ;interrupt vector 
goto isr 
 
 
 
;               PORTS INITIALIZATION 
;WIRING: 
;     PortD                 PortE             PortB 
; 0 --> lcd bus 0        0 --> lcd RS        0 --> keypad row0 
; 1 --> lcd bus 1        1 --> lcd E            1 --> keypad row1 
; 2 --> lcd bus 2       2 --> lcd R/W        2 --> keypad row2 
; 3 --> lcd bus 3                             3 --> keypad row3 
; 4 --> lcd bus 4                            4 --> not used 
; 5 --> lcd bus 5                            5 --> keypad column0 
; 6 --> lcd bus 6                            6 --> keypad column1 
; 7 --> lcd bus 7                            7 --> keypad column2 
 
 
 
portIni 
 
    banksel porta 
    CLRF    PORTA               
    CLRF    PORTB                
    CLRF     PORTE 
    CLRF    PORTD 
 
    banksel  TRISB 
    movlw     b'00000111' 
    movwf     TRISB 
 
    banksel TRISD 
    MOVLW   B'00000000'          
    MOVWF   TRISD                
    MOVWF    TRISE 
 
    banksel OPTION_REG 
    movlw     b'00001000' 
    movwf     OPTION_REG 
 
    banksel ADCON1 
    MOVLW   0X06         
    MOVWF     ADCON1 
    MOVLW     0xCF 
    MOVWF     TRISA 
 
 
 
    BCF     STATUS,RP0          ; Bank 0 
    BCF     STATUS,RP1          ; Bank 0
 
main 
call initializeLCD 
call display_initial_message 
 
 
;initialise interrupt 
    banksel portb 
    clrf portb 
    banksel intcon 
    bcf intcon,rbif 
    bsf intcon,rbie 
    bsf intcon,gie 
    banksel OPTION_REG 
    bcf OPTION_REG,7    ;RBPU: 0=portb pull ups are enabled 
     
loop goto loop 
 
isr  
    ;saving registers 
    movwf wtemp 
    banksel status 
    swapf status,w 
    clrf status 
    movwf statustemp 
    banksel PCLATH 
    movf PCLATH,w 
    movwf pclathtemp 
    clrf PCLATH 
 
 
    banksel intcon 
    btfsc intcon,rbif 
    goto routine     
    goto isrend 
     
routine 
    banksel lcd_line2 
    call lcd_line2 
    banksel clearLCD 
    call clearLCD 
    banksel display_initial_message 
    call display_initial_message 
     
    banksel intcon 
    bcf intcon,rbif 
    bsf intcon, rbie 
 
    ;restore registers 
    movf pclathtemp,w 
    banksel PCLATH 
    movwf PCLATH 
    swapf statustemp,w 
    banksel status 
    movwf status 
    swapf wtemp,f 
    swapf wtemp,w 
 
isrend 
    retfie 
 
 
 
 
initializeLCD 
        call delay_20ms                ;Wait 20ms for LCD to power up 
        bsf porte,E_line                   ;enable bit is high 
        bcf porte,RS_line                ; RS is set for command mode 
        bcf porte,RW_line             ; RW is set for write mode 
        call delay_1ms 
 
        movlw b'00111000'            ;8bit data, 2 lines, 5x8 character 
        MOVWF   portd                   ; Move Working Register to PORTB 
        CALL    toggle_E                    ; Enter 
        CALL    delay_1ms 
 
        movlw b'00001100'           ; Display On, Cursor Underline Off, Blink Off 
        MOVWF   portd                  
        CALL    toggle_E                    ; Enter 
        CALL    delay_1ms 
 
        movwf b'00000110'            ; cursor auto increment right, shift off 
        MOVWF   portd                    
        CALL    toggle_E                    ; Enter 
        CALL    delay_1ms 
 
        movwf b'00000001'            ;clear display 
        MOVWF   portd                    
        CALL    toggle_E                     ; Enter         
        CALL    delay_1ms 
        BSF     porte, RS_line           ; LCD in Character mode 
        return 
 
clearLCD 
        BCF     porte, RS_line             ; LCD in Command mode 
        MOVLW   B'00000001'         ; Command: Clear Display 
        MOVWF   portd                     ; Move Working Register to PORTB 
        CALL    toggle_E                      ; Enter 
        CALL    delay_1ms 
        BSF     porte, RS_line           ; LCD in Character mode 
        RETURN 
 
toggle_E 
        bcf porte,E_line         ;data is enter on the falling edge  
        call delay_1ms  
        bsf porte,E_line         ;E_line ready for the next data string 
return  
 
 
lcd_line2 
        bcf porte,RS_line 
        movlw b'11000000' 
        movwf portd 
        call toggle_E 
        call delay_1ms 
        bsf porte, RS_line 
        return 
 
 
;lcd display initial message  
 
display_initial_message 
        movlw d'0'                        ;table line to start printing from  
        movwf GPR1 
        call display_message 
        return 
         
         
;routine for displaying characters on the lcd 
display_message 
        movf GPR1,w 
        call message_table 
        movwf portd 
        xorlw b'00000000' 
        btfsc status,2 
        goto $+5 
        call toggle_E 
        call delay_1ms 
        incf GPR1 
        goto display_message 
        return 
 
 
message_table 
        addwf PCL,f 
 
        retlw    A'h'    ;0 
        retlw   A'e'    ;1 
        retlw    A'l'    ;3     
        retlw    A'l'    ;4 
        retlw    A'o'    ;5 
        retlw    A' '    ;6 
        retlw    A'w'    ;7 
        retlw    A'o'    ;8 
        retlw    A'r'    ;9 
        retlw    A'l'    ;10 
        retlw    A'd'    ;11 
        retlw    H'0'    ;12 
 

;   Delay Routines 
;4MHz clock frequency 
 
delay_1ms                             
        movlw 0xc6                     
        movwf delay_counter1 
        movlw 0x01                   
        movwf delay_counter2 
delay_1ms_0 
        decfsz delay_counter1, f     
        goto $+2                     
        decfsz delay_counter2, f     
        goto delay_1ms_0                 
        goto $+1                     
        nop                         
        return                         
 
 
delay_20ms                         
        movlw 0x9e 
        movwf delay_counter1 
        movlw 0x10 
        movwf delay_counter2 
delay_20ms_0 
        decfsz delay_counter1,f 
        goto $+2 
        decfsz delay_counter2,f 
        goto delay_20ms_0                 
        goto $+1                     
        nop                         
        return                     
 
 
 
 
stop 
    goto stop 
end
 
Last edited:
3.4.3 INTERRUPT-ON-CHANGE
All of the PORTB pins are individually configurable as an
interrupt-on-change pin. Control bits IOCB<7:0> enable
or disable the interrupt function for each pin. Refer to
Register 3-8. The interrupt-on-change feature is
disabled on a Power-on Reset.
 
3.4.3 INTERRUPT-ON-CHANGE
All of the PORTB pins are individually configurable as an
interrupt-on-change pin. Control bits IOCB<7:0> enable
or disable the interrupt function for each pin. Refer to
Register 3-8. The interrupt-on-change feature is
disabled on a Power-on Reset.

Yes , but i think i dont have Power-on-Reset enabled, in my configuration bits i have _PWRTE_ON (Power-up Timer), correct me if i am wrong
 
Last edited:
;initialise interrupt
banksel portb
clrf portb

I only know assembly, but shouldn't all these be in capitol letters? if not, you're won't get the correct banks?
 
Hello krpz.....

Quite a few things to note..
A) there is no need to define all the registers and register bits as you include the "p16f877.inc" which has them all in (and as Joe kindly explained they are in uppercase)..
B) You cannot initialise your LCD like this.. I have made a change there!!
C) You cannot clear the RBIF flag manually... You have to read PORTB!!
D) You had the OSC set for HS.... With a 4mhz you must set it to XT.
E) you have specified the wiring as RS = 0, E = 1 and RW = 2 but set it as E = 0, RS = 1 and RW = 2.
F) the E line should be low for Idle..

Code:
List p=pic16f877 
include "P16F877.INC" 
__CONFIG _CP_OFF & _WDT_OFF &_BODEN_OFF & _PWRTE_ON & _XT_OSC & _WDT_OFF & _LVP_OFF & _CPD_OFF 
ERRORLEVEL -302 
 
 
#define E_line 0            ;from wiring  
#define RS_line 1            ;   -//- 
#define RW_line 2            ;   -//-         

 
cblock 0x20 
delay_counter1 
delay_counter2 
temp                            ;variable store 8-bit data to send to LCD 
GPR1 
wtemp 
pclathtemp 
STATUStemp 
endc 
 
 
 
org 0h 
goto portIni 
org 04h         ;interrupt vector 
goto isr 
 
 
 
;               PORTS INITIALIZATION 
;WIRING: 
;     PORTD                 PORTE             PORTB 
; 0 --> lcd bus 0        0 --> lcd RS        0 --> keypad row0 
; 1 --> lcd bus 1        1 --> lcd E            1 --> keypad row1 
; 2 --> lcd bus 2       2 --> lcd R/W        2 --> keypad row2 
; 3 --> lcd bus 3                             3 --> keypad row3 
; 4 --> lcd bus 4                            4 --> not used 
; 5 --> lcd bus 5                            5 --> keypad column0 
; 6 --> lcd bus 6                            6 --> keypad column1 
; 7 --> lcd bus 7                            7 --> keypad column2 
  
portIni 
 
    banksel PORTA
    CLRF    PORTA               
    CLRF    PORTB                
    CLRF    PORTE 
    CLRF    PORTD 
 
    banksel  TRISB 
    movlw     b'11110000' 
    movwf     TRISB 
 
    banksel TRISD 
    MOVLW   B'00000000'          
    MOVWF   TRISD                
    MOVWF    TRISE 
 
    banksel OPTION_REG 
    movlw     b'11000000' 
    movwf     OPTION_REG 
 
    banksel ADCON1 
    MOVLW   0X06         
    MOVWF     ADCON1 
    MOVLW     0xCF 
    MOVWF     TRISA 
 
    BCF     STATUS,RP0          ; Bank 0 
    BCF     STATUS,RP1          ; Bank 0
 
main 
call initializeLCD 
call display_initial_message 
  
;initialise interrupt 
    banksel PORTB 
    clrf PORTB 
    bcf INTCON,RBIF 
    bsf INTCON,RBIE 
    bsf INTCON,GIE 
    banksel OPTION_REG 
    bcf OPTION_REG,7    ;RBPU: 0=PORTB pull ups are enabled 
 
loop goto loop 
 
isr  
    ;saving registers 

    movwf wtemp 
    banksel STATUS 
    swapf STATUS,w 
    clrf STATUS 
    movwf STATUStemp 
    banksel PCLATH 
    movf PCLATH,w 
    movwf pclathtemp 
    clrf PCLATH 
    btfsc INTCON,RBIF   
    goto routine     
    goto isrend 
 
routine 
    call lcd_line2 
    call clearLCD 
    call display_initial_message 
    ;restore registers 
    movf  PORTB,w
    movf pclathtemp,w 
    banksel PCLATH 
    movwf PCLATH 
    swapf STATUStemp,w 
    banksel STATUS 
    movwf STATUS 
    swapf wtemp,f 
    swapf wtemp,w 
 
isrend
    clrf INTCON		; for some reason the TMR0IE is bieng set
    bsf  INTCON,RBIE 	; so I disabled it here
    retfie 
  
initializeLCD 
	bcf PORTE,E_line                   ;enable bit is high 
        bcf PORTE,RS_line                ; RS is set for command mode 
        bcf PORTE,RW_line             ; RW is set for write mode
        call delay_20ms                ;Wait 20ms for LCD to power up 
	movlw b'00110011'
	MOVWF   PORTD 
	CALL    toggle_E 
	call delay_20ms
	CALL    toggle_E
    	call delay_20ms
        movlw b'00111000'            ;8bit data, 2 lines, 5x8 character 
        MOVWF   PORTD                   ; Move Working Register to PORTB 
        CALL    toggle_E                    ; Enter 
        CALL    delay_1ms 
 
        movlw b'00001100'           ; Display On, Cursor Underline Off, Blink Off 
        MOVWF   PORTD                  
        CALL    toggle_E                    ; Enter 
        CALL    delay_1ms 
 
        movwf b'00000110'            ; cursor auto increment right, shift off 
        MOVWF   PORTD                    
        CALL    toggle_E                    ; Enter 
        CALL    delay_1ms 
 
        movwf b'00000001'            ;clear display 
        MOVWF   PORTD                    
        CALL    toggle_E                     ; Enter         
        CALL    delay_1ms 
        BSF     PORTE, RS_line           ; LCD in Character mode 
        return 
 
clearLCD 
        BCF     PORTE, RS_line             ; LCD in Command mode 
        MOVLW   B'00000001'         ; Command: Clear Display 
        MOVWF   PORTD                     ; Move Working Register to PORTB 
        CALL    toggle_E                      ; Enter 
        CALL    delay_1ms 
        BSF     PORTE, RS_line           ; LCD in Character mode 
        RETURN 
 
toggle_E 
        bsf PORTE,E_line         ;data is enter on the falling edge  
        call delay_1ms  
        bcf PORTE,E_line         ;E_line ready for the next data string 
return  
  
lcd_line2 
        bcf PORTE,RS_line 
        movlw b'11000000' 
        movwf PORTD 
        call toggle_E 
        call delay_1ms 
        bsf PORTE, RS_line 
        return 
  
;lcd display initial message  
 
display_initial_message 
        movlw d'0'                        ;table line to start printing from  
        movwf GPR1 
        call display_message 
        return 
  
;routine for displaying characters on the lcd 
display_message 
        movf GPR1,w 
        call message_table 
        movwf PORTD 
        xorlw b'00000000' 
        btfsc STATUS,2 
        goto $+5 
        call toggle_E 
        call delay_1ms 
        incf GPR1 
        goto display_message 
        return 
  
message_table 
        addwf PCL,f 
 
        retlw    A'h'    ;0 
        retlw    A'e'    ;1 
        retlw    A'l'    ;3     
        retlw    A'l'    ;4 
        retlw    A'o'    ;5 
        retlw    A' '    ;6 
        retlw    A'w'    ;7 
        retlw    A'o'    ;8 
        retlw    A'r'    ;9 
        retlw    A'l'    ;10 
        retlw    A'd'    ;11 
        retlw    H'0'    ;12 
 
 
;   Delay Routines 
;4MHz clock frequency 
 
delay_1ms                             
        movlw 0xc6                     
        movwf delay_counter1 
        movlw 0x01                   
        movwf delay_counter2 
delay_1ms_0 
        decfsz delay_counter1, f     
        goto $+2                     
        decfsz delay_counter2, f     
        goto delay_1ms_0                 
        goto $+1                     
        nop                         
        return                         
  
delay_20ms                         
        movlw 0x9e 
        movwf delay_counter1 
        movlw 0x10 
        movwf delay_counter2 
delay_20ms_0 
        decfsz delay_counter1,f 
        goto $+2 
        decfsz delay_counter2,f 
        goto delay_20ms_0                 
        goto $+1                     
        nop                         
        return                     
  
stop 
    goto stop 
end

One last thing... You don't need to banksel INTCON as it resides in all the banks..
 
Last edited:
It works!! thank you very very much!
Now i can enter into the world of interrupts :)

Two more questions if you can explain:

1. in your code at first you put:
Code:
   banksel OPTION_REG 
    movlw     b'11000000' 
    movwf     OPTION_REG
that disable pull-ups

and then when interrupt is initialized:
Code:
;initialise interrupt 
    banksel PORTB 
    clrf PORTB 
    bcf INTCON,RBIF 
    bsf INTCON,RBIE 
    bsf INTCON,GIE 
    banksel OPTION_REG 
    bcf OPTION_REG,7    ;RBPU: 0=PORTB pull ups are enabled

you make this on purpuse? in order the interrupt become functionable?


2. in LCD initialization what this part of code do:
Code:
initializeLCD 
	movlw b'00110011'
	MOVWF   PORTD

i cant find in the lcd datasheet

thanks in advance! you make my day!
 
Sorry the first was me messing with RBPU's control... And to see what intedge would do.... you can delete that line..

All Hitachi compatible LCD's must be initialized with 0x33 twice ( for 8 bit interface ) and 0x20 twice ( for 4 bit interface )...

My initialize routines contain..
wait 15mS
0x33
wait 5mS
0x33
wait 5mS

// the busy can now be checked..
Then function 0x38
Then Display , cursor, 0x0D
Then direction ,font, 0x06
Then clear, set home 0x01

Always works for me.

I've included my LCD pdf..
 
Last edited:
useful things to know about lcd display initialization.

in your above code i try to put another interrupt, in the first time i like to display a message1 for example and after this if you press another time a key lcd will display message2.

i think to add a variable (intcounter). first i give intcounter value 0x01 (in main before interrupt intialization), then inside isr after saving registers i put this code:
Code:
btfsc intcounter,0
goto int1
goto int2

int1
   btfsc INTCON,RBIF
   goto routine
   goto isrend

int2
   btfsc INTCON,RBIF
   goto routine2
   goto isrend

routine 2 will be the same with another message
i try to simulate but i take strange results, sometimes i am inside message1 subroutine and after a step out the programm send me inside inililizeLCD subroutine!!!

i think i have 2 things that i made mistake,
1. i need to put this code:
Code:
bansel PORTB
clrf PORTB
after isrend maybe???? or somewhere else???

2. my first routine contains this lines of code to change intcounter value
Code:
routine
   movf intcounter , w
   xorlw 0x01
   movwf intcounter
after this intcounter will have value= 0x00 , so in the second interrupt routine2 will be executed
but when i simulate after first interrupt intcounter have 0x01 value again....
 
Think twice about doing too much inside of an interrupt... The pic16f877 has only 8 stack positions.. The interrupt uses two positions.. The call to LCD routines requires 1, then nested are two calls to delay routines...

I tend to keep the interrupts as short as possible... I run everything in the super loop and flag the routines from the interrupt...
 
Your super loop is at the bottom of your interrupt init
Code:
 Loop  goto loop

If you expand:-

Code:
Loop
   btfsc IntFlags.1
   Call LCDRoutine1
   btfsc IntFlags.2
   Call LCDRoutine2
   ; etc...
   goto Loop

That means the code will only be executed IF the interrupt has been fired.. This will keep your interrupt nice and short.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top