3.2 Bare Metal Code

The necessary code and functions to implement the presented example are analyzed in this section. It has five functions: three of them configure the ADCC, FVR and the main oscillator and one discharges the sample capacitor. The last one initiates the conversion on the temperature channel.

The first step will be to configure the microcontroller to disable the Watchdog Timer (WDT) and to enable low-voltage programming.

/*disable Watchdog*/
#pragma config WDTE = OFF
/* Low voltage programming enabled, RE3 pin is MCLR */
#pragma config LVP = ON 
The CLK_Init function selects HFINTOSC as the main osciilator and sets the frequency to 1 MHz.
static void CLK_Init(void)
{
    /* set HFINTOSC Oscillator */
    OSCCON1bits.NOSC = 6;
    /* set HFFRQ to 1 MHz */
    OSCFRQbits.HFFRQ = 0;
}

The FVR_Init function enables the Fixed Voltage Reference (FVR) and the temperature sensor. The sensor is configured to work on the low range as the high range requires an operating voltage above 3.6V.

static void FVR_Init(void)
{
    /*Enable temperature sensor*/
    FVRCONbits.TSEN = 1;
    /*Enable FVR*/
    FVRCONbits.FVREN = 1;
}
The ADCC_Init function configures the peripheral to use its FRC clock and give the results right justified.
static void ADCC_Init(void)
{
    /* Enable the ADCC module */
    ADCON0bits.ADON = 1; 
    /* Select FRC clock */
    ADCON0bits.ADCS = 1;
    /* result right justified */
    ADCON0bits.ADFM = 1;
}
The ADCC_DischargeSampleCap function connects the ADCC channel to VSS to discharge the sampling capacitor and provide accurate results.
static void ADCC_DischargeSampleCap(void)
{
    /*channel number that connects to VSS*/
    ADPCH = 0x3C;
}
The ADCC_ReadValue function initiates the conversion on the temperature channel, waits for it to end and returns the value. The channel number to connect to the temperature sensor is 0x3C.
static uint16_t ADCC_ReadValue(uint8_t channel)
{   
    ADPCH = channel;
    /*start conversion*/
    ADCON0bits.ADGO = 1;
    while (ADCON0bits.ADGO)
    {
        ;
    }
        
    return ((uint16_t)((ADRESH << 8) + ADRESL));
}

The value from the ADC is then converted to Celsius and Fahrenheit values that give the temperature of the device. The variables can be checked with the debugger.

#define VDD                                 3.3
#define ADC_TO_CELSIUS(adcVal)              (int16_t) \
                ((1241.4967 - VDD * (1024 - (adcVal))) / 2.70336)
#define ADC_TO_FAHRENHEIT(adcVal)           (int16_t) \
                ((((1241.4967 - VDD * (1024 - (adcVal))) / 2.70336) * 1.8) + 32)