Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Interrupt handling in PIC18F4550

Status
Not open for further replies.

freeze32

Newbie level 4
Joined
Jan 27, 2010
Messages
7
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Location
India
Activity points
1,337
Hi,

I am trying to use the interrupt in PIC 18F4550. I have written my code in C, and am using the MPLabs IDE.

The problem I am facing is that once I give the interrupt, it does not take interrupt again for next 30 seconds. I am clueless about this problem. Any help would be welcomed :)

Currently I am using the external interrupt, but I can use the PORTB interrupt as well...

Thanks in advance
 

Could you post the interrupt routine source code?
 

Hi,

Thanks for your prompt reply. Here goes the code.

Code:
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
{
    _asm goto _startup _endasm
}
#pragma code

#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
void _high_ISR (void)
{
    _asm goto change _endasm
}
#pragma code _LOW_INTERRUPT_VECTOR = 0x000818
void _low_ISR (void)
{
     ;
}
#pragma code

void change(void)
{
  	 
	INTCON3bits.INT1IF = 0;
}
[/code]
 

Hi,
Which compiler are you using?
As far as I know, PIC18F4550 does not have vectored interrupts.
Tahmid.
 

Hi Tahmid,

I am using the MPLabs IDE; MCC18 compiler.
 

Hi,
Try this:
Code:
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
	INTCON3bits.INT1IF = 0; //CLEAR INT FLAG
}

Added after 50 seconds:

The high interrupt vector = 0x08, not 0x808, low vector = 0x18, not 0x818.
Hope it helps.
Tahmid.
 

Thanks for the code Tahmid,

It is working with this code as well, but the problem persists. After responding to the interrupt for the first time, it responds again only after 15-20 seconds.

I am posting the whole code, just for info... (have removed the code for LCD, and delay; for the sake of easier navigation)

Code:
/** I N C L U D E S **********************************************************/
#include <p18f4550.h>
#include<adc.h>
#include<delays.h>
#include<timers.h>
#include<portb.h>

/** V A R I A B L E S ********************************************************/
#pragma udata

 

//void change(void);
void high_isr(void);
void initall(void);
void init_LCD4(void);
void OpenLCD(void);
void WriteCmd(unsigned char a);
void WriteChar(unsigned char a);
void WriteString(char* tolcd);
void WriteStringL(char* tolcd,int l);
void WriteInt(int i,int l);
void WriteLong(long i,int l);
void WriteULong(unsigned long i,int l);
void ClearScreen(void);
void ResetCursor(void);
void MoveToDisplay(unsigned char a);
void ShiftDisplayRight(int i);
void ShiftDisplayLeft(int i);
void LCDinit(void);

void Delay_s(int i);
void Delay_ms(int i);
void Delay_us(int i);
/** V E C T O R  R E M A P P I N G *******************************************/

extern void _startup (void);        // See c018i.c in your C18 compiler dir


#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
{
    _asm goto _startup _endasm
}
#pragma code


#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
   INTCON3bits.INT1IF = 0; //CLEAR INT FLAG
}


/** D E C L A R A T I O N S **************************************************/
#pragma code


 	

/*******LCD************/
#define RS              PORTAbits.RA3
#define E               PORTAbits.RA4 

//CONTROL PINS

#define DAT4	PORTAbits.RA5
#define DAT5	PORTEbits.RE0
#define DAT6	PORTEbits.RE1
#define DAT7	PORTEbits.RE2	

//Test LEDs
#define LED1	PORTDbits.RD1
#define LED2	PORTBbits.RB2
#define LED3	PORTBbits.RB0


#define Flow_bit	PORTBbits.RB1	//For interrupt check



void initall(void){
		
	
	TRISAbits.TRISA3=0; 
	TRISAbits.TRISA4=0; 
	TRISAbits.TRISA5=0; 
	TRISEbits.TRISE0=0; 
	TRISEbits.TRISE1=0; 
	TRISEbits.TRISE2=0; 

	TRISBbits.TRISB1=1;
	TRISBbits.TRISB0=0; 
	TRISBbits.TRISB2=0;
 
	TRISDbits.TRISD1=0; 
}





void EnableExternalTimers(void)
{
	T1CONbits.TMR1ON=0;			// stop timer
	T1CONbits.TMR1CS=1;			// transition on T13CKI pin
	T1CONbits.T1CKPS1=0;		// prescalar 00
	T1CONbits.T1CKPS0=0;		// prescalar 00
	T1CONbits.T1RUN=0;			// device clock from another source
	T1CONbits.T1OSCEN=0;		// osc shut for power
	T1CONbits.T1SYNC=0;			// syncronisation
	TMR1H = 0;                  // clear timer
  	TMR1L = 0;                  // clear timer
	T1CONbits.TMR1ON=1;			// start timer
	PIE1bits.TMR1IE = 0;		// interrupt disable
}




//#pragma interrupt change


void main(void)
{
	int a = 0;
	int b=0;
	int c=0;
	char z[9] = "IIT Delhi";
	char z1[7] = "BTP-SWH";

    ADCON1 |= 0x0D;                 // Default all pins to digital, except 2
	
	OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_16_TAD , ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS , ADC_1ANA );	//robotics club
	//OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_16_TAD , ADC_CH1 & ADC_INT_OFF & ADC_REF_VDD_VSS , ADC_2ANA );
	
    EnableExternalTimers();

   	initall();	LCDinit();	ClearScreen();

	WriteStringL(z,9);	Delay_ms(1000);	ClearScreen();
	WriteStringL(z1,7);	Delay_ms(1000);	ClearScreen();
	WriteInt(9,2);	Delay_ms(1000);	ClearScreen();
	
	

		
	WDTCONbits.SWDTEN = 0; //WDT disabled

	//RCONbits.IPEN = 1;	//Enabling high priority interrupt
	INTCON3bits.INT1IF =0;	//External interrupt 1 Flag
    INTCONbits.GIE = 1;	//Global interrupt enable
	
	INTCON3bits.INT1IE = 1;	//External interrupt 1 enable
	INTCON2bits.INTEDG1 = 1;	//Rising edge interrupt
	//INTCON3bits.INT1IP = 1;	//High Priority interrupt

	while(1)
   {		
		LED1 = 1;		Delay_ms(100);
	

		Sleep();
		INTCONbits.GIE = 1;
		INTCON3bits.INT1IE = 1;
		INTCON2bits.INTEDG1 = 1;	


		LED1 = 0;		Delay_ms(100);

		WriteStringL(z,9);		Delay_ms(1000);		ClearScreen();
				 
	}
}

//end 



/** EOF Demo02.c *************************************************************/
 

Hi,
In the while loop, you go to sleep, but I don't think you need to set the GIE, INT1IE, INTEDG1 bits again. Try removing these three lines.
Other than that, I can't see anything wrong.
Tahmid.

Added after 2 minutes:

O, And change this:
Code:
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
to
Code:
#pragma code _RESET_INTERRUPT_VECTOR = 0x00000
See what happens.
 

Hi,
I removed the line enabling different bits form the while loop, still it takes the second interrupt after 20-30 seconds.

And also changing the interrupt vector address gives the following error
MPLINK 4.21, Linker
Copyright (c) 2008 Microchip Technology Inc.
Error - section '_entry_scn' can not fit the absolute section. Section '_entry_scn' start=0x00000000, length=0x00000006
Errors : 1

Still not able to get the proper functioning of the PIC.

And one more question does it matter where we remap the registers? I dont know but it may be that high interrupt vector has a offset of 0x08 and low interrupt vector has offset 0x18 w.r.t. start up vector.
 

Hi,
Just a question: Why define reset vector at all? At startup, program jumps to main function, right?
Try this and see:
Code:
/** I N C L U D E S **********************************************************/
#include <p18f4550.h>
#include<adc.h>
#include<delays.h>
#include<timers.h>
#include<portb.h>

/** V A R I A B L E S ********************************************************/
#pragma udata

 

//void change(void);
void high_isr(void);
void initall(void);
void init_LCD4(void);
void OpenLCD(void);
void WriteCmd(unsigned char a);
void WriteChar(unsigned char a);
void WriteString(char* tolcd);
void WriteStringL(char* tolcd,int l);
void WriteInt(int i,int l);
void WriteLong(long i,int l);
void WriteULong(unsigned long i,int l);
void ClearScreen(void);
void ResetCursor(void);
void MoveToDisplay(unsigned char a);
void ShiftDisplayRight(int i);
void ShiftDisplayLeft(int i);
void LCDinit(void);

void Delay_s(int i);
void Delay_ms(int i);
void Delay_us(int i);
/** V E C T O R  R E M A P P I N G *******************************************/

#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
   INTCON3bits.INT1IF = 0; //CLEAR INT FLAG
}


/** D E C L A R A T I O N S **************************************************/
#pragma code


    

/*******LCD************/
#define RS              PORTAbits.RA3
#define E               PORTAbits.RA4

//CONTROL PINS

#define DAT4   PORTAbits.RA5
#define DAT5   PORTEbits.RE0
#define DAT6   PORTEbits.RE1
#define DAT7   PORTEbits.RE2   

//Test LEDs
#define LED1   PORTDbits.RD1
#define LED2   PORTBbits.RB2
#define LED3   PORTBbits.RB0


#define Flow_bit   PORTBbits.RB1   //For interrupt check



void initall(void){
      
   
   TRISAbits.TRISA3=0;
   TRISAbits.TRISA4=0;
   TRISAbits.TRISA5=0;
   TRISEbits.TRISE0=0;
   TRISEbits.TRISE1=0;
   TRISEbits.TRISE2=0;

   TRISBbits.TRISB1=1;
   TRISBbits.TRISB0=0;
   TRISBbits.TRISB2=0;
 
   TRISDbits.TRISD1=0;
}





void EnableExternalTimers(void)
{
   T1CONbits.TMR1ON=0;         // stop timer
   T1CONbits.TMR1CS=1;         // transition on T13CKI pin
   T1CONbits.T1CKPS1=0;      // prescalar 00
   T1CONbits.T1CKPS0=0;      // prescalar 00
   T1CONbits.T1RUN=0;         // device clock from another source
   T1CONbits.T1OSCEN=0;      // osc shut for power
   T1CONbits.T1SYNC=0;         // syncronisation
   TMR1H = 0;                  // clear timer
     TMR1L = 0;                  // clear timer
   T1CONbits.TMR1ON=1;         // start timer
   PIE1bits.TMR1IE = 0;      // interrupt disable
}




//#pragma interrupt change


void main(void)
{
   int a = 0;
   int b=0;
   int c=0;
   char z[9] = "IIT Delhi";
   char z1[7] = "BTP-SWH";

    ADCON1 |= 0x0D;                 // Default all pins to digital, except 2
   
   OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_16_TAD , ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS , ADC_1ANA );   //robotics club
   //OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_16_TAD , ADC_CH1 & ADC_INT_OFF & ADC_REF_VDD_VSS , ADC_2ANA );
   
    EnableExternalTimers();

      initall();   LCDinit();   ClearScreen();

   WriteStringL(z,9);   Delay_ms(1000);   ClearScreen();
   WriteStringL(z1,7);   Delay_ms(1000);   ClearScreen();
   WriteInt(9,2);   Delay_ms(1000);   ClearScreen();
   
   

      
   WDTCONbits.SWDTEN = 0; //WDT disabled

   //RCONbits.IPEN = 1;   //Enabling high priority interrupt
   INTCON3bits.INT1IF =0;   //External interrupt 1 Flag
    INTCONbits.GIE = 1;   //Global interrupt enable
   
   INTCON3bits.INT1IE = 1;   //External interrupt 1 enable
   INTCON2bits.INTEDG1 = 1;   //Rising edge interrupt
   //INTCON3bits.INT1IP = 1;   //High Priority interrupt

   while(1)
   {      
      LED1 = 1;      Delay_ms(100);
   

      Sleep();
      INTCONbits.GIE = 1;
      INTCON3bits.INT1IE = 1;
      INTCON2bits.INTEDG1 = 1;   


      LED1 = 0;      Delay_ms(100);

      WriteStringL(z,9);      Delay_ms(1000);      ClearScreen();
            
   }
}

//end
 

Hello Tahmid,

Finally it worked. The actual problem was not software related but, as we found out, hardware related.

Actually the latches inside the PIC locks the input to high; once it is given the interrupt. Thus connecting a pull down resistor solves the problem (from that port to ground).

Cheers and Thanks a lot for all the help

Nishant
 

Hi Tahmid,

I am also trying to use interrupt function in PIC18f4550 with mikro C to write my code.
I simulated my system with Proteus.

While trying to use my interrupt portb, I also use some of portB pins for my LCD display.
Below is my interrupt codes.
Please have some advice... Thanks!


void interrupt(void){

PORTD = 0x01; //To see if interrupt is triggered
//Delay_ms(2000);
}

void main(){

//----------------------------------------------------------------------------
INTCON.GIE = 1; // Disable GIE, PEIE, TMR0IE,INT0IE,RBIE
INTCON.RBIE = 1; // Disable GIE, PEIE, TMR0IE,INT0IE,RBIE

INTCON2 = 0xF5;
INTCON3 = 0xC0;
RCON.IPEN = 0; // Disable Priority Levels on interrupts
PIE1 = 0;
PIE2 = 0;
PIR1 = 0;
PIR2 = 0;
ADCON1 |= 0x0F; // Configure all ports with analog function as digital
CMCON |= 7; // Disable comparators
//----------------------------------------------------------------------------

TRISD = 0;
PORTD = 0;
PORTB = 0xFF;
TRISB = 0xFF;

Lcd_Init(); // Initialize LCD

Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off

while(1){
Lcd_Out(1,3,"Hello World");

}
}
 

To start off with, where are the LCD pin and direction definitions?
Such as this:
Code:
// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections

It's required at the beginning of your code.
Which version of mikroC are you using?
 

I already done that part above. In fact, my LCD is working properly already.
I am using MikroC 3.2. The only problem I got is on interrupt implementation.
For me to use the interrupt pins I replaced some of pins in PORTB for my LCD as shown below.

// LCD module connections
sbit LCD_RS at RB6_bit;
sbit LCD_EN at RB7_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;
sbit LCD_RS_Direction at TRISB6_bit;
sbit LCD_EN_Direction at TRISB7_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections

Note My LCD is working fine already.
 

You can't use PORTB change interrupt. From the datasheet:
Four of the PORTB pins (RB7:RB4) have an interrupt-on-change feature. Only pins configured as inputs can cause this interrupt to occur. Any RB7:RB4 pin configured as an output is excluded from the interrupt-on-change comparison.

Since you used RB4, RB5, RB6, RB7 as ouputs, you don't have any input pins for interrupt-on-change feature.

So your code is ineffective, since all it'd be doing is displaying on the LCD. However, you can use INT0 and INT1 external interrupts on RB0 and RB1. You can't also use INT2 on RB2 as this is also used for LCD.

Hope this helps.
Tahmid.
 

I will am now using portD for my LCD.
How can I initialized/configure my interrupt at PortB?
 

I've written this code and simulated it. It works fine. You should try it. I hope you can understand what I did. I'm in a hurry and I can't explain everything now. If there's something you don't understand, ask. Some one else might help you or I'll answer when I get back home.
Code:
// LCD module connections
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connections

unsigned char temp;

void interrupt(void){
RD0_bit = 1; //To see if interrupt is triggered
delay_ms(500);
RD0_bit = 0;
//Delay_ms(2000);
temp = PORTB;
RBIF_bit = 0; //Clear RB interrupt flag
}

void main(){

//----------------------------------------------------------------------------
INTCON.GIE = 1; // Disable GIE, PEIE, TMR0IE,INT0IE,RBIE
INTCON.RBIE = 1; // Disable GIE, PEIE, TMR0IE,INT0IE,RBIE

INTCON2 = 0xF5;
INTCON3 = 0xC0;
RCON.IPEN = 0; // Disable Priority Levels on interrupts
PIE1 = 0;
PIE2 = 0;
PIR1 = 0;
PIR2 = 0;
ADCON1 |= 0x0F; // Configure all ports with analog function as digital
CMCON |= 7; // Disable comparators
//----------------------------------------------------------------------------

TRISD = 0;
PORTD = 0;
PORTB = 0xFF;
TRISB = 0xFF;

Lcd_Init(); // Initialize LCD

Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off

while(1){
Lcd_Out(1,3,"Hello World");

}
}

Hope this helps.
Tahmid.
 
The code above works fine.
Thanks!

One more thing, Why is it that the interrupt will be triggered only if I applied a 5V supply to either pins of RB4-RB7?
While Pins RB0-RB3 is has no response at all!

Also, inside the interrupt function I can't use some commands (e.g. Lcd_Out(1,3,"Hello World");).
Instead I received this error: Reentrancy is not allowed: function 'Lcd_Out' called from the two threads.

My project plan was to use the interrupt when there is a key pressed in my keypad. Then I want to display the key pressed in the LCD.
Is this plan possible to accomplished? IF none, Is there any alternative or suggestion you can give?

Thank you so much!

Marven
 

Interrupt is only for RB4 to RB7. You don't have pin-change interrupt on RB0 to RB3.

You can't call LCD_Out from the interrupt.

What you should do is, in the interrupt, set a flag. In the main code, check the status of that flag. If the flag is set, then display on LCD and clear the flag.
You should be able to do this and use the keypad.

I posted some stuff here:
https://www.edaboard.com/threads/166775/

They should be of interest to you.

Hope this helps.
Tahmid.
 
Thanks for the great advices.
I'm sure that will surely do.
Thanks!


Marven
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top