2.2 Bare Metal Code

First, the Watchdog Timer has to be disabled and Low-Voltage Programming (LVP) has to be enabled using the following pragma code:

#pragma config WDTE = OFF   /* WDT operating mode->WDT Disabled */ 
#pragma config LVP = ON     /* Low voltage programming enabled, RE3 pin is MCLR */  

The following function initializes the system clock to have the HFINTOSC oscillator as input clock and to run at 1 MHz:

static void CLK_Initialize(void)
{ 
    OSCCON1 = 0x60;    /* set HFINTOSC as new oscillator source */
    OSCFRQ = 0x00;     /* set HFFRQ to 1 MHz */
}

The following function initializes the RE0 pin (corresponding to the on-board LED0) as output pin:

static void PORT_Initialize(void)
{
    TRISEbits.TRISE0 = 0;   /* configure RE0 as output */
}

The following function initializes Timer0 in 8-bit mode, sets the prescaler to 1:16, loads TMR0H and TMR0L registers, clears the Interrupt flag, and enables the interrupt and Timer0:

static void TMR0_Initialize(void)
{
    T0CON1 = 0x94;        /* Select LFINTOSC, set the prescaler to 1:16, Disable TMR0 sync */
    TMR0H = 0xC1;         /* Load the compare value to TMR0H */ 
    TMR0L = 0x00;         /* Load the reset value to TMR0L */ 
    PIR0bits.TMR0IF = 0;  /* clear the interrupt flag */
    PIE0bits.TMR0IE = 1;  /* enable TMR0 interrupt */
    T0CON0 = 0x80;        /* Configure TMR0 in 8-bit mode and enable TMR0 */
}

The following function enables the global and peripheral interrupts:

static void INTERRUPT_Initialize(void)
{
    INTCONbits.GIE = 1;   /* Enable the Global Interrupts */
    INTCONbits.PEIE = 1;  /* Enable the Peripheral Interrupts */
}
The following function handles the Timer0 interrupt and it is called in the interrupt manager function:
static void TMR0_ISR(void)
{
    PIR0bits.TMR0IF = 0;                /* clear the TMR0 interrupt flag */
    LATEbits.LATE0 = ~LATEbits.LATE0;   /* toggle LED0 */
}
The following function handles the interrupts in the project:
void __interrupt() INTERRUPT_InterruptManager (void)
{
    /* Check if TMR0 interrupt is enabled and if the interrupt flag is set */
    if(PIE0bits.TMR0IE == 1 && PIR0bits.TMR0IF == 1)
    {
        TMR0_ISR();
    }
}
The main function will call all the initializing functions and run all the peripherals in an infinite empty loop:
void main(void) 
{   
    CLK_Initialize();
    PORT_Initialize();
    TMR0_Initialize();
    INTERRUPT_Initialize();
    
    while(1)
    {
        ;
    }
}