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.

PIC 16F877 interrupt on change problem

Status
Not open for further replies.

lele_75

New Member
hi all,
i'm posting a problem with my IOC routine.
i'm trying to use PORTB R5 with an IFR sensor that is normally at +5v and when a IFR barrier is sensed put RB5 to 0v causing an interrupt change on portb.
in the Interrupt Service Routine I recognize only changing on line 5 and when it happen a flag (IFR_ITR) is setted and tested in the main loop which is incrementing a counter that is resetted when this flag is setted.

the problem is that in normal condition (no IFR and no changed in signal applied to RB5) the flag IFR_ITR is set and the counter is resetted without any explanation after about 2 or 3 minutes.
i've displayed in main loop the values of RB5 (which is permanently to 1) and IFR_ITR(that in effect became 1)

any suggestion?please help me.

thankyou very much


following my ISR

Code:
void interrupt isr(void)
{
	GIE=0;
	if(INTF)                
	{                			// RB0 interrupt                
		cntr++ ;                // inc. transition counter                
		INTF = 0 ;       		// clear interrupt flag to enable next call                
	}        
	
	else if(T0IF)                
	{                			//TIMER 0 overflow                
		ovrflw++ ;              // inc. overflow counter                
		T0IF = 0 ;       		// clear interrupt flag to enable next call on overflow
	}
	else if (TMR1IF){
		cntoscurato++;
		TMR1IF=0;
	}
	else if(RBIF)                
	{   
		if (RB5==0)
		{
			IFR_ITR=1 ;              
		}
		RBIF = 0 ;       		
	} 	
	GIE=1;
}
 
The IOC will trigger when ANY of Port B bits 4-7 that are set to input change. Do you have the other bits set to output or tied high/low so they can't cause an interrupt.

BTW, no need to modify GIE, it is automatically disabled/enabled on entry/exit of an ISR.

Mike.
 
thank you for your answer.

in effect in my proto board, RB7 and RB6 is used for ICSP and is not pulled up
, RB4 is foating too.
i didn't think it was necessary to pull up or down this pin since i test in my sw only the RB5==0 case, so i thought other interrupts was ignored: is it correct?
 
If you have left RB4 floating and still input then it will cause an interrupt. However, if RB5 is permanently high then this should not cause your problem. Can you post a cut down version of your complete code that still has the problem?

Mike.
 
here is all the code.

thank you very much

Code:
#define LCD_CLR			0x01 // Clear Display
#define LCD_HOME		0x02 // Cursor to Home position


unsigned long   cntr ;          // number of RB0 transitionunsigned 
int    ovrflw ;        			// number of timer0 overflowsunsigned 
int	   IFR_ITR;
int	   cntoscurato;
int	   OSCURATO;
int    RB5_PREC;


void interrupt isr(void)
{
	GIE=0;
	if(INTF)                
	{                			// RB0 interrupt                
		cntr++ ;                // inc. transition counter                
		INTF = 0 ;       		// clear interrupt flag to enable next call                
	}        
	
	else if(T0IF)                
	{                			//TIMER 0 overflow                
		ovrflw++ ;              // inc. overflow counter                
		T0IF = 0 ;       		// clear interrupt flag to enable next call on overflow
	}
	else if (TMR1IF){
		cntoscurato++;
		TMR1IF=0;
	}
	else if(RBIF)                
	{   
		if (RB5==0)
		{
			//IFR_ITR=1 ;              // inc. overflow counter
			RB5_PREC=RB5;
		}
		RBIF = 0 ;       		// clear interrupt flag to enable next call on overflow
	} 	
	GIE=1;
}

 int getTimeToDisplay(int timeIn,char unit)
{
	
	int sec=0;
	int decSec=0;
	
	sec=(timeIn/(76.6));
	
	decSec=(timeIn-(sec*(76.6)))/(7.6);
if (unit=='s')
	return sec;
else
	return decSec;

}

/************************************************************************/
#if (LCD_COLS==20)
	#define LCD_line1	0x80 // Line 1 position 1
	#define LCD_line2	0xC0 // Line 2 position 1
	#define LCD_line3	0x94 // Line 3 position 1 (20 char LCD)
	#define LCD_line4	0xD4 // Line 4 position 1 (20 char LCD)
#else
	#define LCD_line1	0x80 // Line 1 position 1
	#define LCD_line2	0xC0 // Line 2 position 1
	#define LCD_line3	0x90 // Line 3 position 1 (16 char LCD)
	#define LCD_line4	0xD0 // Line 4 position 1 (16 char LCD)
#endif
/************************************************************************/


/****************************************/
/* 	 Enable LCD to read data	*/
/****************************************/
void LCD_STROBE (void)
{
LCD_EN = 1;
//DelayUs(1);
DelayUs(5);
LCD_EN=0;
}	

      
/****************************************/
/* 	Write a nibble to the LCD	*/
/****************************************/
void LCD_NIBBLE_OUT (unsigned char c )
{
if ( c & 0b10000000 ) 
        LCD_D7=1;
else LCD_D7=0;
if ( c & 0b01000000 ) 
        LCD_D6=1;
else LCD_D6=0;
if ( c & 0b00100000 ) 
        LCD_D5=1;
else LCD_D5=0;
if ( c & 0b00010000 ) 
        LCD_D4=1;
else LCD_D4=0;
LCD_STROBE();
}


/****************************************/
/* Write a byte to the LCD (4 bit mode) */
/****************************************/
void LCD_WRITE (unsigned char c)
{
LCD_NIBBLE_OUT(c);
c <<= 4;
LCD_NIBBLE_OUT(c);
//DelayUs(50);
DelayUs(250);
}


/****************************************/
/*       send a command to the LCD      */
/****************************************/
void LCD_CMD (char c)
{
LCD_RS = 0;	// write command
LCD_WRITE(c);
}


/****************************************/
/*  GoTO specified line and position    */
/****************************************/
void LCD_GOTO (char line,char pos)
{
switch(line)
	{
	case 1: LCD_CMD((LCD_line1-1)+pos);
		break;
	case 2: LCD_CMD((LCD_line2-1)+pos);
		break;
	case 3: LCD_CMD((LCD_line3-1)+pos);
		break;
	case 4: LCD_CMD((LCD_line4-1)+pos);
	}
}


/****************************************/
/*           Clear and Home LCD         */
/****************************************/
void LCD_CLEAR (void)
{
LCD_CMD(LCD_CLR);
//Delay(3);
Delay(15);
}


/****************************************/
/*     Write one character to the LCD   */
/****************************************/
void LCD_PUTCH (char c)
{
LCD_RS = 1;	// write characters
LCD_WRITE(c);
}


/****************************************/
/*        Write numbers to the LCD      */
/****************************************/
void LCD_PUTUN (unsigned int c)
{
unsigned char t1,i,wrote;
unsigned int k;

wrote=0;
for (i=4;i>=1;i--)
	{
	switch(i){
	case 4: k=10000;
		break;
	case 3: k=1000;
		break;
	case 2: k=100;
		break;
	case 1: k=10;
	}
	t1=c/k;
	if((wrote)||(t1!=0))
		{
		LCD_PUTCH(t1+'0');
		wrote=1;
		}
	c-=(t1*k);
	}
LCD_PUTCH(c+'0');
}
/****************************************/
void LCD_PUTSN (signed int c)
{
if(c<0)
	{ 
	LCD_PUTCH('-');
	c*=(-1);
	}
LCD_PUTUN(c);
}


/****************************************/
/*       Write a string to the LCD      */
/****************************************/
void LCD_PUTS (const char * s)
{
LCD_RS = 1;	// write characters
while(*s)
	LCD_WRITE(*s++);
}


/****************************************/
/*             Initialize LCD           */
/****************************************/	
void LCD_INIT (void)
{

LCD_RS = 0;		// write control bytes
//Delay(15);		// power on delay
Delay(75);		// power on delay
LCD_D4=1;
LCD_D5=1;
LCD_D6=0;
LCD_D7=0;
LCD_STROBE();
//Delay(5);
Delay(25);
LCD_STROBE();
//DelayUs(100);
DelayUs(500);
LCD_STROBE();
//Delay(5);
Delay(25);
LCD_D4=0;		// set 4 bit mode
LCD_STROBE();
//DelayUs(40);
DelayUs(200);



#if (LCD_ROWS==1)
LCD_WRITE(0b00100000);	// 4 bit mode, 1 line, 5x8 font
#else
LCD_WRITE(0b00101000);	// 4 bit mode, 2 or more lines, 5x8 font
#endif

LCD_WRITE(0b00001000);	// display off
LCD_WRITE(0b00001100);	// display on, curson off, blink off
LCD_WRITE(0b00000110);	// shift entry mode, display not shifted
}

/************************************************************************/
#undef LCD_ROWS
#undef LCD_COLS
/************************************************************************/
/*             		       !!! END !!!				*/
/*	   	      THANKS FOR EXAMINING MY CODE ;)			*/
/************************************************************************/
/*									*/
/*	  Please report any bug or suggestion at zypkin@inwind.it	*/
/*									*/
/************************************************************************/




void main(void)
{
	 int tempo_giro;
	 int tempo_giro_hold;	 
	 int tempo_giro_best;
	 int cnt;
	 initadc();
	 init();
     Delay(500);    // serve per stabilizzare l'alimentazione dell'lcd (l'lcd è molto lento) 
     LCD_INIT();       // INDISPENSABILE serve ad inizializzare l'LCD 
     Delay(1250);    // piccolo ritardo per completare l'inizializzazione (facoltativo) 
     LCD_CLEAR();  // Cancella il display  
     DelayUs(200);     // Altra piccola pausa (facoltativo) 

     cnt=0;
	 tempo_giro=0;
	 tempo_giro_hold=0;
	 tempo_giro_best=10000;
	 RB5_PREC=1;
     while(1) // inizio ciclo 
     { 
    	 ovrflw=0;
    	 cntr=0;
    	 IFR_ITR=0;
    	 	
    	 while(ovrflw<78){}   //attesa 1 secondo
   			tempo_giro=tempo_giro+ovrflw;
    		
    	 	if (IFR_ITR==1)
    		{
    	 		if (cntoscurato==0)
    	 		{
  			    	tempo_giro_hold=tempo_giro;
  			    	if ((tempo_giro!=0)&&(tempo_giro<tempo_giro_best))
  			        {	
  			        	tempo_giro_best=tempo_giro;
  			        }
  			    	tempo_giro=0;
  			    	TMR1ON=1;

    	 		}
    	 		else if(cntoscurato>0&&cntoscurato<200)//tempo di oscuramento
  			    {
    				TMR1ON=1;		//se sono dentro non faccio nulla
  			    }
  			    else
    			{
  			    	tempo_giro_hold=tempo_giro;
  			    	if ((tempo_giro!=0)&&(tempo_giro<tempo_giro_best))
  			        {	
  			        	tempo_giro_best=tempo_giro;
  			        }
  			        cntoscurato=0;	//se sono fuori è il primo fronte di INFRAROSSO e aggiorno i tempi
  			        //tempo_giro_hold=3;
  			        tempo_giro=0;
  			        TMR1ON=0;
    			}
    		}
    	 	if(cntoscurato>200){cntoscurato=0;TMR1ON=0;}
    	 	LCD_CLEAR();
    	 	LCD_CMD(LCD_line1);
    	 	//LCD_PUTUN(tempo_giro_hold);
    	 	//LCD_PUTS(" ");
    	 	LCD_PUTUN(cntoscurato);
    	 	LCD_PUTS(" ");
    	 	LCD_PUTUN(tempo_giro);
    	 	LCD_PUTS(" ");
    	 	LCD_PUTUN(RB5);
    	 	LCD_PUTS(" ");
    	 	LCD_PUTUN(IFR_ITR);
    	 	
   	 		LCD_CMD(LCD_line2);
	    	LCD_PUTS("LAP ");
	    	LCD_PUTUN(getTimeToDisplay(tempo_giro_hold,'s'));
	    	//LCD_PUTUN(tempo_giro_hold);
	    	LCD_PUTS(".");
	    	LCD_PUTUN(getTimeToDisplay(tempo_giro_hold,'d'));
	   	 	LCD_PUTS("| BEST ");
	   	 	if (tempo_giro_best==10000)
	   	 		LCD_PUTS(" ");
	   	 	else
	   	 		LCD_PUTUN(tempo_giro_best);
     } 
     


}


and this is the init code
Code:
#include <htc.h>


__CONFIG(HS & WDTDIS & PWRTEN & BORDIS & LVPEN & WRTEN & DEBUGDIS & DUNPROT & UNPROTECT);

// Peripheral initialization function
void init(void){
	/***** Common Code ****
	 *  Peripheral interrupts not enabled
	 *  Global interrupt disabled during initialization
	 */
	//INTCON	= 0b00000000;
	
    OPTION=0b11000111;
    // bit 0 -> Prescaler Rate Select bit 0
    // bit 1 -> Prescaler Rate Select bit 0
    // bit 2 -> Prescaler Rate Select bit 0 (1:256)
    // bit 3 -> Prescaler assegnato al Timer0 
	// bit 4 -> Non importa
    // bit 5 -> Clock per Timer0 derivato da ciclo di clock interno
    // bit 6 -> Non importa
    // bit 7 -> Resistenze di pull-up su porta B disattivate
	
	// Impostazione Interrupt
    INTCON=0b11111000;
    // bit 0 -> RBIF - Flag interrupt su porte B
    // bit 1 -> INTF - Flag interrupt su RB0/INT
    // bit 2 -> T0IF - Flag interrupt su Timer0
    // bit 3 -> RBIE, Interrupt su porte B attivato
    // bit 4 -> INTE, Interrupt su porta RB0/INT attivato
    // bit 5 -> TMR0IE, Interrupt su Timer0 attivato
    // bit 6 -> PEIE, Interrupt di periferica attivato
    // bit 7 -> GIE, Gestione Interrupt attiva
	
	TMR0 =0; // Interrupt per Timer0 ogni 1 mS
    TMR0IE=1;
    TMR1IE=1;
    //TMR1ON=1;
	
	/*
	 *  Port directions: 1=input, 0=output
	 */
	//TRISA	= 0b00000000;
	
    TRISD4=0;          //DATA 4 dell'LCD 
    TRISD5=0;          //DATA 5 
    TRISD6=0;          //DATA 6 
    TRISD7=0;          //DATA 7 
    TRISB1=0;          //RS
    TRISB4=0;          //E
    TRISB0=1;
    TRISC2=0;
    TRISB5=1;		   //INPUT INTERRUPT IFR          
    
}


void initadc(void){
	ADCON0 = 0b11001001;           
	ADCON1 = 0b00000010; 
}
 
A very quick look at your code and I can see that you don't clear IFR_ITR in the statement that acts on it. May I suggest you add this,
Code:
    	 	if (IFR_ITR==1)
    		{
                        [COLOR="Red"]IFR_ITR=0;[/COLOR]
    	 		if (cntoscurato==0)
    	 		{
  			    	tempo_giro_hold=tempo_giro;
  			    	if ((tempo_giro!=0)&&(tempo_giro<tempo_giro_best))
  			        {	
  			        	tempo_giro_best=tempo_giro;
  			        }
  			    	tempo_giro=0;
  			    	TMR1ON=1;

    	 		}
    	 		else if(cntoscurato>0&&cntoscurato<200)//tempo di oscuramento
  			    {
    				TMR1ON=1;		//se sono dentro non faccio nulla
  			    }
  			    else
    			{
  			    	tempo_giro_hold=tempo_giro;
  			    	if ((tempo_giro!=0)&&(tempo_giro<tempo_giro_best))
  			        {	
  			        	tempo_giro_best=tempo_giro;
  			        }
  			        cntoscurato=0;	//se sono fuori è il primo fronte di INFRAROSSO e aggiorno i tempi
  			        //tempo_giro_hold=3;
  			        tempo_giro=0;
  			        TMR1ON=0;
    			}
    		}
Otherwise, once set the code will always execute.

Mike.
 
thankyou,
IFR_ITR is set as first instruction in the main loop but i report onl the code fragment which manage the flag.

after one night of experiments, if i display all the values of RB4-7 the value of IFR_ITR and a different trace displa for each branch of the if code you've seen, i've noted that:

RB4-7 remain fixed
IFR_ITR toggle it's value to 1
no if branches is executed

in my opinion it seems that a "self reset" was executed in some strange condition.
watch dog is disabled, is there any condition (exception, error handling etc...)that i've to know and tha will be managed?

thanks
 
hi all,
a news about my problem:
ho provato a sostituire, nella struttura del programma, l'interrupt ad un polling su rb5.

i've tried to change my program structure implementig a polling in rb5 pin instead of interrupt.

so when RB5 goes to 0V i reset a minute/second counter otherwise the counter is incremnted to count the time since last event (RB5=0)
what it happens is that it's all right but, after about 10 minute the counter is reset and the count start again from zero by itself.
i think there could be a big error in my code but i can't understand what is wrong.
if it's necessary i can post my new code version.

thanks
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top