7.2 Bare Metal Code
The functions and code necessary to implement the example discussed are analyzed in this section.
The first step will be to configure the microcontroller to disable the Watchdog Timer and to enable Low-Voltage Programming (LVP):
#pragma config WDTE = OFF /* WDT operating mode->WDT Disabled */
#pragma config LVP = ON /* Low voltage programming enabled, RE3 pin is MCLR */
As described in the example functionality, the following peripherals must be initialized: TMR1, the system clock, the GPIO pin and the interrupts.
The system clock was configured to use the HFINTOSC oscillator with an internal frequency of 32 MHz and the clock divided by 32, so the actual system frequency is 1 MHz. The following function is used:
/* Clock initialization function */ static void CLK_Initialize(void) { /* set HFINTOSC as new oscillator source */ OSCCON1bits.NOSC = 0x6; /* set Clock Div by 32 */ OSCCON1bits.NDIV = 0x5; /* set HFFRQ to 32MHz */ OSCFRQbits.HFFRQ = 0x6; }
The GPIO peripheral was configured to use PINB5 as input for TMR1 button. The following function is used:
/* Port initialization function */ static void PORT_Initialize(void) { /* configure RB5 as input */ TRISBbits.TRISB5 = 1; /* configure RB5 as digital */ ANSELBbits.ANSELB5 = 0; }
The TMR1 peripheral is configured in Gate Single-Pulse mode, has a clock source of 1 MHz, the counter is active on a falling edge and the peripheral gate and overflow interrupts are Active. The following function is used:
/* TMR1 initialization function */
static void TMR1_Initialize(void)
{
/* Timer controlled by gate function */
T1GCONbits.GE = 1;
/* Timer acquistion is ready */
T1GCONbits.GGO_nDONE = 1;
/* Timer gate single pulse mode enabled */
T1GCONbits.T1GSPM = 1;
/* Source Clock FOSC/4 */
T1CLKbits.CS = 0x1;
/* Clearing IF flag before enabling the interrupt */
PIR4bits.TMR1IF = 0;
/* Enabling TMR1 interrupt */
PIE4bits.TMR1IE = 1;
/* Clearing gate IF flag before enabling the interrupt */
PIR5bits.TMR1GIF = 0;
/* Enabling TMR1 gate interrupt */
PIE5bits.TMR1GIE = 1;
/* CLK Prescaler 1:8 */
T1CONbits.CKPS = 0x3;
/* TMR1 enabled */
T1CONbits.ON = 1;
}
The microcontroller’s interrupts were enabled and are used to determine the button press time. The following function is used:
/* Interrupt initialization function */ static void INTERRUPT_Initialize(void) { /* Enable the Global Interrupts */ INTCONbits.GIE = 1; /* Enable the Peripheral Interrupts */ INTCONbits.PEIE = 1; }
/* Interrupt handler function */
static void __interrupt() INTERRUPT_interruptManager(void)
{
// interrupt handler
if(INTCONbits.PEIE == 1)
{
if(PIE4bits.TMR1IE == 1 && PIR4bits.TMR1IF == 1)
{
TMR1_ISR();
}
else if(PIE5bits.TMR1GIE == 1 && PIR5bits.TMR1GIF == 1)
{
TMR1_GATE_ISR();
}
else
{
//Unhandled Interrupt
}
}
else
{
//Unhandled Interrupt
}
}
/* TMR1 ISR function */
static void TMR1_ISR(void)
{
/* Stop Gate control */
T1GCONbits.GGO_nDONE = 0;
/* Clearing overflow IF flag */
PIR4bits.TMR1IF = 0;
/* Clearing gate IF flag */
PIR5bits.TMR1GIF = 0;
/* Reset the counted value */
TMR1_writeTimer(0);
/* Prepare for next read */
T1GCONbits.GGO_nDONE = 1;
}
/* TMR1 GATE ISR function */
static void TMR1_GATE_ISR(void)
{
/* Clearing gate IF flag after button release */
PIR5bits.TMR1GIF = 0;
/* Reset the counted value */
TMR1_writeTimer(0);
/* Prepare for next read */
T1GCONbits.GGO_nDONE = 1;
}
0
’. The following function is
used:static void TMR1_writeTimer(uint16_t timerValue)
{
/* Write TMR1H value */
TMR1H = timerValue >> 8;
/* Write TMR1L value */
TMR1L = timerValue;
}