I was working on my RFID reader project and needed to decode an ON-OFF Keying (OOK) modulated carrier. The analog section outputs logic levels, so the thing to do next was to decode this code.

First, I wanted to use INT pin of the PIC16F887 which is an external interrupt and will only trigger an interrupt on a rising or a falling edge. I noticed this method was not suitable as the signal I worked on didn’t have perfect timing.

So, I decided I should use “PORT B Interrupt On Change”  feature. However this created a problem; the interrupt flag didn’t clear properly so it kept going to the interrupt routine. Here is the code I was running.


volatile unsigned int fiftymicros=0;
volatile unsigned int milis=0;
volatile unsigned char fiftymicroscounter=0;
volatile unsigned int data_time=0;
volatile unsigned int milis_ctr=0;
unsigned long int data_bar[20]={0};
void interrupt()
{
 if(INTCON.T0IF)
 {
 TMR0=198;
 INTCON.T0IF=0;
 fiftymicros++;
 if(++fiftymicroscounter==40) { fiftymicroscounter=0; milis++; }
 }
 if(INTCON.RBIF)
 {
 PORTC.F1=~PORTC.F1;
 INTCON.RBIF=0;
 }
}
void main()
{
 ANSEL =0;
 ANSELH=0;
 TRISA=0; PORTA=0;
 TRISB=0x01; PORTB=0;
 TRISC=0; PORTC=0;
 TRISD=0; PORTD=0;
 TRISE=0; PORTE=0;
 OPTION_REG.INTEDG=1;
 OPTION_REG.T0CS=0;
 OPTION_REG.PSA=0;
 OPTION_REG.PS0=1;
 OPTION_REG.PS1=0;
 OPTION_REG.PS2=0;
 //OPTION_REG.B7=0;
 //WPUB=0x80;
 INTCON.TMR0IE=0;
 INTCON.RBIE=1;
 IOCB.B0=1;
 INTCON.GIE=1;
 UART1_Init(9600);
 Delay_ms(100);
 milis_ctr=milis;
 while(1)
 {
 }
}

Here is a screenshot from the oscilloscope that probes PORTC.1:

Oscilloscope Screenshot

Oscilloscope Screenshot

Zoomed Oscilloscope Screenshot

Zoomed Oscilloscope Screenshot

It turns out that interrupt flag is not cleared since I didn’t read PORTB. Here is an answer to my question on this issue at electronics.stackexchange.

As the datasheet notes:
For enabled interrupt-on-change pins, the present value is compared with the old value latched on the last read of PORTB to determine which bits have changed or mismatched the old value.
As AN566 comments in “Example 1″ on page 2:

Read PortB (to itself) to end
; mismatch condition

So, next time, read PORTB, no matter how, before clearing RBIF. Here is the way AN566 handles this:

PORTB=PORTB;

INTCON.RBIF=0;

I always yell at myself to read the datasheet thoroughly, however it seems like I don’t learn from it. I hope this will help someone.

Edit:

Oh, by the way, if “PORTB=PORTB;” gets removed by the mikroC PRO for PIC compiler and most likely it will get removed by other compilers due to code optimization, then use inline assembly like below, or assign PORTB to a dummy variable as Vishal noted in the comments.

asm { MOVF PORTB, 1}

Be Sociable, Share!

    2 Thoughts on “Weird PORT.B Interrupt on Change

    1. Vishal on January 25, 2013 at 04:55 said:

      thank you for your well documented website.
      the interrupt on change had too given me a lot of problem while i was work on pic16f877a.finally , i found that port b should be read.

      just read port b to a dummy variable.
      char dummy;
      dummy=PORTB

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

    Post Navigation