Problem about Interrupts on portb pin 1 (PIC16F877A)

Thread Starter

lloydi12345

Joined Aug 15, 2010
103
Hello guys, I'm having problem with my external interrupts using pic16f877a. I can't make the interrupt service routine run. The command "portc.f0 = ~portc.f0;" should be executed when the logic state is changed either from 0 to 1 or 1 to 0 on the pin 1 of PORTB.

Here's my code:

Rich (BB code):
void interrupt(void){
     if (pir1.rbif == 1){
        portc.f0 = ~portc.f0;   //invert the state of output to see an if an interrupt occured
        pir1.rbif = 0;
     }
}

void main() {
  ADCON1  = 0x06;
  CMCON = 0x07;

  TRISB  = 0xFF;
  TRISC = 0x00;

  portc = 0x00;

  intcon.rbie = 1;
  intcon.gie = 1;

  while(1) {
           delay_ms(1);
  }
}
I hope you can help me. Thank you.
 

Tahmid

Joined Jul 2, 2008
343
Quote from the datasheet:
14.11.3 PORTB INTCON CHANGE
An input change on PORTB<7:4> sets flag bit, RBIF
(INTCON<0>). The interrupt can be enabled/disabled
by setting/clearing enable bit, RBIE (INTCON<4>). See
Section 4.2 “PORTB and the TRISB Register”.
You can't have PORTB change interrupt on RB1. It's only available on RB4, RB5, RB6 and RB7.

Hope this helps.
Tahmid.
 

Tahmid

Joined Jul 2, 2008
343
Don't you have to read the port to clear the mismatch condition before clearing the RBIF flag?
Exactly. The datasheet states:
The user, in the Interrupt Service Routine, can clear the interrupt in the following manner:
a) Any read or write of PORTB. This will end the mismatch condition.
b) Clear flag bit RBIF.

A mismatch condition will continue to set flag bit RBIF. Reading PORTB will end the mismatch condition and allow flag bit RBIF to be cleared.
So, you can do two things:
Rich (BB code):
void interrupt(void){
     if (intcon.rbif == 1){
        portc.f0 = portb.f4;   //invert the state of output to see an if an interrupt occured
        intcon.rbif = 0;
     }
}

void main() {
  ADCON1  = 0x06;
  CMCON = 0x07;

  TRISB  = 0xFF;
  TRISC = 0x00;

  portc = 0x00;

  intcon.rbie = 1;
  intcon.gie = 1;

  while(1) {}
}
or you could have a dummy read:

Rich (BB code):
unsigned char buffer;

void interrupt(void){
     if (intcon.rbif == 1){
        buffer = portb;
        portc.f0 = ~portc.f0;   //invert the state of output to see an if an interrupt occured
        intcon.rbif = 0;
     }
}

void main() {
  ADCON1  = 0x06;
  CMCON = 0x07;

  TRISB  = 0xFF;
  TRISC = 0x00;

  portc = 0x00;

  intcon.rbie = 1;
  intcon.gie = 1;

  while(1) {}
}
Hope this helps.
Tahmid.
 

Thread Starter

lloydi12345

Joined Aug 15, 2010
103
Thanks for both of your replies :)

Both of your codes work well Tahmid.

Last clarification.

1. What does a mismatch mean on the PIC?

2. And also, I tried this code:

Rich (BB code):
void interrupt(void){
     if (intcon.rbif == 1){
        portc.f0 = ~portc.f0;   //invert the state of output to see an if an interrupt occured
        intcon.rbif = 0;
     }
}


void main() {
  ADCON1  = 0x06;
  CMCON = 0x07;

  TRISB  = 0xFF;
  TRISC = 0x00;

  portc = 0x00;

  intcon.rbie = 1;
  intcon.gie = 1;

  while(1) {
}
}
After an interrupt occured, it then changes the state of the LED always from 1 to 0 then to 1 and so on. Is it because it is triggered always?

3. So it means if I'm using the PORTB as external interrupts, I have to place it first on any variable or even just read it?
(Sorry I can't clearly understand some terms on the datasheet)

Edit: I think it has a problem. When I start the simulation from 6v, I reduce the power to 0v the LED doesn't light yet. It only lights when I increase again the voltage above. What I mean is that the interrupt is activated at the second change of state. The interrupt should be activated at the first change of state when the 6v approaches a voltage below the reference voltage.
 
Last edited:

Tahmid

Joined Jul 2, 2008
343
Hi,
Mismatch is the state of change I guess, I'm not very sure about this. But if the mismatch is not ended, the interrupt keeps on occurring. Your code does not end the mismatch because it does not read the port, so the interrupt keeps on occurring just after the service routine is carried out.

Hope this helps.
Tahmid.
 

Thread Starter

lloydi12345

Joined Aug 15, 2010
103
Hi,
Mismatch is the state of change I guess, I'm not very sure about this. But if the mismatch is not ended, the interrupt keeps on occurring. Your code does not end the mismatch because it does not read the port, so the interrupt keeps on occurring just after the service routine is carried out.

Hope this helps.
Tahmid.
Thank you Tahmid I got it now.

Can someone help me on the problem left? It is about the changing state. Starting from 6v when I lower the voltage to 0v (1st change of state), the interrupt is not yet called. The interrupt starts only to execute when I return back the voltage to 6v (2nd change of state) and from that point, any change of state will trigger the interrupt routine.
 
Last edited:

Markd77

Joined Sep 7, 2009
2,806
Four of the PORTB pins, RB7:RB4, have an interrupt-
on-change feature. Only pins configured as inputs can
cause this interrupt to occur (i.e., any RB7:RB4 pin
configured as an output is excluded from the interrupt-
on-change comparison). The input pins (of RB7:RB4)
are compared with the old value latched on the last
read of PORTB. The “mismatch” outputs of RB7:RB4
are OR’ed together to generate the RB Port Change
Interrupt with flag bit RBIF (INTCON<0>).
From the bit that mentions "the last read of PORTB" I'd try reading the port and then setting up the interrupt or maybe the other way round.
 

Thread Starter

lloydi12345

Joined Aug 15, 2010
103
From the bit that mentions "the last read of PORTB" I'd try reading the port and then setting up the interrupt or maybe the other way round.
Hi Markd77 thanks for replying, the interrupt is already working but it is only activated on the second change of state not in first change of state. Suggestions?
 

Tahmid

Joined Jul 2, 2008
343
From the bit that mentions "the last read of PORTB" I'd try reading the port and then setting up the interrupt or maybe the other way round.
Spot on.

Try with this piece of code:
Rich (BB code):
unsigned char buffer;

void interrupt(void){
     if (intcon.rbif == 1){
        buffer = portb;
        portc.f0 = ~portc.f0;   //invert the state of output to see an if an interrupt occured
        intcon.rbif = 0;
     }
}

void main() {
  ADCON1  = 0x06;
  CMCON = 0x07;

  TRISB  = 0xFF;
  TRISC = 0x00;

  portc = 0x00;

  intcon.rbie = 1;
  intcon.gie = 1;

  buffer = portb;
  
  while(1) {}
}
I hope you understand the difference.

Hope this helps.
Tahmid.
 

Thread Starter

lloydi12345

Joined Aug 15, 2010
103
Try with this piece of code...
This is the most exact code :)
I think I lacked the reading part of portb at first before initializing the interrupts. All I know is just to read portb at the interrupt service routine already. I didn't know it should be twice.

Thank you alot Tahmid :D
 

Tahmid

Joined Jul 2, 2008
343
I think I lacked the reading part of portb at first before initializing the interrupts.
Not necessarily. PORT should be read before first interrupt occurs, it could be after initializing interrupts as well, as I've shown in the code.

Hope this helps.
Tahmid.
 
Top