I think @joeyd999 has nailed it but you also should know that you have to read the port to clear any mismatch before counting on the interrupt. You also have to read the port after any int-on-change to prepare for the next one, potentially losing changes that happen between the first one and the time you service the interrupt. IOC can be incredibly useful but only in certain cases.The interrupt is being triggered all of the time because the normal state is high. Is there any way to change the configuration of the Pic so the interrupt triggers when going low?
Yeah, about a ton. Interrupt on change was one of the least thought out features ever added to any commercially produced device. However, since it basically belongs to those who already have it built into existing devices it will never be fixed.Any issues I need to be aware there?
Note:
If a change on the I/O pin should occur
when the read operation is being executed
(start of the Q2 cycle), then the RBIF
interrupt flag may not get set. Furthermore,
since a read or write on a port affects all
bits of that port, care must be taken when
using multiple pins in Interrupt-on-change
mode. Changes on one pin may not be
seen while servicing changes on another
pin.
The interrupt-on-change feature is recommended for
wake-up on key depression operation and operations
where PORTB is only used for the interrupt-on-change
feature. Polling of PORTB is not recommended while
using the interrupt-on-change fe
So if I read this correctly, a read of one of the other pins on Port B might screw me up? Pure dumb luck but I am not currently using them for anything right now. RB6 and RB7 are also PGC and PGD. I usually like trying to avoid using those pins in the design.Yea, it's got a timing bug (in some chips) that can cause problems with fast signals.
http://www.microchip.com/forums/m294169.aspx
http://www.xargs.com/pic/portb-change-bug.html
PIC18(L)F2X/4XK22
If you know what to expect you can code around it. I've used IOC with two rotary quadrature encoder A/B inputs (low speed HID control knob interfaces) without any problems. For a simple home/index sensor the external interrupt pin setup might work better.So if I read this correctly, a read of one of the other pins on Port B might screw me up? Pure dumb luck but I am not currently using them for anything right now. RB6 and RB7 are also PGC and PGD. I usually like trying to avoid using those pins in the design.
I've done the same for 1, but it could be easily expanded to two.If you know what to expect you can code around it. I've used IOC with two rotary quadrature encoder A/B inputs (low speed HID control knob interfaces) without any problems. For a simple home/index sensor the external interrupt pin setup might work better.
#define HOME_SENSOR_INTERRUPT_ENABLE() INTCONbits.RBIE = 1
void interrupts_Init()
{
RCONbits.IPEN = 1; // Enable priority levels on interrupts
INTCONbits.RBIE = 1; // Interrupt on change
IOCBbits.IOCB4 = 1;
INTCONbits.GIEH = 1;
INTCON2bits.INTEDG0 = 0;
INTCONbits.RBIF = 0;
HOME_SENSOR_INTERRUPT_ENABLE();
}
void interrupt high_priority interrupts_highPriority(void)
{
// uart_putStringRom("High Priority Interrupt\r\n\r\n");
if ( INTCONbits.RBIF == 1)
{
int x=HOME_SENSOR_RX_PIN;
if (HOME_SENSOR_RX_PIN)
LATA = 1;
else
LATA = 0;
INTCONbits.RBIE = 1; // Interrupt on change
//IOCBbits.IOCB4 = 1;
INTCONbits.RBIF = 0;
}
}
void interrupts_Init()
{
INTCON = 0; // just disable everything for init then..
// remove IOC stuff, you are on RB0 (INT0)
RCONbits.IPEN = 1; // Enable priority levels on interrupts
INTCON2bits.INTEDG0 = 0; // interrupt on falling edge
INTCONbits.INT0IF = 0; // clear the interrupt flag
INTCONbits.INT0IE = 1; // enable the interrupt
INTCONbits.GIEH = 1; // enable hi priority interrupts
}
void interrupt high_priority interrupts_highPriority(void)
{
// uart_putStringRom("High Priority Interrupt\r\n\r\n");
if ( INTCONbits.INT0IF == 1)
{
int x=HOME_SENSOR_RX_PIN;
if (HOME_SENSOR_RX_PIN)
LATA = 1;
else
LATA = 0;
INTCONbits.INT0IF = 0; // clear interrupt flag
} // INT0 service
else{
INTCON = 0; // stray interrupt! kill all
uart_putStringRom("Unknown Interrupt!!!!!\r\n\r\n");
}// bad IRQ
} // HiPrio IRQ handler
Pretty sure that RB0 is not an interrupt on change - only RB7-4 are IOC. That means that you are enabling the wrong interrupt (RBIE/IF is for interrupt on change, not RB0 interrupt). RB0 is INT0 so you need to enable INT0IE in INTCON and manage INT0IF, also in INTCON.
I would also take care not to enable the interrupt until its fully configured and INT0IF has been cleared to take care of power up strays. Lines 9 and 11 enable interrupts before configuring the edge.
I would do something like this for interrupt on RB0:
IIRC, you can use the ext interrupts in the legacy (non priority) mode. Its just that if you elect to use priority IRQs, INT0 (RB0) is always a high priority.C:void interrupts_Init() { INTCON = 0; // just disable everything for init then.. // remove IOC stuff, you are on RB0 (INT0) RCONbits.IPEN = 1; // Enable priority levels on interrupts INTCON2bits.INTEDG0 = 0; // interrupt on falling edge INTCONbits.INT0IF = 0; // clear the interrupt flag INTCONbits.INT0IE = 1; // enable the interrupt INTCONbits.GIEH = 1; // enable hi priority interrupts } void interrupt high_priority interrupts_highPriority(void) { // uart_putStringRom("High Priority Interrupt\r\n\r\n"); if ( INTCONbits.INT0IF == 1) { int x=HOME_SENSOR_RX_PIN; if (HOME_SENSOR_RX_PIN) LATA = 1; else LATA = 0; INTCONbits.INT0IF = 0; // clear interrupt flag } // INT0 service else{ INTCON = 0; // stray interrupt! kill all uart_putStringRom("Unknown Interrupt!!!!!\r\n\r\n"); }// bad IRQ } // HiPrio IRQ handler
Hope that helps!
The best example I can think of is the quadrature encoder - lets use a rotary knob with the two phases A and B. As you rotate the switch in one direction, the two phases will run 90deg out with respect to each other with one leading the other. Turn it the other way and both phases also run but now the other one leads. Each click of the knob changes a one of the phases. To fully read this, you need to know about each click so you have to monitor both phases and interrupt when either changes. The interrupt service routine reads both inputs, compares them with the previous value and knows which way the knob turned. But to do this, you need an interrupt on a change of either phase. IOC on portB is a convenient tool to do that. But it comes with caveats - the change detection logic resets each time you read the port so care has to be taken there. uCHIP recommends against polling portB when IOC is used. But that's it in a nutshell, a single interrupt when any line on RB7-4 changes in any way. The service routine sorts it out.I am still confused by "It allows you to monitor up to 4 pins at once for a change in either direction". What do y mean by "change in either direction"? It can also interrupt when the pin is an output?
Depends on the PIC. Later/better PICs have more tolerance here - outputs on the IOC pins are ignored. This PIC allows you to select individual pins in RB7-4 to be a part of IOC. I haven't read carefully enough to see what other caveats there may be - I don't usually mess around with it except for special cases and then carefully.It can also interrupt when the pin is an output?
Thinking more, I would have the main routine generate a buffer full of the patterns to display. For example, if you were swinging a row of 8 LEDs that blinked out the time digits as it swept the circle main would keep time, decode the time into sweepable digit patterns composed of successive 'columns' of LEDs and post them in a pattern array. MAIN is the producer here.OK this is for a home sensor for an external clock. What would be the best way to go?