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.

Please help me with my Interrupts

Status
Not open for further replies.

Wilko

New Member
I am currently working on a piece of code that uses two interrupt routines. A high priority and a low priority. I will be using the PIC18F4620 but currently only debugging in simulation mode in MPLAB (v7.60). I am using the MCC18 library to compile my code.
I am using a 20Mhz external oscillating crystal.

This is what i would like to happen:
Timer0 interrupts as a high priority
Timer1 interrupts as a low priority

This is what happens:
Timer0 interrupts as it should
Timer1 just sits there watching tea while drinking hot chocolate!

I would be very grateful if you can tell me where I've gone wrong.

All I care about is my interrupt flag..and my hair loss due to stress...

Here is my code, I realise its really unclear but I've tampered with it so many times its got messy.

#include <p18f4620.h>
#include <timers.h>
#include <stdio.h>
#include <delays.h>


void power (void);
void signal (void);
unsigned int ReadTimer0(void);
unsigned int ReadTimer1 (void);
void WriteTimer0( unsigned int timer );
void Delay100TCYx( unsigned char unit );
void Delay10TCYx( unsigned char unit );
void HandlerHigh (void);
void HandlerLow (void);

int number = 15;
unsigned char clock = 0;
unsigned char clock2 = 0;
int servo_flag = 0;

void main (void)
{
int Time = 0;

INTCON = 0x20; //disable global and enable TMR0 interrupt
INTCON2 = 0x84; //TMR0 high priority
IPR1 = 0x00; //TMR1 low priority
RCONbits.IPEN = 1; //enable priority levels
INTCONbits.GIEH = 1; //enable interrupts
INTCONbits.GIEL = 1; //enable low interrupts
OpenTimer0(TIMER_INT_ON & T0_8BIT & T0_SOURCE_INT & T0_PS_1_128);
T0CONbits.TMR0ON = 1;
TMR1H = 0;
TMR1L = 0;
T1CON = 0x13; /*b'00001001' */
PIE1bits.TMR1IE = 1;
RCONbits.IPEN = 1;

power();


while (1)
{
// clock++;
// signal(); //send out servo signal
}
}

void signal (void)
{
if (servo_flag == 1)
{
PORTAbits.RA1 = 1;
servo_flag = 0;
}

if (clock >= 100)
{
PORTAbits.RA1 = 0;

}
}

/*Set a Led to show PIC is running*/
void power (void)
{
ADCON1 = 0x0f;
TRISA = 0x00000110;
PORTA = 0;
PORTAbits.RA0 = 1;
}


//----------------------------------------------------------------------------
// High priority interrupt vector

#pragma code VectorHigh = 0x08
void VectorHigh (void)
{
_asm
goto HandlerHigh //jump to interrupt routine
_endasm
}

//----------------------------------------------------------------------------
// High priority interrupt routine

#pragma code
#pragma interrupt HandlerHigh

void HandlerHigh (void)
{
if (INTCONbits.TMR0IF) //check for TMR0 overflow
{
clock++;
INTCONbits.TMR0IF = 0; //clear interrupt flag
}
if (clock > 2)
{
clock = 0;
servo_flag = 1;
}

}
//----------------------------------------------------------------------------
// Low priority interrupt vector
#pragma code VectorLow = 0x18
void VectorLow (void)
{
_asm
goto HandlerLow
_endasm
}

//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt HandlerLow
void HandlerLow (void)
{
if (PIR1bits.TMR1IF) //check for TMR1 overflow
{
clock2++;
PIR1bits.TMR1IF = 0; //clear interrupt flag
}
}

// END

Please don't just recommend me to use OpenTimer1() unless you can inform me what needs to go in there. I tried this method first and failed.

Thanks for reading,

James
 
I believe your problem lies here:
T1CON = 0x13; /*b'00001001' */
The HEX doesn't match the binary. The HEX is setting up timer1 to use external clock from pin RC0/T1OSO/T13CKI. Which clock do you intend to use with timer1? For SIM, I would use the internal clock for simplicity.
 
Last edited:
Actually I want to use an external clock source. The same for timer0 and timer1. Timer zero is set to interrupt around20ms and timer1 needs to be 100us. Don't suppose you can see why timer1 interrupts so slowly. I've tried changing the pre scaler but nothing changes.
 
I've updated my code and now both my interrupts work but only if i use an internal clock and then it runs at the wrong speed. I want timer0 to interrupt every 20ms and timer1 as 100us. Im trying to get my code to use an external 20Mhz crystal but just no luck.

#include <p18f4620.h>
#include <timers.h>
#include <stdio.h>
#include <delays.h>


void power (void);
void signal (void);
//unsigned int ReadTimer0(void);
//unsigned int ReadTimer1 (void);

void HandlerHigh (void);
void HandlerLow (void);

int number = 15;
unsigned char clock = 0;
unsigned char clock2 = 0;
int servo_flag = 0;

void main (void)
{
int Time = 0;

INTCON = 0x20; //disable global and enable TMR0 interrupt
INTCON2 = 0x84; //TMR0 high priority
IPR1 = 0x00; //TMR1 low priority
RCONbits.IPEN = 1; //enable priority levels
INTCONbits.GIEH = 1; //enable interrupts
INTCONbits.GIEL = 1; //enable low interrupts
OpenTimer0(TIMER_INT_ON & T0_8BIT & T0_SOURCE_EXT & T0_PS_1_128);
// T0CONbits.TMR0ON = 1;
// TMR1H = 0;
// TMR1L = 0;
// T1CON = 0x09; /*b'00001001'*/
PIE1bits.TMR1IE = 1;
RCONbits.IPEN = 1;
OpenTimer1(TIMER_INT_ON & T1_8BIT_RW & T1_SOURCE_EXT & T1_PS_1_2);
power();


while (1)
{
clock++;
signal(); //send out servo signal
}
}

void signal (void)
{
if (servo_flag == 1)
{
PORTAbits.RA1 = 1;
servo_flag = 0;
}

if (clock >= 100)
{
PORTAbits.RA1 = 0;
}
}

/*Set a Led to show PIC is running*/
void power (void)
{
ADCON1 = 0x0f;
TRISA = 0x00000110;
PORTA = 0;
PORTAbits.RA0 = 1;
}


//----------------------------------------------------------------------------
// High priority interrupt vector

#pragma code VectorHigh = 0x08
void VectorHigh (void)
{
_asm
goto HandlerHigh //jump to interrupt routine
_endasm
}

//----------------------------------------------------------------------------
// High priority interrupt routine

#pragma code
#pragma interrupt HandlerHigh

void HandlerHigh (void)
{
if (INTCONbits.TMR0IF) //check for TMR0 overflow
{
clock++;
INTCONbits.TMR0IF = 0; //clear interrupt flag
}
if (clock > 2)
{
clock = 0;
servo_flag = 1;
}

}
//----------------------------------------------------------------------------
// Low priority interrupt vector
#pragma code VectorLow = 0x18
void VectorLow (void)
{
_asm
goto HandlerLow
_endasm
}

//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt HandlerLow
void HandlerLow (void)
{
if (PIR1bits.TMR1IF) //check for TMR1 overflow
{
clock2++;
PIR1bits.TMR1IF = 0; //clear interrupt flag
}
}
 
To use an external clock for the timers in the SIM you need to open the SCL workbook. It's located under Debugger/SCL Generator/NewWorkBook. Click the clock stimulus tab and fill in the necessary info, save your workbook and then Generate SCL from Workbook. Close the workbook and then open the Stimulus Controller under Debugger/Stimulus Controller/NewScenario. Now load the file you created with the SCL generator by attaching the file here. Leave this window active while you run the simulation and it will toggle the pin as per your setup.
Im trying to get my code to use an external 20Mhz crystal but just no luck.
Under Debugger/Settings... you can set the processor speed.
 
Thank you.

One last problem..Why is my timer1 taking so long to interrupt? it seems to always take around 13ms (using internal clock set in SIM as 20MHz). I'm after 100us or at least close to that.

Thanks guys
 
Timer1 is a 16bit timer and you are getting an interrupt when it rolls over. Timer0 is an 8bit timer and it can roll over 256 times faster. You need to preload timer1 during every interrupt by doing some thing like this:
TMR1H |= 0xF0;
Don't try to load TMR1L directly (TMR1L = 0xE0) because interrupt latency will add cumulative errors. Use the Or function instead.
 
Last edited:
You can also use the Special Events Trigger of the CCP module. This makes the CCP1 value a 16 bit period for timer1. Have a look at section 15.3.4 & 12.5 of the data sheet for details. Note that the interrupt generated is the CCP int, not the timer1 int.

Mike.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top