Snippet:ADC

From Curuxa

These snippets show how to use the Analog-to-Digital converter (ADC) on the Main Boards. An ADC lets you measure the real voltage on a microcontroller pin/data connector and the result will be stored in a variable you can easily read and maniputale in your program.

To know which pins can be used as analog inputs, see section Device Overview -> Pinout Description in the datasheet of your microcontroller.

To know exactly how the analog-to-digital converter (ADC) works, see section Analog-to-Digital Converter (ADC) Module in the datasheet. There you'll also find explanations about how to do anything, and what each bit/byte means.

All microcontrollers used in Curuxa Main Boards give results as a 10-bit variable. This means that the ADC will measure the voltage at a specified pin and you'll read a variable with a value between 0 and 1023, being "0" when there are exactly 0V at that pin, and "1023" when there are 5V. For example, if the ADC conversion returns a value of 673, there are around 3.29V.

Contents

Disable ADC

By default, the ADC is enabled on most microcontrollers. This means that if you don't disable it, the microcontroller pins multiplexed as analog inputs, digital I/O and other features (this means that a single pin can be configured to do different tasks depending on what you need) will be setup as analog inputs by default.

MBP8, MBP14, MBP18

//Disable Analog-to-Digital converter
void AdcDisable(){
	ADON=0;
	ANSEL=0;
}

MBP40

//Disable Analog-to-Digital converter on a MBP40
void AdcDisable(){
	ADON=0;
	ANSEL=0;
	ANSELH=0;
}


Setup one pin as analog input

Before making an analog conversion (taking a measurement) you usually need to setup that pin as a digital input (so it's not used as an output), then set the same pin as analog input, and finally, since each microcontroller has only one ADC but multiple pins can be set as analog inputs, you have to choose the channel to specify which one of the analog inputs will be used by the ADC module to take the measurement.

Some of these methods use some macro definitions.

MBP8

//Set AN2 as analog input, and use it as the source for the ADC conversion
void EnableAN2(){
	SetBit(TRISIO, 2);
        //use channel 0b110 (AN3) as the analog input for the ADC
	ANS2=1;
	CHS1=1;
	CHS0=0;
}
//Set AN3 as analog input, and use it as the source for the ADC conversion
void EnableAN3(){
	SetBit(TRISIO, 4);
        //use channel 0b111 (AN3) as the analog input for the ADC
	ANS3=1;
	CHS1=1;
	CHS0=1;
}

MBP18

//Set AN0 as analog input, and use it as the source for the ADC conversion
void EnableAN0(){
	TRISA0=1; //set RA0 as digital input
	ANSEL&=0b00000001; //set AN0 as analog input
        //use channel 0b000 (RA0/AN0) as the analog input for the ADC
	CHS2=0;
	CHS1=0;
	CHS0=0;
}


Take a synchronous measurement

A synchronous measure is a way of calling a function or piece of code and wait doing nothing until the ADC conversion finishes.

This is the simplest way to make a measure, but it wastes time since it won't be able to execute other things while it's waiting for the ADC conversion to finish.

MBP18

(it would probably work for other Main Boards too)

//Synchcronously get the analog value on the active analog input. It waits doing nothing until the measurement is done
unsigned int AdcMeasure(){
	ADFM=1; //right justification so we read the variable in a normal way
	ADON=1; //activate ADC
	GO=1; //start A/D conversion
	while(NOT_DONE) /*do nothing while making conversion*/;
	return ADRESH << 8 | ADRESL; //return a 16-bit variable using the result value from ADRESH and ADRESL
}


Get real voltage

Real voltage can be calculated by the formula:

Voltage = adcResult / maxValue * Vref

Being adcResult the value returned by the ADC conversion, maxValue the maximum value it can return (1023 in a 10-bit ADC), and Vref the voltage reference (by default it's the voltage at which it's powered. Around 5V in Curuxa Main Boards).

Remember that if you use the default voltage reference you'll never really exactly 5V if you are using batteries or a non-perfect power supply. Therefore the calculated value won't be exact and will probably contain some noise.

For more precise results, use an external voltage reference. See section Analog-to-Digital Converter (ADC) Module in the datasheet, bits VCFG.

// calculate real voltage from the A/D conversion result using default parameters
float AdcGetVoltage(int adcResult) {
    return adcResult / 1023.0 * 5.0;
}


Sample program

#include <pic16fxxx.h>
 
//put here the required macro definitions (SetBit, ClearBit, DigitalInput...)
 
//put here the ADC functions you need (as shown above, in previous sections)
 
void main() {
    int adcResult = 0;
 
    AdcDisable(); //disable ADC and the rest of analog inputs we won't use
    EnableAN0(); //we'll use AN0 as the pin for making the measurement
 
    //setup other things you want here...
 
    //infinite loop
    while(1) {
        adcResult = AdcMeasure();
        if( adcResult < 679 ) {
            //do something
        } else {
            //so something else
        }
    }
}