Ben Brown
Ben Brown

Reputation: 11

Can an interrupt interrupt itself?

I am using a pic16F690 with mplabv8.70, a pickit 2 and the hi-tech PICC PRO c compiler.

My question is whether this interrupt will be able to use the getch function within it as the getch function uses the RCIF flag which is also the flag used to trigger the EUSART interrupt.

Her is my code, sorry its long but people on here seem not to like putting snippets/sections rather than the whole thing. It multiplexs a 4 digit 7-segment LED display and gets a EUSART signal for the RPM value, however I want it to continue the display even when it doesn't receive the EUSART and then effectively 'update' when it does hence the interrupt and global variables. If there is an obvious better way then im happy to be told my way is wrong.

//#include _LEGACY_HEADERS              //Added for compiler versions 9.81+
#include <stdio.h>                      //For the printf function
#include <htc.h>                        //Compiler header file
//#include "usart.h"                        //USART header file
//#include "pause.h"
//#include "SerialIn.h"
//#include "Display.h"

__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT & UNPROTECT & BORDIS & IESODIS & FCMDIS);        //Configure the PIC with generic set up

#define BAUD 2400      
#define FOSC 4000000L
#define baudsetting ((int)(FOSC/(64UL * BAUD) -1))

#define RX_PIN TRISB5
#define TX_PIN TRISB7

#define dig0 0b01111110
#define dig1 0b00110000
#define dig2 0b01101101
#define dig3 0b01111001
#define dig4 0b00110011
#define dig5 0b01011011
#define dig6 0b01011111
#define dig7 0b01110000
#define dig8 0b01111111
#define dig9 0b01111011

unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
unsigned char byte5;
unsigned char byte6;
unsigned char byte7;
unsigned char byte8;
unsigned char byte9;

unsigned RPMleft;
unsigned RPMright;

#define units 0b000001
#define tens 0b000010
#define hundreds 0b000100
#define thousands 0b001000

unsigned char RPM_unit;
unsigned char RPM_ten;
unsigned char RPM_hund;
unsigned char RPM_thou;

void interrupt isr(void);
void display_digit(unsigned char digit);
void multiplex(unsigned RPM);
void pause(unsigned usvalue);
unsigned char getch(void);
void init_comms(void);

void interrupt isr(void)
{   
    if (RCIF == 1)
    {
        byte2 = getch();                //Receive 8 bytes from the PICAXE
        byte3 = getch();
        byte4 = getch();
        byte5 = getch();
        byte6 = getch();
        byte7 = getch();
        byte8 = getch();
        byte9 = getch();

        byte2 = byte2 - 30;             //Convert the ASCII to equivilent integer
        byte3 = byte3 - 30;
        byte4 = byte4 - 30;
        byte5 = byte5 - 30;
        byte6 = byte6 - 30;
        byte7 = byte7 - 30;
        byte8 = byte8 - 30;
        byte9 = byte9 - 30;

////////Depending on which PIC is being used comment one of the following lines///////////////////////////////

        RPMleft = byte2*1000 + byte3*100 + byte4*10 + byte5;    //Save the RPM of the left prop shaft

//      RPMright = byte6*1000 + byte7*100 + byte8*10 + byte9;   //Save the RPM of the right prop shaft
    }
}

void main(void)
{
    /* General Setup */
    PORTA = 0;                          //Clear PortA
    PORTB = 0;                          //Clear PortB
    PORTC = 0;                          //Clear PortC
    TRISA = 0;                          //All PortA outputs
    TRISB = 0xFF;                       //All PortB inputs
    TRISC = 0;                          //All PortC outputs
    CM1CON0 = 0;                        //Comparators off
    CM2CON0 = 0;
    ANSEL = 0;                          //A/D module off

    INTCON = 0b11000000;                //Enable interrupts GIE = 1 (global interrupts), PEIE = 1 (periphaeral interrupts)
    PIE1 = 0b00100000;                  //Enable bit 5 RCIE = 1 (EUSART receive interrupt enable bit)

    init_comms();                       //Set up the USARTh

    while(1==1)                         //Loop Forever
    {
////////Depending on which PIC is being used comment one of the following lines////////////////////////////////////
        multiplex(RPMleft);
//      multiplex(RPMright);
    }//End while    
}//End main

unsigned char getch(void) {
    /* retrieve one byte */
    while(!RCIF)    /* set when register is not empty */
        continue;
    return RCREG;   
}

void init_comms(void)
{   
    RX_PIN = 1; 
    TX_PIN = 0;       
    SPBRG = baudsetting;        
    //Continuous 8 bit asynchronous non inverted low speed communication
    RCSTA = 0x90; // SPEN and CREN bit = 1, RX9EN = 0
    TXSTA = 0x20;//TXEN = 1, BRGH, SYNC = 0
    BAUDCTL = 0; //BRG16 = 0 
}

void multiplex(unsigned RPM)
{
    RPM_unit = RPM / 1000;                                  //Split the Left RPM value into 4 digits
    RPM_ten = (RPM / 100) % 10;
    RPM_hund = (RPM / 10) % 10;
    RPM_thou = RPM % 10;

    //Start Multiplexing

    PORTA = thousands;
    display_digit(RPM_thou);

    PORTA = hundreds;
    display_digit(RPM_hund);

    PORTA = tens;
    display_digit(RPM_ten);

    PORTA = units;
    display_digit(RPM_unit);
}

void display_digit(unsigned char digit)
{
    switch (digit)
    {
        case 0:
        PORTC = dig0;       //zero
        break;

        case 1:
        PORTC = dig1;       //one
        break;

        case 2:
        PORTC = dig2;       //two
        break;

        case 3:
        PORTC = dig3;       //three
        break;

        case 4:
        PORTC = dig4;       //four
        break;

        case 5:
        PORTC = dig5;       //five
        break;

        case 6:
        PORTC = dig6;       //six
        break;

        case 7:
        PORTC = dig7;       //seven
        break;

        case 8:
        PORTC = dig8;       //eight
        break;

        case 9:
        PORTC = dig9;       //nine
        break;
    }
}

Upvotes: 1

Views: 1802

Answers (2)

Grossu Iulian
Grossu Iulian

Reputation: 275

I like to keep interrupt service routines as short as possible and avoid delays or code that takes too long to process in them. This way the program is ready to handle new Interrupts as fast as possible.

If an interrupt occurs while you are servicing another interrupt the microprocessor will re-enter the ISR again as soon as you exit it since the Interrupt flag is set.

In your code I think you can exit the ISR after reading the first character then continue execution until the next time the RCIF flag is set. Since you can execute quite a deal of code until another byte is sent trough USART. If you create a buffer like byte[9] and a static pointer to remember which character you are receiving between ISR calls this should work.

Here is an example:

void interrupt isr(void)
{   
    static char pointer = 0;
    if (RCIF == 1)
    {
         byte[pointer]=getch();        // stores the incoming data in byte[0]-byte[8]
         pointer++;                  
         if(pointer==9)
         {
              pointer=0;               // Reset pointer
              // Other operations or flags that signal the expected data was received
         }
    }
}

Edit: I also think you need to clear the RCIF flag in software, check the datasheet to see if you need to do this manually or if the flag is cleared automatically if the buffer is empty.

Upvotes: 1

Oleg Mazurov
Oleg Mazurov

Reputation: 497

In PIC16 architecture, an interrupt can't interrupt itself. Even if you clear the flag early the ISR will continue to run until it returns.

If you need nested interrupts switch to PIC18.

Upvotes: 5

Related Questions