PIC16F887 Accessing IOCB bits (interrupt-on-change) problem - Page 1
Forum section: electronics / general

author: newtekuser
author_rank: Frequent Contributor
timestamp: August 20, 2023, 05:45:00 pm
content: The PIC16F887 supports interrupt-on-change feature on all PORTB ports and the pic16f887.h file has the definition of IOC bits in the IOCBbits_t union:Code:typedef union {struct {unsigned IOCB :8;};struct {unsigned IOCB0 :1;unsigned IOCB1 :1;unsigned IOCB2 :1;unsigned IOCB3 :1;unsigned IOCB4 :1;unsigned IOCB5 :1;unsigned IOCB6 :1;unsigned IOCB7 :1;};} IOCBbits_t;However, my code doesn't compile when I'm trying to access any of the union members:Code:void __interrupt() isr(void) {if (INTCONbits.INTF) {// do something when RB0 button pressedINTCONbits.INTF = 0;}if (IOCBbits_t.IOCB2) {// do something when RB2 button pressedIOCBbits_t.IOCB2 = 0;}}interrupts.c:40:9: error: unexpected type name 'IOCBbits_t': expected expressionif (IOCBbits_t.IOCB2) {^interrupts.c:62:19: error: expected identifier or '('IOCBbits_t.IOCB2 = 0;What am I missing here?

author: DavidAlfa
author_rank: Super Contributor
timestamp: August 20, 2023, 06:35:54 pm
content: Code:if (IOCBbits.IOCB2) {// do something when RB2 button pressedIOCBbits.IOCB2 = 0;}IOCBbits_t is a type declaration, not the variable.

author: Ian.M
author_rank: Super Contributor
timestamp: August 20, 2023, 06:37:34 pm
content: Read a little further down the header:Code:extern volatile IOCBbits_t IOCBbits @ 0x096;That's the line that declares a variable of type IOCbits_t to give you a union IOCbits to access those bitfields.DavidAlfa has just posted the fix to your code.

author: newtekuser
author_rank: Frequent Contributor
timestamp: August 20, 2023, 07:11:20 pm
content: Dang it, I missed that! Thanks guys!

author: newtekuser
author_rank: Frequent Contributor
timestamp: August 20, 2023, 08:54:06 pm
content: For some reason unknown to me I can only get the INT0 pin to react to an interrupt, none of my other configured ports react to port changes.I have it hooked up such that an LED is connected to RB0 (INT0), second LED to RB1 and third one to RB2. Only when I press on the button connected to RB0 does the first LED light. The other two LEDs connected to RB1 and RB2 don't light up.Anything I'm missing in this case?Code:void main(void){OSCCON = 0x70;ANSEL = 0b0000000;ANSELH = 0b0000000;// interrupt stuffINTCONbits.INTE = 1;OPTION_REGbits.INTEDG = 0;INTCONbits.GIE = 1;IOCBbits.IOCB1 = 1;IOCBbits.IOCB2 = 1;while (1){RB0, RB1, RB2 = 0;__delay_ms(1000);}}void __interrupt() isr(void) {if (INTCONbits.INTF) {RB0 = 1;__delay_ms(1000);INTCONbits.INTF = 0;}if (IOCBbits.IOCB1) {RB1 = 1;__delay_ms(1000);IOCBbits.IOCB1 = 0;}if (IOCBbits.IOCB2) {RB2 = 1;__delay_ms(1000);IOCBbits.IOCB2 = 0;}}

author: DavidAlfa
author_rank: Super Contributor
timestamp: August 20, 2023, 09:35:24 pm
content: PORTB uses its own interrupt enable bit, you're missing RBIE:Code:INTCONbits.RBIE = 1;The interrupt itself is wrong as well, you should checkINTCONbits.RBIF:Code:void __interrupt() isr(void) {if (INTCONbits.INTF) {RB0 = 1;INTCONbits.INTF = 0;}if (INTCONbits.RBIF) {static unsigned char pb_last; // This variable holds its value between interrupt callsunsigned char pb_now = PORTB;// Compare each bit between the two variables to determine which bit changedpb_last = pb_now; // Update for the next callINTCONbits.RBIF = 0;}}

author: newtekuser
author_rank: Frequent Contributor
timestamp: August 20, 2023, 11:20:15 pm
content: Quote from: DavidAlfa on August 20, 2023, 09:35:24 pmSo one does the checking of which pins were changed using INTF register and not IOCB register? Thank you for pointing out the RBIE register enable!Ok, I did some mocking around and almost got it to work but not quite.QuoteThe problem I see now is that when I press the first button (RB0), the third LED lights up and stay on.When pressing the second button (RB1), also the third LED lights up and stays on.When pressing the third button (RB2), the second LED (RB1) lights up and stays on.It also looks as if the MCU is stuck in the isr?

author: DavidAlfa
author_rank: Super Contributor
timestamp: August 21, 2023, 03:42:33 am
content: You must compare last vs now. Try this:Code:static unsigned char pb_last = 0xFF; // Initialize with all pins in idle stateunsigned char pb_now = PORTB;// XOR before and now, 1=changed pin.// AND with before, result is changed pins now reading 0.unsigned char pb_changed = (pb_last ^ pb_now) & pb_last;pb_last = pb_now;if (pb_changed & 0b10) { // PB1 changed and it's pressed downRB1 = 1;__delay_ms(1000);}if (pb_changed & 0b100) { // PB2RB2 = 1;__delay_ms(1000);}INTCONbits.RBIF = 0;

author: newtekuser
author_rank: Frequent Contributor
timestamp: August 21, 2023, 03:49:26 am
content: Quote from: DavidAlfa on August 21, 2023, 03:42:33 amExcellent, it works perfectly now, many thanks!