Electronics > Microcontrollers

Timer interrupt for pic18f4550

(1/2) > >>


I am trying to make a 50Hz pwm signal using interrupt and timer 0, however, i have tried a number of examples and i can't get the program to enter in the interrupt. I have tried a lot of configs, and i still can't get a single interrupt to work.
I am using pic18f4550 with usb bootloader .
I may have some extra config i don't need, and some missing config i need, so please feel free to correct me.

This is my code:

#include <p18f4550.h>

#pragma code REMAPPED_RESET_VECTOR=0x1000      //Because of the bootloader
extern void _startup (void);

void _reset (void)
   _asm goto _startup _endasm

void high_isr(void);

#pragma code
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
  _asm GOTO high_isr _endasm

#pragma code
/*****************High priority ISR **************************/

#pragma interrupt high_isr
void high_isr (void)
       if (INTCONbits.TMR0IF){  // Interrupt Check   
                INTCONbits.TMR0IF = 0;                 
                TMR0H = 0xEE;        //Timer0 initializare
                TMR0L = 0xEE;
            PORTBbits.RB7 = 0;                   


void main(void)
   unsigned int second, check;
// config interrupt   
   INTCON = 0x20;             
   INTCON2 = 0x04;               //TMR0 high priority
    RCONbits.IPEN = 1;            //enable priority levels

// Timer0 configuration
   T0CONbits.TMR0ON = 0; // Stop the timer
   T0CONbits.T08BIT = 0; // Run in 16-bit mode
   T0CONbits.T0CS = 0; // Use system clock to increment timer
   T0CONbits.PSA = 0; // A prescaler is assigned for Timer0
   T0CONbits.T0PS2 = 1; // Use a 1:256 prescaler
   T0CONbits.T0PS1 = 1;
   T0CONbits.T0PS0 = 1;

   INTCONbits.GIEH = 0;
   INTCONbits.TMR0IE = 1;      //1 = Enables the TMR0 overflow interrupt
   INTCONbits.TMR0IF = 0;
   INTCONbits.INT0IF = 0;      //1 = The INT0 external interrupt occurred (must be cleared in software)

   T0CONbits.TMR0ON = 1;      // Start the timer

   TMR0L = 0x82;      //(255-130)*4/Fosc *prescaler=0.05ms
              TMR0H = 0x85;
              INTCONbits.GIEH = 1;          //enable interrupts

   // LED configuration
   TRISB = 0; // Configure portb as an output
   PORTBbits.RB7 = 1;

   while(1) // Program loop


Just and though.
I don't really know the PIC interrupt syntax but with some micros you have to be careful using interrupts when you have a bootloader.
You can end up with interrupts in a memory area assigned for bootloader code and then be unable to call them from main.
Especially if you have played with the fuse bits to lockdown main code reading bootloader memory and/or vice versa.

This is working for me, but I'm using a different compiler, you can use it as a reference.

// I N T E R R U P T   S E R V I C E S   **********************************************************
#pragma interrupt HighPriorityInt
void HighPriorityInt(void)

#pragma interruptlow LowPriorityInt
void LowPriorityInt(void)

if ( INTCONbits.TMR0IF == 1)
   PORTBbits.RB7 = 1;
   INTCONbits.TMR0IF = 0;                        //Need to clear timer interuption flag 
   TMR0L = Timer_Low;                            //Init value for Counter
   TMR0H = Timer_High;                           //Init value for Counter
   PORTBbits.RB7 = 0;


// 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 HighPriorityInt _endasm
#pragma code low_vector=0x18

void interrupt_at_low_vector(void)
    _asm goto LowPriorityInt _endasm
#pragma code

// *** Interrupt configuration *** //
INTCONbits.TMR0IF = 0;                           //Clear timer interuption flag 
RCONbits.IPEN = 0;                               //Enable/Disable priority levels
INTCONbits.GIEH = 0;                             //Enable/Disable high priority interrupt
INTCONbits.GIEL = 0;                             //Enable/Disable low priority interrupt
INTCONbits.TMR0IE = 0;                           //Enable/Disable Timer 0 interrupt
INTCON2bits.TMR0IP = 0;                          //Timer 0 is low priority interrupt

// *** Timer 0 Configuration *** //
T0CONbits.T08BIT = 0;                            //1=8 bit timer, 0=16 bit timer
T0CONbits.T0CS = 0;                              //Use internal clock, use as Timer
T0CONbits.PSA = 1;                               //Do not use prescaler

TMR0L = Timer_Low;                               //Init value for Timer 0
TMR0H = Timer_High;                              //Init value for Timer 0
T0CONbits.TMR0ON = 0;                            //Enable Timer = 1 Disable Timer = 0


T0CONbits.TMR0ON = 1;                            //Enable Timer = 1 Disable Timer = 0

Should be 1, I had it temporary disabled for some testing.

At the very least...

--- Quote ---TMR0H is not the actual high byte of Timer0 in 16-bit mode. It is actually a buffered version of the real high
byte of Timer0 which is not directly readable nor writable (refer to Figure 11-2). TMR0H is updated with
the contents of the high byte of Timer0 during a read of TMR0L. This provides the ability to read all 16 bits of
Timer0 without having to verify that the read of the high and low byte were valid, due to a rollover between
successive reads of the high and low byte.

Similarly, a write to the high byte of Timer0 must also take place through the TMR0H Buffer register. The high
byte is updated with the contents of TMR0H when a write occurs to TMR0L. This allows all 16 bits of Timer0
to be updated at once.
--- End quote ---

So, to set TH & TL you MUST write the values in the correct order

TMR0H = Timer_High;      // must set TH before writing to TL
TMR0L = Timer_Low;       // writing to TL updates TL and TH

Your code may appear to work but in reality the first interrupt will be slow to appear, after that the value you set in TH will be the previous value written to the TH buffer, not necessarily the value currently in Timer_High.

You have the same problem in your initialisation code

TMR0L = 0x82;      //(255-130)*4/Fosc *prescaler=0.05ms
TMR0H = 0x85;

So, TL = 0x82, the TH buffer = 0x85 but the actual TH register = ?? ie whatever happened to be in the TH buffer at the time TL was written, after a reset it could well be zero.

In this case you are running a 1/255 prescaler. At 8MHz: 8000000 / 4 / 256 = 7812.5Hz timer frequency, assuming 0 in TH your count to interrupt will be around 0xff00 (65280), 65280 * 1 / 7812.5 = 8.35584 seconds

You appear to be running at 2MHz (? from the TMR0L comment above), so the time to your first interrupt will be around 40 seconds, after which you will run at your 0xEEEE timings.

Your code looks feasible, are you perhaps declaring the code bad before the 40 seconds are up? I've certainly done this at least once... or twice ;)


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version