3.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 16-bit mode, sets the prescaler to 1:32, loads the TMR0H and TMR0L registers, clears the Interrupt flag and enables the interrupt and Timer0:

static void TMR0_Initialize(void)
{
    T0CON1 = 0x95;        /* select LFINTOSC, disable TMR0 sync, set prescaler to 1:32 */
    TMR0H = 0xDA;         /* set TMR0H reload value */
    TMR0L = 0x29;         /* set TMR0L reload value */ 
    PIR0bits.TMR0IF = 0;  /* clear the interrupt flag */
    PIE0bits.TMR0IE = 1;  /* enable TMR0 interrupt */
    T0CON0 = 0x90;        /* configure TMR0 in 16-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 */
    TMR0H = 0xDA;           /* set TMR0H reload value */
    TMR0L = 0x29;           /* set TMR0L reload value */ 
}
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 true */
    if(PIE0bits.TMR0IE == 1 && PIR0bits.TMR0IF == 1)
    {
        TMR0_ISR();
    }
}
The main function will call all the initializing functions and will turn on the LED0 for 100 ms and put the microcontroller to Sleep using the SLEEP() instruction. Additionally, prior to the main function, the _XTAL_FREQ symbol must be defined and set to 1000000 (equivalent to the 1 MHz system frequency) for the use of the __delay_ms() function:
#define _XTAL_FREQ                  1000000UL  

void main(void) 
{   
    CLK_Initialize();
    PORT_Initialize();
    TMR0_Initialize();
    INTERRUPT_Initialize();
    
    while(1)
    {
        LATEbits.LATE0 = 0;    /* turn LED ON */
        __delay_ms(100);       /* wait 100 ms */
        LATEbits.LATE0 = 1;    /* turn LED OFF */
        
        SLEEP();
    }
}