Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC16F877A prevent queuing interrupts.

Status
Not open for further replies.

Kylobeetle

Member
Hello guys... some of you have helped me in my 1st post some weeks ago, im very thankful with that.

While my work lets me, im studying and doing some lil practices and I have encounter this problem that i will show below.

Im trying to work with interrupt, specially talking about uart interrupt i have made this simply program and my scope was to stay in the while(1) until some character was recieved (in this case an "ok") and then excuse some leds combination, then come back to the loop. rinse and repeat .. My problem is that I was aware that the interrupts could queue and in effect when the leds code is being executed, if you type again "ok" it will "queue" as soon it finishes it will make valid that "ok" and if you spam it, the program will freeze. Im kind of aware about the buffer overflow , with my own logic i tried to prevent this issue like this
(im about to leave and not plenty of time, if needed i can provide it, in the meanwhile, connecting through usart, making the interrupt work and others wasnt a problem.

void interrupt ISR()
{
INTCON = 0x00; //disabling
PIE1 = 0x00; //disabling
UART_Read_Text(2); // reading "ok" or any other 2 characters word (at the end it will add \0)

UART_Write_Text(rec); // print in my temrinal what it got to make myself clear that its working (this is working without problems)
__delay_ms(1000);
PORTB = 0b00000001; //leds combination just for test.
__delay_ms(1000);
PORTB = 0b00000010;
__delay_ms(1000);
PORTB = 0b00000100;
__delay_ms(1000);
PORTB = 0b00000111;
__delay_ms(1000);
PORTB = 0b00000000;
}

int main() {

TRISB = 0x00; // B as output
PORTB = 0x01; // B0 "on" for pilot purposes
OPTION_REG = 0X07;
usart_init(); // UART init module
while(1){
PORTB = 0x01;
RCREG = buff; // my try to empty the register
RCREG = buff; // my try to empty the register
__delay_ms(300);
INTCON = 0b11000000; //enabling my interrupts flags
PIE1 = 0b00100000; // //enabling my interrupts flags
PORTB = 0b00000000; // //enabling my interrupts flags
}
}


so i wanted to know how can i interrupt via usart and while the program is in process or running , how prevent the interrupt to queue again while the 1st interrupt hasnt finished yet .. i tried to keep alive the flags in the while(1) until the ISR is called to turn them off to prevent further interrupts but is not working, they are queuing . thanks in advance!


for the record i have tried to look for a similar problem with no results. I used PIC16F877A with MPLAB X XC8 compiler (last version), 4Mhz, and its configuration bits. i just tried to resume it to focus on the concept of the interrupts.
 
void interrupt ISR()
{
INTCON = 0x00; //disabling
PIE1 = 0x00; //disabling
UART_Read_Text(2); // reading "ok" or any other 2 characters word (at the end it will add \0)

UART_Write_Text(rec); // print in my temrinal what it got to make myself clear that its working (this is working without problems)
__delay_ms(1000);
PORTB = 0b00000001; //leds combination just for test.
__delay_ms(1000);
PORTB = 0b00000010;
__delay_ms(1000);
PORTB = 0b00000100;
__delay_ms(1000);
PORTB = 0b00000111;
__delay_ms(1000);
PORTB = 0b00000000;
}
This is a no no...

You cannot possibly have an interrupt that lasts 5 seconds... The interrupt should be short. and other proccesses should be done in the main loop.

ie:-

interrupt()
read usart and place in buffer..
if last char received
set all done flag​
end interrupt

Then in the main loop you can sort out displaying input!
 
This is a no no...

You cannot possibly have an interrupt that lasts 5 seconds... The interrupt should be short. and other proccesses should be done in the main loop.

ie:-

interrupt()
read usart and place in buffer..
if last char received
set all done flag​
end interrupt

Then in the main loop you can sort out displaying input!


I see. i wasnt aware of that .... what do you think if I use the interrupt to call a different function ? would it works ? i want to have different proccess in independient functions an example like this.

int main() {

TRISB = 0x00; // B as output
PORTB = 0x01; // B0 "on" for pilot purposes
OPTION_REG = 0X07;
usart_init(); // UART init module
while(1){
PORTB = 0x01;
INTCON = 0b11000000; //enabling my interrupts flags
PIE1 = 0b00100000; // //enabling my interrupts flags
PORTB = 0b00000000; // //enabling my interrupts flags
}
}

void interrupt ISR()
{

UART_Read_Text(2); // reading "ok" or any other 2 characters word (at the end it will add \0)
void program();
UART_Write_Text(rec); // print in my temrinal what it got to make myself clear that its working (this is working without problems)

}

void program()
{
INTCON = 0x00; //disabling
PIE1 = 0x00; //disabling
__delay_ms(1000);
PORTB = 0b00000001; //leds combination just for test.
__delay_ms(1000);
PORTB = 0b00000010;
__delay_ms(1000);
PORTB = 0b00000100;
__delay_ms(1000);
PORTB = 0b00000111;
__delay_ms(1000);
PORTB = 0b00000000;
}
 
You could set a flag in the interrupt. Then check it in the main program and act accordingly.
 
That was what i wanted to ask... what about this ?


volatile char flag = 1;

int main() {

TRISB = 0x00; // B as output
PORTB = 0x01; // B0 "on" for pilot purposes
OPTION_REG = 0X07;
usart_init(); // UART init module
while(1){
PORTB = 0x01;
INTCON = 0b11000000; //enabling my interrupts flags
PIE1 = 0b00100000; // //enabling my interrupts flags
PORTB = 0b00000000; // //enabling my interrupts flags
if(flag){
INTCON = 0x00; //disabling
PIE1 = 0x00; //disabling
__delay_ms(1000);
PORTB = 0b00000001; //leds combination just for test.
__delay_ms(1000);
PORTB = 0b00000010;
__delay_ms(1000);
PORTB = 0b00000100;
__delay_ms(1000);
PORTB = 0b00000111;
__delay_ms(1000);
PORTB = 0b00000000;
flag = 0;
}
}
}

void interrupt ISR()
{

UART_Read_Text(2); // reading "ok" or any other 2 characters word (at the end it will add \0)
UART_Write_Text(rec); // print in my temrinal what it got to make myself clear that its working (this is working without problems)
flag = 1;

}


what i expect is .. when i press two charecters, they will be displayed in my hyperterminal (At my pc) then procced to execute the led combination, in the meantime, no matter how many times i press my keyboard, after it finish it should wait again in the loop and not queue any further request.. what do you say about this ?
 
You can't wait in an ISR. You can use an ISR to check for OK but need to return between characters.

something like, (untested)
Code:
uint8_t count=0,flag=0,buff[2];

ISR{
    if(RCIF){
        buff[count]=RCREG;        //copy to buffer
        TXREG=buff[count];        //and echo back
        count++;
        if(count==2){            //got two chars?
            if(buff[0]='O' && buff[1]='K'){    //are they OK?
                flag=1;            //yes so set flag
                count=0;
            }else{                //no so deal with it
                buff[0]=buff[1];//scroll buffer
                count--;        //and reduce count
            }
        }
    }
}

When flag becomes 1 in your main code then you know you have received OK and can flash your LEDs.

If you reset flag as soon as you detect it then it will get set again if OK is sent while you are flashing LEDs.

Mike.
 
Last edited:
You're still trying to run massively long routines from within the ISR - as you've been told multiple times, ISR's should be as short as possible.

In your case the ISR should simply set flags, and all the long routines run outside the ISR in the main code.

For UART routines the ISR would normally place incoming data in a buffer, and your main routine can then check if there's any data in the buffer or not, or if the incoming data is terminated by CR/LF etc. then the ISR can check for that, and set a flag to tell the main program your data has arrived and is ready for processing.
 
You're still trying to run massively long routines from within the ISR - as you've been told multiple times, ISR's should be as short as possible.

In your case the ISR should simply set flags, and all the long routines run outside the ISR in the main code.

For UART routines the ISR would normally place incoming data in a buffer, and your main routine can then check if there's any data in the buffer or not, or if the incoming data is terminated by CR/LF etc. then the ISR can check for that, and set a flag to tell the main program your data has arrived and is ready for processing.

I understand took me awhile to process it.. dont you think that im doing it on purpose haha.. So i can use the ISR to check conditions and enable flags, is that correct right ? i ll try some code after i get home .



You can't wait in an ISR. You can use an ISR to check for OK but need to return between characters.

something like, (untested)
Code:
uint8_t count=0,flag=0,buff[2];

ISR{
    if(RCIF){
        buff[count]=RCREG;        //copy to buffer
        TXREG=buff[count];        //and echo back
        count++;
        if(count==2){            //got two chars?
            if(buff[0]='O' && buff[1]='K'){    //are they OK?
                flag=1;            //yes so set flag
            }else{                //no so deal with it
                buff[0]=buff[1];//scroll buffer
                count--;        //and reduce count
            }
        }
    }
}

When flag becomes 1 in your main code then you know you have received OK and can flash your LEDs.

If you reset flag as soon as you detect it then it will get set again if OK is sent while you are flashing LEDs.

Mike.

I will test this for sure.. so let me see if i got the idea... this ISR will check in there is an "OK" in the buffer if so.. if will enable the flag to 1 .. and my main code will let it run if i coded it. can i set flag=0 before the end of the if inside of my main program right? also, any recommendations to prevent to request others ISR in the meantime that my program is running ? excuse me if i missed something. Thanks in advance to everyone
 
You should only set flag equal to zero when it is defined and AFTER it has tested positive.

I.E.
Code:
if(flag==1){
    flag=0;
    //flash code
}

Mike.
 
Just to report my self i have run into some erros trying to use the code that Mike suggested ( i know that he stated that it wasnt tested) so i ll make my own respecting the rule of not wait inside of the ISR and i ll post the results ..
 
If the error was uint8_t not defined then change it to unsigned char.

Mike.
Edit, also the ISR should be "void interrupt ISR(){"
 
nope it wasnt, i foresight it, the compiler is saying this..

Main.c:44: error: (981) pointer required
Main.c:44: error: (981) pointer required
Main.c:46: error: (981) pointer required
Main.c:46: error: (981) pointer required
Main.c:46: error: (981) pointer required
Main.c:46: error: (981) pointer required
Main.c:46: error: (202) only lvalues can be assigned to or modified
Main.c:49: error: (981) pointer required
Main.c:49: error: (981) pointer required
Main.c:49: error: (981) pointer required
Main.c:49: error: (981) pointer required


seems that the part of counting needs a pointer. i was about to use one design of mine but if you help me to fix this one i can try with this one, after all , all im doing here is learning to use the ISR and testing its depths for furute stuff. thanks in advance
 
I can only see one other error,
if(buff[0]='O' && buff[1]='K'){
should be
if(buff[0]=='O' && buff[1]=='K'){

Mike.
Edit, can you post your complete code?
 
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "uart.h"
#define _XTAL_FREQ 4000000

// CONFIG
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)

/*
*
*/

//Prototypes
void TM0delay();
//void interrupt ISR();
volatile int status_flag;
volatile int a;
char buff; /* buffer to store responses and messages */
int count=0, flag=0;


void interrupt ISR()
{
if(RCIF){
buff[count]=RCREG; //copy to buffer
TXREG=buff[count]; //and echo back
count++;
if(count==2){ //got two chars?
if(buff[0]=='O' && buff[1]=='K'){ //are they OK?
flag=1; //yes so set flag
}else{ //no so deal with it
buff[0]=buff[1];//scroll buffer
count--; //and reduce count
}
}
}
}

int main() {

TRISB = 0x00; // B as output
PORTB = 0x01; // B0 "on" for pilot purposes
OPTION_REG = 0X07;
usart_init(); // UART init module
while(1){
PORTB = 0x01;
if(flag==1){
flag =0;
PORTB = 0b00000001; //leds combination just for test.
__delay_ms(1000);
PORTB = 0b00000010;
__delay_ms(1000);
PORTB = 0b00000100;
__delay_ms(1000);
PORTB = 0b00000111;
__delay_ms(1000);
PORTB = 0b00000000;
__delay_ms(300);
INTCON = 0b11000000;
PIE1 = 0b00100000;
PORTB = 0b00000000;
}
}
}

void TM0delay(){ //configuracion del registro del timer para 5 segundos con opcion a degradamiento dinamico
int i;
for(i=0;(i<152);i++){
while(!T0IF);
T0IF=0;
}
}




Im not using the timer now, but it works! im passing you the code how is it, i didnt made some fixes because i was trying to figure the errors i had first
 
You removed the brackets from the array definition.

char buff; should be char buff[2];

Mike.
Edit should say I had to remove uart.h to get it to compile.
 
Last edited:
You removed the brackets from the array definition.

char buff; should be char buff[2];

Mike.
And uart.h isn't needed.

My bad mike, that happened because i had already a variable called buff, when i saw yours, i simply ignored it but i forgot to add the [] . Im aware of the uart.h confition now, but after this test passes and i want to make it more complex and i will need the uart content. Im looking to make the ISR work, and in the mean time the program in the main is working, ISR shouldnt be triggered until the program finished what it started.

I ll test it right now i comment you .
 
When you post code you should use code tags, here is your code properly indented with code tags.

Mike.
Code:
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uart.h"

#define _XTAL_FREQ 4000000

// CONFIG
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)

/*
*
*/

//Prototypes
//void interrupt ISR();
volatile int status_flag;
volatile int a;
char buff[2]; /* buffer to store responses and messages */
int count=0, flag=0;


void interrupt ISR(){
    if(RCIF){
        buff[count]=RCREG; //copy to buffer
        TXREG=buff[count]; //and echo back
        count++;
        if(count==2){ //got two chars?
            if(buff[0]=='O' && buff[1]=='K'){ //are they OK?
                flag=1; //yes so set flag
                count=0;
            }else{ //no so deal with it
                buff[0]=buff[1];//scroll buffer
                count--; //and reduce count
            }
        }
    }
}

int main() {
    TRISB = 0x00; // B as output
    PORTB = 0x01; // B0 "on" for pilot purposes
    OPTION_REG = 0X07;
    usart_init(); // UART init module
    while(1){
        PORTB = 0x01;
        if(flag==1){
            flag =0;
            PORTB = 0b00000001; //leds combination just for test.
            __delay_ms(1000);
            PORTB = 0b00000010;
            __delay_ms(1000);
            PORTB = 0b00000100;
            __delay_ms(1000);
            PORTB = 0b00000111;
            __delay_ms(1000);
            PORTB = 0b00000000;
            __delay_ms(300);
            INTCON = 0b11000000;
            PIE1 = 0b00100000;
            PORTB = 0b00000000;
        }
    }
}
 
Last edited:
When you post code you should use code tags, here is your code properly indented with code tags.

Mike.
Code:
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uart.h"

#define _XTAL_FREQ 4000000

// CONFIG
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)

/*
*
*/

//Prototypes
//void interrupt ISR();
volatile int status_flag;
volatile int a;
char buff[2]; /* buffer to store responses and messages */
int count=0, flag=0;


void interrupt ISR(){
    if(RCIF){
        buff[count]=RCREG; //copy to buffer
        TXREG=buff[count]; //and echo back
        count++;
        if(count==2){ //got two chars?
            if(buff[0]=='O' && buff[1]=='K'){ //are they OK?
                flag=1; //yes so set flag
            }else{ //no so deal with it
                buff[0]=buff[1];//scroll buffer
                count--; //and reduce count
            }
        }
    }
}

int main() {
    TRISB = 0x00; // B as output
    PORTB = 0x01; // B0 "on" for pilot purposes
    OPTION_REG = 0X07;
    usart_init(); // UART init module
    while(1){
        PORTB = 0x01;
        if(flag==1){
            flag =0;
            PORTB = 0b00000001; //leds combination just for test.
            __delay_ms(1000);
            PORTB = 0b00000010;
            __delay_ms(1000);
            PORTB = 0b00000100;
            __delay_ms(1000);
            PORTB = 0b00000111;
            __delay_ms(1000);
            PORTB = 0b00000000;
            __delay_ms(300);
            INTCON = 0b11000000;
            PIE1 = 0b00100000;
            PORTB = 0b00000000;
        }
    }
}
I tried to use the code tags, but when i call on them, my display shows a white light shaded loading screen and nothing happens thats why im not using it, any idea how fix it ?


in the other hand, i tested the program, when you 1st write OK. it does the led cycle, but in the next time , it wont work until you type OKOKOK, (at the third one will work) Im trying to make it work as soon i call it (in this case, with an OK)
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top