IOC Interrupts

Interrupt On Change interrupts induce a Flag whenever a PORT Pin changes state from low-to-high, and/or from high-to-low. Some PICs have generous IOCs while many limit them to PORTB/C.

Older PICs use a generic Read Only IOC Interrupt Flag (IOCIF). Individual PORT bits in the IOCB/C Registers, and IOCIE in the INTCONx Register must be Enabled (Set, = 1). The PIC18FxxK22 is a popular example.

More recent PIC versions allow virtually any Input pin to be configured as an IOC, with polarity control. In fact, the PIC18FxxK40 will allow an IOC interrupt, with Rising Edge AND/OR Falling Edge trigger on EVERY PORT PIN (including MCLR when configured as an Input)! This means you can generate an IOCIF when the PORT goes Positive, and generate an IF when it goes Negative selectively; and you can assign BOTH Rising AND Falling.

IOC is similar to INT0/1/2 in that it is triggered by a change in the logic state of the PORT Pin. The PIC18FxxK50 allows control over Rising/Falling edge trigger over the INTx Interrupts, but any change in logic state on the IOC pins will trigger an IOC interrupt.

IOC may be any of the following:

  • Interrupt on any logic state change (High-to-Low, Low-to-High; doesn’t matter)
  • Interrupt on a Positive transition (Low-to-High)
  • Interrupt on a Negative transition (High-to-Low)
  • Configurable as either Positive, or Negative, or both

Configuring SFRs for IOC

Without exception, the Global Interrupt Enable (GIE) bit of the INTCON Register must be set (= 1), and usually the Peripheral Interrupt Enable (PIE) bit must also be set (= 1). The Interrupt On Change Interrupt Enable (IOCIE) bit must be set, along with the individual PORT Pin Interrupt Enable (IOCB, IOCC).
For the PIC18FxxK40, you must set the associated IOCxN bit (IOCAN, IOCBN, IOCCN…) for a Negative Edge trigger and/or the IOCxP bit for a Positive Edge trigger.

Registers associated with IOC:

  • Global Interrupt Enable (GIE, often INTCON.7)
  • Peripheral Interrupt Enable (PIE, often INTCON.6)
  • IOCA, IOCB, IOCC, IOCD… (Individual bits correspond with individual PORT pins)
  • IOCIP Interrupt Priority bit, INTCONx Register (1 = High Priority)
  • IOCAP, IOCBP, IOCCP… Positive Edge Trigger bits
  • IOCAN, IOCBN, IOCCN… Negative Edge Trigger bits
  • IOCAF, IOCBF, IOCCF… Individual IOC Flags for individual PORT Pin changes

Handling an IOC Interrupt

For older PICs, the IOCIF merely indicates one of the Enabled IOC PORT Pins have changed logic state.

Within the Interrupt Handler you must read the PORTs to determine which of the Enabled pins triggered the Interrupt. Even if you only have one IOC pin Enabled, the method of clearing the IF is often by reading the PORT.

When a global IOCIF is implemented along with individual PORT IOC flags, the global IF is often Read Only. The method of clearing this Flag is to clear the individual IOC[PORT] Flag(s). The global IF indicates one of the individual IOCIFs are set. Clearing all individual IOCIFs clear the global IF.
With newer PICs, you will only get one single IOCAF (IOCBF, IOCCF…) type Flag, which is specific to the PORT Pin that changed logic state. Clearing that Flag is all that’s needed.

Whether using “ON INTERRUPT GOTO [Label]”, ASM Interrupts, or DT_INTs, older PICs require special attention when handling IOC Interrupts. (Newer PICs with IOCAF type Flags can be treated like any other Interrupt.)

Here are several examples ,based on the PIC18FxxK22, of how to implement an IOC Interrupt Handler:


   ON INTERRUPT GOTO Alarm		;Establish the Interrupt Handler

   ;Special Function Registers:
   INTCON = %11001000			;Enable GIE, PIE, & RBIE
   TRISB.4 = 1			        ;Configure PORTB.4 as Input
   ANSELB.4 = 0				;Configure PORTB.4 as Digital
   IOCB.4 = 1		                ;PORTB.4 will trigger an IOCIF
   INTCON2.0 = 0		        ;RBIP = 0, Low Priority Interrupt

   IF PORTB.4 = 1 THEN			;IOCIF Set
	HIGH LED			;Do Something
	GOSUB Squelch			;Do More Somethings
	INTCON.0 = 0			;Clear the RBIF
   ELSEIF INTCON.2 = 1 THEN		;Filter out other Interrupts (TMR0IF)
	TOGGLE LATA.6			;Do Something
	INTCON.2 = 0			;Clear TMR0IF

The "IF PORTB.4 = 1" statement initiates a PORT Read, which is one of the requirements for clearing the RBIF (PORTB IOCIF). According to the Data Sheet, this alone should clear the RBIF. Some application Interrupt Handlers may require the RBIF to be cleared manually, INTCON0.0 = 0. Everything else is covered in the PBP3 Reference Manual and Data Sheet.

Example 2: DT_INTS

Notice we did not have to clear the RBIF in the Interrupt Handler (denoted as INTCON.0 = 0 in the “ON INTERRUPT” example). In the Interrupt Processor there is an option to automatically reset the flag, which this example uses yes.

Example 3: ASM Interrupt

  DEFINE INTHAND Alarm			;Covered in 6.2.2 (page 249 of PBP3 Reference Manual)

  ;Special Function Registers:
  INTCON = %11001000			;Enable GIE, PIE, & RBIE
  TRISB.4 = 1				;Configure PORTB.4 as Input
  ANSELB.4 = 0				;Configure PORTB.4 as Digital
  IOCB.4 = 1				;PORTB.4 will trigger an IOCIF
  INTCON2.0 = 0				;RBIP = 0, Low Priority Interrupt

  BSR_TEMP		VAR	BYTE	        ;Temporary storage Variable for BSR
  STATUS_TEMP	        VAR	BYTE 	        ;Temporary storage Variable for STATUS
  W_TEMP		VAR	BYTE 	        ;Temporary storage Variable for W

  GOTO Main					;Alarm must occupy Address 0x08, see 6.2.3 (Page 249) of the PBP3 Reference Manual

  ASM						;Forces the Assembler to treat the following as ASSEMBLY
  Alarm						;Use of a colon (:) optional
	MOVWF		W_TEMP			;Save W in W_TEMP
	BSF 		LATA,6			;Turn LED On
	BCF 		INTCON, 0		;Clear RBIF (INTCON.0)
	MOVF		W_TEMP, W		;Restore Working Register
	RETFIE					;Return from Handler
  ENDASM					;Denotes end of ASSEMBLY

  Main:						;Normal Routine Label
	Some Code

Assembly Language Interrupts are covered in Section 6.2 (page 248) of the PBP3 Reference Manual. The first 3 lines of the Interrupt Handler “Alarm” save important Registers to temporary variables, declared with all your other Variables. They are Restored in 3 of the last 4 lines. RETFIE is the ASM version of RETURN (from Interrupt Handler)
Newer PIC MCUs incorporate automatic context saving. This would be covered in the Interrupt section of the Data Sheet. When Context Restore is available, the MOVx commands storing and restoring context to the W, STATUS, and BSR registers would not be required; but RETFIE FAST would be used instead of RETFIE.

Example 4: DT_INTS on PIC16F1619

include     "DT_INTS-14a.bas"
include     "ReEnterPBP.bas"

;Interrupt Processor:
INT_LIST  macro      ;IntSource,  Label,     Type, ResetFlag? 
        INT_Handler   IOC_INT,    _Alarm,    PBP,  yes   ;IOCB.4 
    INT_CREATE                      ;Creates the interrupt processor

;Special Function Registers:
INTCON = %11001000		    ;.0 = IOCIF, .3 = IOCIE
TRISB.4 = 1                         ;RB4 = Input
IOCBP.4 = 1                         ;IOC Interrupt when RB4 goes from low-to-high

wsave   VAR BYTE    $20     SYSTEM  ;location for W if in bank0
;wsave  VAR BYTE    $70	    SYSTEM  ;alternate save location for W
				    ;if using $70, comment wsave1-3

   PAUSE 100


Using DT_INTS-14 is almost identical to -18 but with the addition of the variable wsave. If you open DT_INTS-14.bas in MicroCode Studio, lines 22 & 23 have 2 variables commented out with instructions to “Place a copy of these variables in your Main program; The compiler will tell you which lines to un-comment; Do Not un-comment these lines.” By pasting both lines into your code, the compiler will give you an error for the wrong one. In this case, the PIC16F1619 needs the $20 version.

While in DT_INTS-14.bas, lines 30 - 32 list wsave1_2_3 with instructions, “IF any of these three lines cause an error ?? Comment them out to fix the problem; Which variables are needed, depends on the Chip you are using”. When you leave all 3 uncommented and try to compile, you will get an error for wsave3. Simply comment that line out and save this version of DT_INTS-14.bas as something different, like DT_INTS-14a.bas. With these few exceptions, the -14 version will perform the same as the -18 version.

This section deals specifically with Interrupt On Change peculiarities. The appropriate Data Sheet will give details on specific PIC implementation.

Furthermore, “ON INTERRUPT”, DT_INTS, and ASM Interrupts are covered in much greater detail elsewhere (PBP3 Reference Manual is a good source for non-DT_INTS Interrupt handling).

Recommended reading would include associated sections of the PBP3 Reference Manual, as well as Interrupt, PORT 1/0, and IOC sections of your Data Sheet. If using ASSEMBLY Interrupts, read that section in the PBP3 Reference Manual (Section 6.2, starting on page 248) along with the Instruction Set Summary section of the appropriate Data Sheet. The Instruction Set Summary is like the Commands section (Section 5) of the PBP3 Reference Manual, except it deals specifically with the Assembly Language Commands applicable to your specific PIC.

Another good resource covering Assembly Language programming for PIC18 MCUs:
"Applying PIC18 Microcontrollers", by Barry B. Brey (Copyright 2008 Pearson Education, Inc., ISBN 0-13-088546-0).

Page last modified on February 28, 2018, at 05:20 PM