Author Topic: Interrupt on change 16f877A using XC8  (Read 1191 times)

0 Members and 1 Guest are viewing this topic.

Offline djsbTopic starter

  • Frequent Contributor
  • **
  • Posts: 966
  • Country: gb
Interrupt on change 16f877A using XC8
« on: August 20, 2021, 10:41:43 am »
I'm trying to get an interrupt on change example working on an 16F877A using XC8.

Code: [Select]
/*
 * File: Main.c
 * Author: David Briscoe
 * PIC: 16F877A w/Ext OSC @ 8MHz, 5v
 * Program: 11_IOC
 * Compiler:XC8 (v2.31, MPLAX X v5.45)
 * Program Version: 1.0
 *               
 *               
 * Program Description: This Program Allows PIC16F877A to toggle an LED based
 *                      on the state of a IOC
 *                     
 * Hardware Description: An LED is connected via a 220R resistor to PIN D1 and
 *                       a switch is connected to PIN B0
 *                     
 * Created August 20th, 2021
 */


/*******************************************************************************
 *Includes and defines
 ******************************************************************************/

#define _XTAL_FREQ 8000000
#define BUTTON  PORTBbits.RB0       // pushbutton
#include "16F877A_Internal.h"




/*******************************************************************************
 * Function: void initMain()
 *
 * Returns: Nothing
 *
 * Description: Contains initializations for main
 *
 * Usage: initMain()
 ******************************************************************************/

void initMain(){
   
   
   
    ////////////////////////
    /// Configure Ports
    ////////////////////////
   
    // Set PIN D1 as output
    TRISDbits.TRISD1 = 0;
    // Set PIN D2 as output
    TRISDbits.TRISD2 = 0;
    // Set PIN B0 as input
    TRISBbits.TRISB0 = 1;
    OPTION_REGbits.nRBPU = 0; // turn on pull-up
    // On 16F877A ALL of PORT B is pulled HI. NO INDIVIDUAL BITS CAN BE SET.
    // On 16F887 INDIVIDUAL PORTB pins can have weak pull-ups enabled.
   
   
    // Turn LED's ON
   
       RD1 = 1;
       RD2 = 1;
       __delay_ms(500);
    // Wait 0.5s then turn them off
       RD1 = 0;
       RD2 = 0;
   
    /////////////////////////
    /// Configure Interrupts
    ////////////////////////
   
    // enable detection of falling edges on RB0
    //IOCBNbits.IOCBN0 = 1;
    INTCONbits.RBIE = 1; // enable interrupt on change
    // enable IOC interrupt
    OPTION_REGbits.INTEDG = 0;
   
    INTCONbits.GIE = 1; // interrupt global
   
    // Enable global interrupt
    //ei();
}

/*******************************************************************************
 * Function: Main
 *
 * Returns: Nothing
 *
 * Description: Program entry point
 ******************************************************************************/

void main(void) {
    initMain();
   
    while(1){
       
       ; // do nothing
    }
   
    return;
}

/*******************************************************************************
 * Function: void interrupt isr(void)
 *
 * Returns: Nothing
 *
 * Description: Service port change interrupt which is triggered on any valid
 *              transition on IOC-enables input pin caused by external button
 *              press. Toggles LED on every enabled transition (high -> low)
 ******************************************************************************/

__interrupt() void isr(void){
   
    // clear IOC flags on PORTB
    //INTCONbits.RBIF = 0;
    //IOCBF = 0;
   
    // toggle LED
    //
    if (INTCONbits.RBIF)
    {
        if (!BUTTON)
        {
          RD2 = ~RD2; 
        }
        INTCONbits.RBIF = 0;
    }
   
}

The code compiles OK with no errors or warnings. I just can't get it to work.

Everything is wired up correctly and the switch works OK (I made a for() loop in main() to flash the LED's 5 times on a button press). I can't get the code above to work. I'm not really understanding how the interrupt logic works. Where am I going wrong? Thanks.

David.
« Last Edit: August 20, 2021, 10:45:43 am by djsb »
David
Hertfordshire, UK
University Electronics Technician, London, PIC16/18, CCS PCM C, Arduino UNO, NANO,ESP32, KiCad V8+, Altium Designer 21.4.1, Alibre Design Expert 28 & FreeCAD beginner. LPKF S103,S62 PCB router Operator, Electronics instructor. Credited KiCad French to English translator
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3339
  • Country: gb
Re: Interrupt on change 16f877A using XC8
« Reply #1 on: August 20, 2021, 11:47:32 am »
The PICs interrupt on change peripheral internally stores a copy of the port's input pin values which is compared against the live input pin values in order to detect a change.  After a change is detected you have to do two things in this order: 1) Read or write the port.  This saves the new pin state for the next comparison.  2) Reset the interrupt flag.

If you don't read/write the port then the mismatch condition remains and RBIF will immediately get set after you clear it.
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 13133
Re: Interrupt on change 16f877A using XC8
« Reply #2 on: August 20, 2021, 11:51:37 am »
PIC16F877A only has IOC on RB4-7. Your button on RB0 is *NOT* on an IOC capable pin (though it is on an INT pin).

Also, Microchip's older 8 bit PICs' IOC implementation is known to be buggy!  BEWARE of the RACE CONDITION!

You must read the whole port* with the active IOC pins, and attempt to clear its IOC interrupt flag at the beginning of your ISR immediately after confirming the interrupt source, and store the port value for the ISR to decode.   DO NOT re-read the port later on in the ISR or read it in your main program (apart from ONCE immediately before enabling GIE) or you *WILL* loose some interrupts.

The remaining port B pins can be safely used as outputs, but only if you write the *whole* port without using an instruction that performs a RMW (read modify write) operation.  *DO* *NOT* attempt direct use of individual pins of the port.
 
* Due to the race condition bug, you must use a very specific sequence to read the port and clear the IOC interrupt flag without missing pin transitions. See RACE CONDITION link above.
« Last Edit: August 20, 2021, 11:56:05 am by Ian.M »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf