5.2 Bare Metal Code
The necessary code and functions to implement the presented example are analyzed in this section. The code contains seven functions and the main function that implements the previously described functionality.
/*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
oscillator, sets its frequency to 1 MHz and sets the prescaler to 4 for a operating
frequency of 250 kHz.
static void CLK_Init(void) { /* set HFINTOSC Oscillator */ OSCCON1bits.NOSC = 6; /* clk divided by 4 */ OSCCON1bits.NDIV = 4; /* set HFFRQ to 1 MHz */ OSCFRQbits.HFFRQ = 0; }
The PORT_Init
function configures the RA0 pin as analog
input.
static void PORT_Init(void) { /*set pin RA0 as analog*/ ANSELAbits.ANSELA0 = 1; /*set pin RA0 as input*/ TRISAbits.TRISA0 = 1; }
The function ADCC_Init
configures the ADCC: it enables it,
activates Continuous Conversion mode, sets the result right-justified, selects the main
clock divided by 128 as the ADCC clock.
static void ADCC_Init(void) { /* Enable the ADCC module */ ADCON0bits.ADON = 1; /* Enable continuous operation*/ ADCON0bits.ADCONT = 1; /* result right justified */ ADCON0bits.ADFM = 1; /*FOSC divided by 128*/ ADCLKbits.ADCS = 63;
It sets the number of repetitions to 16, sets the ADACLR bit, selects the Average mode and sets the number of bits that will be right-shifted at the end of a conversion to 16.
ADRPT = 16; /*clear status bits on overflow enabled (this setting prevents overflow interrupts that trigger the same interrupt as the threshold interrupt)*/ ADCON2bits.ADACLR = 1; /* Average mode */ ADCON2bits.ADMD = 2; /*result is right shifted by 16*/ ADCON2bits.ADCRS = 4;
It then selects the Error Calculation mode as the first derivative of a single measurement, the Threshold Comparison mode as the error being higher than the upper threshold or smaller than the lower threshold and sets the upper threshold to 35 and the lower threshold to -35.
/* mode: error bigger than upper threshold or lower than lower threshold*/ ADCON3bits.ADTMD = 4; /*error calculation method: difference between the last result and the current result*/ ADCON3bits.ADCALC = 0; /*upper threshold*/ ADUTH = 35; /*lower threshold*/ ADLTH = -35;
Finally, it clears the Threshold Interrupt bit and enables the Threshold interrupt.
/* Clear the ADC Threshold interrupt flag */ PIR1bits.ADTIF = 0; /* Enable ADCC threshold interrupt*/ PIE1bits.ADTIE = 1; }
The ADCC_DischargeSampleCap
function connects the ADCC
channel to VSS in order to discharge the sampling capacitor.
static void ADCC_DischargeSampleCap(void)
{
/*channel number that connects to VSS*/
ADPCH = 0x3C;
}
The INTERRUPT_Init
function enables the global and
peripheral interrupts.
static void INTERRUPT_Init(void) { /* Enable global interrupts */ INTCONbits.GIE = 1; /* Enable peripheral interrupts */ INTCONbits.PEIE = 1; }
The ADCC_StartConversion
function selects the RA0 analog
channel for the ADCC and starts the conversion by setting the ADGO bit in the ADCON0
register. The channel number to connect to pin RA0 is 0x00
.
static void ADCC_StartConversion(uint8_t channel) { ADPCH = channel; /* Start the conversion */ ADCON0bits.ADGO = 1; }
The INTERRUPT_InterruptManager
function is called at every
interrupt. It checks to see if the peripheral interrupts are enabled and then checks to
see if the ADCC threshold interrupt is enabled and triggered. It then calls
ADCC_ThresholdISR
to store the value of the error into the
errVal
variable.
void __interrupt() INTERRUPT_InterruptManager(void) { if (INTCONbits.PEIE) { if ((PIE1bits.ADTIE) && (PIR1bits.ADTIF)) { ADCC_ThresholdISR(); } } } static void ADCC_ThresholdISR(void) { /*read the error*/ errVal = ((ADERRH << 8) + ADERRL); /*clear interrupt flag*/ PIR1bits.ADTIF = 0; }
The main
function calls the previously described functions
in order and then waits for the interrupt. The variable can be checked with a debugger
after an interrupt has been triggered,
void main(void) { CLK_Init(); PORT_Init(); ADCC_Init(); ADCC_DischargeSampleCap(); INTERRUPT_Init(); /*channel number that connects to RA0*/ ADCC_StartConversion(0x00); while (1) { ; } }