Thread: PIC16F690: Using RA2 as Both an Input and an Interrupt

  1. #1
    Registered User
    Join Date
    Feb 2013
    Posts
    8

    PIC16F690: Using RA2 as Both an Input and an Interrupt

    I brought some code from a PICDEM DV lab example into a simple program I'd written. The example showed how to use the external interrupt on the PIC16F690 to switch directions in a function.

    I've been trying to use that RA2 pin as both the input (start) trigger for one of my functions and as an interrupt to get out of that function, too. So far the interrupt doesn't work, but the function trigger does. Should I use two pushbuttons or add a random timer to the for() loop to execute the function to roll the dice?

    Trying to incorporate that example code also seems to have messed up the little random counter [a for() loop] that I used. The dice pattern was reliably random before adding this new stuff, and now I can clearly see repetition.

    Sorry for the messy noob coding. I'm only just starting a MC class.

    Code:
    
    #pragma config FOSC = INTRCIO   // Oscillator Selection bit
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit
    #pragma config PWRTE = OFF      // Power-up Timer Enable bit
    #pragma config MCLRE = OFF      // MCLR Pin Function Select bit
    #pragma config CP = OFF         // Code Protection bit
    #pragma config CPD = OFF        // Data Code Protection bit
    #pragma config BOREN = ON       // Brown-out Reset Selection bits
    #pragma config IESO = ON        // Internal External Switchover bit
    #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit
    
    
    #include <xc.h>		// Include HITECH CC header file
    
    
    void FirstFlash(int);
    void pause(unsigned short usvalue);
    void msecbase(void);
    void Initialize(void);
    void Delay_5mS(void);
    void OneToSixLoop(void);
    
    
    //----------------------PROGRAM MEMORY----------------------
    
    
    void Delay_5mS(void)
    {   T0IF = 0;             //Make sure the T0IF is cleared.
        TMR0 = 100;         //Preload the TMR0 register.
    
    
        while (T0IF == 0);  //Sit here and wait for Timer0 to overflow.
    }
    
    
    /*** INTERRUPT CODE ***/
    
    
    void interrupt PB_PressISR(void)
    {
     if(INTE && INTF) INTF = 0; //Check to see if the interrupt was caused by
                                    //the external interrupt on RA2.
                                    //If so, clear the external interrupt flag
                                    //to allow subsequent interrupts to be detected.
     if(RA2 == 0)               //Check to see if the RA2 pin is 0;
     {                              //(i.e. push button pressed).
        Delay_5mS();            //If RA2 is 0, delay for 5mS to filter
                    }               //any switch bounce.
     if(RA2 == 0)
     {
        PORTC = 0x00;
        OneToSixLoop();  }
    }
    
    
    void main(void)
    {
        Initialize();
        OneToSixLoop();
    
    
    }	//end main
    
    
    void Initialize(void)
    {   /*** Configure Timer0 to overflow ever 5ms ***/
        T0CS = 0;           // Select FOSC/4 as Timer0 clock source.
        T0SE = 0;           // Increment TMR0 on rising clock edge.
        PSA  = 0;           // Assign prescaler to Timer0.
    
    
        PS0 = 0;            // Select a 1:32 prescaler.
        PS1 = 0;
        PS2 = 1;
    
    
        /*** Initialize Ports ***/
        ANSEL   = 0;			// Intialize A/D ports off
        CM1CON0 = 0;			// Initialize Comparator 1 off
        CM2CON0 = 0;			// Initialize Comparator 2 off
    
    
        PORTC = 0x00;			//Clear PortC port
        TRISC = 0x00;			//All PortC I/O outputs
        TRISA = 0xFF;			//All PortA I/O inputs
        ANS2  = 0;
    
    
        /*** Initialize Interrupts ***/
        INTEDG = 0;     // Interrupt occurs on High/Low transition of RA2 voltage.
        INTE   = 1;     // Enable the RA2/PIN17 external interrupt.
        INTF   = 0;     // Clear the external interrupt flag.
        GIE    = 1;     // Enable global interrupt capability on the PIC16F690--
                        // ***ALWAYS DONE LAST*****
    }
    
    
    //*******************************************************
    void pause( unsigned short usvalue )    // Pause function
    {
    	unsigned short x;
    	for (x=0; x<=usvalue; x++)	// Loop through a delay equal to usvalue
    		{			// in milliseconds.
                    msecbase();		// Jump to millisec delay routine.
    		}
    }
    //*******************************************************
    void msecbase(void)                     // Msecbase function
    {
    	OPTION_REG = 0b00000001;    // Set prescaler to TMRO 1:4
    	TMR0 = 0xD;                 // Preset TMRO to overflow on 250 counts
    	while(!T0IF);               // Stay until TMRO overflow flag equals 1
    	T0IF = 0;                   // Clear the TMR0 overflow flag
    }
    //*******************************************************
    
    
    void FirstFlash(int DiceRND)
    {   int Pattern;
    
    
        INTF = 0;
        for(Pattern = 0; Pattern <=4; Pattern++)
            {   PORTC = 0xFF;
                    pause(100);
                PORTC = 0x00;
                    pause(100);
            }
    
    
        if(DiceRND==1) PORTC = 0b00001000;
        if(DiceRND==2) PORTC = 0b01000001;
        if(DiceRND==3) PORTC = 0b01001001;
        if(DiceRND==4) PORTC = 0b01100011;
        if(DiceRND==5) PORTC = 0b01101011;
        if(DiceRND==6) PORTC = 0b01110111;
            pause(10000);
            PORTC = 0x00;
    }
    
    
    void OneToSixLoop(void)
    {   while(1==1)
    
    
    {   int DiceRND;
    
    
        for(DiceRND = 1; DiceRND <= 6; DiceRND++)
        {   if(RA2 == 0)
            {   FirstFlash(DiceRND);  }
            else if(DiceRND == 6)
            {   DiceRND = 0;  }
                              }
    }
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    First of all, your indentation needs work.
    Code:
    #pragma config FOSC = INTRCIO   // Oscillator Selection bit
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit
    #pragma config PWRTE = OFF      // Power-up Timer Enable bit
    #pragma config MCLRE = OFF      // MCLR Pin Function Select bit
    #pragma config CP = OFF         // Code Protection bit
    #pragma config CPD = OFF        // Data Code Protection bit
    #pragma config BOREN = ON       // Brown-out Reset Selection bits
    #pragma config IESO = ON        // Internal External Switchover bit
    #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit
    
    #include <xc.h>                 // Include HITECH CC header file
    
    void FirstFlash(int);
    void pause(unsigned short usvalue);
    void msecbase(void);
    void Initialize(void);
    void Delay_5mS(void);
    void OneToSixLoop(void);
    
    //----------------------PROGRAM MEMORY----------------------
    void Delay_5mS(void)
    {
      T0IF = 0;                     //Make sure the T0IF is cleared.
      TMR0 = 100;                   //Preload the TMR0 register.
    
      while (T0IF == 0);            //Sit here and wait for Timer0 to overflow.
    }
    
    
    /*** INTERRUPT CODE ***/
    void interrupt PB_PressISR(void)
    {
      if (INTE && INTF)
        INTF = 0;                   //Check to see if the interrupt was caused by
      //the external interrupt on RA2.
      //If so, clear the external interrupt flag
      //to allow subsequent interrupts to be detected.
      if (RA2 == 0)                 //Check to see if the RA2 pin is 0;
      {                             //(i.e. push button pressed).
        Delay_5mS();                //If RA2 is 0, delay for 5mS to filter
      }                             //any switch bounce.
      if (RA2 == 0) {
        PORTC = 0x00;
        OneToSixLoop();
      }
    }
    
    void main(void)
    {
      Initialize();
      OneToSixLoop();
    }                               //end main
    
    void Initialize(void)
    {   /*** Configure Timer0 to overflow ever 5ms ***/
      T0CS = 0;                     // Select FOSC/4 as Timer0 clock source.
      T0SE = 0;                     // Increment TMR0 on rising clock edge.
      PSA = 0;                      // Assign prescaler to Timer0.
    
      PS0 = 0;                      // Select a 1:32 prescaler.
      PS1 = 0;
      PS2 = 1;
    
      /*** Initialize Ports ***/
      ANSEL = 0;                    // Intialize A/D ports off
      CM1CON0 = 0;                  // Initialize Comparator 1 off
      CM2CON0 = 0;                  // Initialize Comparator 2 off
    
      PORTC = 0x00;                 //Clear PortC port
      TRISC = 0x00;                 //All PortC I/O outputs
      TRISA = 0xFF;                 //All PortA I/O inputs
      ANS2 = 0;
    
      /*** Initialize Interrupts ***/
      INTEDG = 0;                   // Interrupt occurs on High/Low transition of RA2 voltage.
      INTE = 1;                     // Enable the RA2/PIN17 external interrupt.
      INTF = 0;                     // Clear the external interrupt flag.
      GIE = 1;                      // Enable global interrupt capability on the PIC16F690--
      // ***ALWAYS DONE LAST*****
    }
    
    
    //*******************************************************
    void pause(unsigned short usvalue)  // Pause function
    {
      unsigned short x;
      for (x = 0; x <= usvalue; x++)  // Loop through a delay equal to usvalue
      {                             // in milliseconds.
        msecbase();                 // Jump to millisec delay routine.
      }
    }
    
    //*******************************************************
    void msecbase(void)             // Msecbase function
    {
      OPTION_REG = 0 b00000001;     // Set prescaler to TMRO 1:4
      TMR0 = 0xD;                   // Preset TMRO to overflow on 250 counts
      while (!T0IF);                // Stay until TMRO overflow flag equals 1
      T0IF = 0;                     // Clear the TMR0 overflow flag
    }
    
    //*******************************************************
    void FirstFlash(int DiceRND)
    {
      int Pattern;
    
      INTF = 0;
      for (Pattern = 0; Pattern <= 4; Pattern++) {
        PORTC = 0xFF;
        pause(100);
        PORTC = 0x00;
        pause(100);
      }
    
      if (DiceRND == 1)
        PORTC = 0b00001000;
      if (DiceRND == 2)
        PORTC = 0b01000001;
      if (DiceRND == 3)
        PORTC = 0b01001001;
      if (DiceRND == 4)
        PORTC = 0b01100011;
      if (DiceRND == 5)
        PORTC = 0b01101011;
      if (DiceRND == 6)
        PORTC = 0b01110111;
    
      pause(10000);
      PORTC = 0x00;
    }
    
    
    void OneToSixLoop(void)
    {
      while (1 == 1)
      {
        int DiceRND;
    
        for (DiceRND = 1; DiceRND <= 6; DiceRND++) {
          if (RA2 == 0) {
            FirstFlash(DiceRND);
          } else if (DiceRND == 6) {
            DiceRND = 0;
          }
        }
      }
    }
    > I've been trying to use that RA2 pin as both the input (start) trigger for one of my functions and as an interrupt to get out of that function,
    Well the hardware isn't that smart.
    Every time you hit the switch, you get an interrupt.


    Code:
      if (RA2 == 0)                 //Check to see if the RA2 pin is 0;
      {                             //(i.e. push button pressed).
        Delay_5mS();                //If RA2 is 0, delay for 5mS to filter
      }                             //any switch bounce.
      if (RA2 == 0) {
        PORTC = 0x00;
        OneToSixLoop();
      }
    Bad bad bad!
    1. Do not call delay() in an isr
    2. Do NOT call a function containing a while(true) loop.

    ISR code should do the least amount of work possible.
    This is typically
    - acknowledge the interrupt to the hardware ( like INTF = 0; )
    - read the information (key press, pin, port register)
    - store the result somewhere in memory (say a buffer)
    - signal (say set a flag variable in memory) that an interrupt has been received, and there is data to process)
    - that's it!

    From that, you should be able to implement in your main code
    - waitForSwitchStateChange()
    - isSwitchOn()
    - isSwitchOff()
    or other functions in a similar style.

    For the debouncing, start with something like this.
    Do you know for sure that the key isn't already fully debounced? If it is, then count should reliably increment by just one on each switch event.
    Code:
    int count = 0;
    void interrupt PB_PressISR(void)
    {
      if (INTE && INTF)
        INTF = 0;                   //Check to see if the interrupt was caused by
      count++;
    }
    int main ( ) {
      while ( 1 ) {
        Delay_20mS();
        // format count as a string, send to serial port
      }
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Feb 2013
    Posts
    8
    Ok, let's say I fix the double-duty RA2 pin by adding another pushbutton or making the timer for the dice roll a random event. I still need to stop the program at any point and start over where the dice roll begins--either waiting for the user to press a button or just randomly rolling them.

    The example code from the datasheet used the interrupt as you described--just to return a value--but I'm not dreaming up any interrupt function that will start the program over without jumping to one of the existing functions. If I keep looping out of the ISR, does that lead to stack overflow or some other catastrophic error?

    What exactly happens when if I use the ISR to start over at the dice-rolling function where the while() loop is?

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    A simple way.

    Code:
    volatile flag = 0;
    void interrupt PB_PressISR(void)
    {
      if (INTE && INTF)
        INTF = 0;                   //Check to see if the interrupt was caused by
      flag = 1;
    }
    int main ( ) {
      while ( !flag ) {
        // do stuff
      }
      // flag is now 1
      flag = 0;
      // maybe go on to do other things, like say wait for another key press
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with interrupt handler
    By afflictedd2 in forum C Programming
    Replies: 2
    Last Post: 02-18-2010, 10:35 AM
  2. ASM interrupt and others
    By Unregistered in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 06-08-2002, 07:18 PM
  3. interrupt
    By juandy in forum C++ Programming
    Replies: 4
    Last Post: 05-21-2002, 08:24 AM
  4. how do i use interrupt 0x33?
    By linuxman132 in forum C Programming
    Replies: 1
    Last Post: 12-27-2001, 03:12 PM
  5. Interrupt???
    By GiSH in forum C++ Programming
    Replies: 1
    Last Post: 11-15-2001, 12:27 PM