Get Adobe Flash player
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

The electric chair was invented by a dentist.

Help us stay online:

small donate

logo dspic adcThe 12-bit Analog-to-Digital Converter (ADC) allows conversion of an analog input signal to a 12-bit digital number. This module is based on a Successive Approximation Register (SAR) architecture and provides a maximum sampling rate of 200 ksps. The A/D module has up to 16 analog inputs which are multiplexed into a sample and hold amplifier. The output of the sample and hold is the input into the converter which generates the result.

The analog reference voltage is software selectable to either the device supply voltage (AVDD/AVSS) or the voltage level on the (VREF+/VREF-) pin. The A/D converter has a unique feature of being able to operate while the device is in Sleep mode with RC oscillator selection.

The A/D module has six 16-bit registers:
• A/D Control Register 1 (ADCON1)
• A/D Control Register 2 (ADCON2)
• A/D Control Register 3 (ADCON3)
• A/D Input Select Register (ADCHS)
• A/D Port Configuration Register (ADPCFG)
• A/D Input Scan Selection Register (ADCSSL)
The ADCON1, ADCON2 and ADCON3 registers control the operation of the A/D module. The ADCHS register selects the input channels to be converted. The ADPCFG register configures the port pins as analog inputs or as digital I/O. The ADCSSL register selects inputs for scanning. For more information see dsPIC30F4013 datasheet.

In our example we will add potentiometer and humidity sensor to simulate variation of analogue signal. Microcontroller board described in article Microchip dsPIC30f4013 microcontroller and Telit GM862 GSM modem – hardware implementation is used. In our example we will use only two ADCs on different ports (RB3 and RB8) to show how to set initialization. Here are adc.h and adc.c codes:


void ADCinit(void);

If you need to change number of ADC, you only need to change highlighted lines.


#include "adc.h"
void ADCinit(void)
    bit 15 ADON: A/D Operating Mode bit
            1 = A/D converter module is operating
            0 = A/D converter is off
    bit 14 Unimplemented: Read as ‘0’
    bit 13 ADSIDL: Stop in Idle Mode bit
            1 = Discontinue module operation when device enters Idle mode
            0 = Continue module operation in Idle mode
    bit 12-10 Unimplemented: Read as ‘0’
    bit 9-8 FORM<1:0>: Data Output Format bits
            11 = Signed fractional (DOUT = sddd dddd dddd 0000)
            10 = Fractional (DOUT = dddd dddd dddd 0000)
            01 = Signed integer (DOUT = ssss sddd dddd dddd)
            00 = Integer (DOUT = 0000 dddd dddd dddd)
    bit 7-5 SSRC<2:0>: Conversion Trigger Source Select bits
            111 = Internal counter ends sampling and starts conversion (auto convert)
            110 = Reserved
            101 = Reserved
            100 = Reserved
            011 = Motor Control PWM interval ends sampling and starts conversion
            010 = General purpose Timer3 compare ends sampling and starts conversion
            001 = Active transition on INT0 pin ends sampling and starts conversion
            000 = Clearing SAMP bit ends sampling and starts conversion
    bit 4-3 Unimplemented: Read as ‘0’
    bit 2 ASAM: A/D Sample Auto-Start bit
            1 = Sampling begins immediately after last conversion completes. SAMP bit is auto set.
            0 = Sampling begins when SAMP bit set
    bit 1 SAMP: A/D Sample Enable bit
            1 = At least one A/D sample/hold amplifier is sampling
            0 = A/D sample/hold amplifiers are holding
            When ASAM = 0, writing ‘1’ to this bit will start sampling.
            When SSRC = 000, writing ‘0’ to this bit will end sampling and start conversion.
    bit 0 DONE: A/D Conversion Status bit
            1 = A/D conversion is done
            0 = A/D conversion is not done
            Clearing this bit will not effect any operation in progress.
            Cleared by software or start of a new conversion.*/
    //at end od initialization do this  ADCON1bits.ASAM=1;
    //at end od initialization do this ADCON1bits.ADON=1;
    bit 15-13 VCFG<2:0>: Voltage Reference Configuration bits
                            A/D	VREFH	 			A/D VREFL
            000 	AVDD 					AVSS
            001 	External VREF+ pin 		AVSS
            010 	AVDD 					External VREF- pin
            011 	External VREF+ pin 		External VREF- pin
            1xx 	AVDD 					AVSS
    bit 12 Reserved: User should write ‘0’ to this location
    bit 11 Unimplemented: Read as ‘0’
    bit 10 CSCNA: Scan Input Selections for CH0+ S/H Input for MUX A Input Multiplexer Setting bit
            1 = Scan inputs
            0 = Do not scan inputs
    bit 9-8 Unimplemented: Read as ‘0’
    bit 7 BUFS: Buffer Fill Status bit
            Only valid when BUFM = 1 (ADRES split into 2 x 8-word buffers)
            1 = A/D is currently filling buffer 0x8-0xF, user should access data in 0x0-0x7
            0 = A/D is currently filling buffer 0x0-0x7, user should access data in 0x8-0xF
    bit 6 Unimplemented: Read as ‘0’
    bit 5-2 SMPI<3:0>: Sample/Convert Sequences Per Interrupt Selection bits
            1111 = Interrupts at the completion of conversion for each 16th sample/convert sequence
            1110 = Interrupts at the completion of conversion for each 15th sample/convert sequence
            0001 = Interrupts at the completion of conversion for each 2nd sample/convert sequence
            0000 = Interrupts at the completion of conversion for each sample/convert sequence
    bit 1 BUFM: Buffer Mode Select bit
            1 = Buffer configured as two 8-word buffers ADCBUF(15...8), ADCBUF(7...0)
            0 = Buffer configured as one 16-word buffer ADCBUF(15...0)
    bit 0 ALTS: Alternate Input Sample Mode Select bit
            1 = Uses MUX A input multiplexer settings for first sample, then alternate between MUX B and MUX A input
            multiplexer settings for all subsequent samples
            0 = Always use MUX A input multiplexer settings*/
    ADCON2bits.SMPI=2;/*The SMPI bits select the number of acquisition/conversion sequences that would be
                       *  performed before an interrupt occurs. This can vary from 1 sample per interrupt
                       *  to 16 samples per interrupt.*/
    bit 15-13 Unimplemented: Read as ‘0’
    bit 12-8 SAMC<4:0>: Auto Sample Time bits
            11111 = 31 TAD
            00001 = 1 TAD
            00000 = 0 TAD
    bit 7 ADRC: A/D Conversion Clock Source bit
            1 = A/D internal RC clock
            0 = Clock derived from system clock
    bit 6 Unimplemented: Read as ‘0’
    bit 5-0 ADCS<5:0>: A/D Conversion Clock Select bits
            111111 = TCY/2 • (ADCS<5:0> + 1) = 32 • TCY
            000001 = TCY/2 • (ADCS<5:0> + 1) = TCY
            000000 = TCY/2 • (ADCS<5:0> + 1) = TCY/2*/
    ADCHS: A/D Input Select Register
    bit 15-13 Unimplemented: Read as ‘0’
    bit 12 CH0NB: Channel 0 Negative Input Select for MUX B Multiplexer Setting bit
            Same definition as bit <4> (see Note).
    bit 11-8 CH0SB<3:0>: Channel 0 Positive Input Select for MUX B Multiplexer Setting bit
            Same definition as bits <3:0> (see Note).
    bit 7-5 Unimplemented: Read as ‘0’
    bit 4 CH0NA: Channel 0 Negative Input Select for MUX A Multiplexer Setting bit
            1 = Channel 0 negative input is AN1
            0 = Channel 0 negative input is VREFbit
    3-0 CH0SA<3:0>: Channel 0 Positive Input Select for MUX A Multiplexer Setting bit
            1111 = Channel 0 positive input is AN15
            1110 = Channel 0 positive input is AN14
            1101 = Channel 0 positive input is AN13
            0001 = Channel 0 positive input is AN1
            0000 = Channel 0 positive input is AN0
    /*ADPCFG: A/D Port Configuration Register
    bit 15-0 PCFG<15:0>: Analog Input Pin Configuration Control bits
            1 = Analog input pin in Digital mode, port read input enabled, A/D input multiplexer input connected to AVSS
            0 = Analog input pin in Analog mode, port read input disabled, A/D samples pin voltage*/
    /*ADCSSL: A/D Input Scan Select Register
    bit 15-0 CSSL<15:0>: A/D Input Pin Scan Selection bits
            1 = Select ANx for input scan
            0 = Skip ANx for input scan*/
    //ADCSSL=0b0001111111111111;  //all adcs are ON
    ADCSSL=0b0000000100001000;//0 0 0 RB12 RB11 RB10 RB9 RB8 RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0   put 1 at used pin

In our example we will use potentiometer and humidity sensor 808H5V5 as source of analogue signal. Middle pin of potentiometer is tied to ADC input, other two pins are tied to VCC (5V) and GND. Humidity sensor is connected on same way with difference that output of sensor depends on ambient humidity. Output of potentiometer can be change manually, but humidity sensor need variation of ambient humidity. For demonstration we will use glass of boiled water and when we put sensor over glass humidity will be locally increased (see picture).


Whole experiment setup is shown on next picture.


Project for MPLABX can be downloded HERE. Note that we don't need to set ADPCFG register because for every ADC input it is by default set to zero (zero is analogue input). But, if we need to use pin where ADC input exists as digital pin, we need to set to 1 ADPCFG. For example: ADPCFGbits.PCFG3=1;, now pin PB3 is digital, not analogue. Just to remind you, dsPIC30F4013 has 12bit ADCs, so maximum output will be 4095. In this example that correspond to supply voltage of 5V. Here is MAIN code:


#include <string.h>
#include "uart.h"
_FOSC(CSW_FSCM_OFF & FRC_PLL4); //7.37 MHz Internal RC oscillator, 4x PLL enabled
_FWDT(WDT_OFF);                 //Watchdog disabled
#define DELAY_RANDOM 3000000
int tempRX, tempRX2;
char buf[10];
int data0, data1;
unsigned int ms_counter;
void __attribute__((__interrupt__)) _U1RXInterrupt(void)
    IFS0bits.U1RXIF = 0;
    tempRX = U1RXREG;
void __attribute__((__interrupt__)) _U2RXInterrupt(void) {
    IFS1bits.U2RXIF = 0;
    tempRX2 = U2RXREG;
void __attribute__((__interrupt__)) _T1Interrupt(void) // svakih 1ms
// prekidna rutina Thajmera 1
    TMR1 = 0;
    ms_counter++; //used in Delay_ms() function
    IFS0bits.T1IF = 0;
void __attribute__((__interrupt__)) _ADCInterrupt(void) {
    data0 = ADCBUF0; //RB3  respect order RB0, RB1..etc, if not used skip it but ADCBUFs are ordered
    data1 = ADCBUF1; //RB8
    IFS0bits.ADIF = 0;  //After conversion ADIF is set to 1 and must be cleared
void Delay_ms(unsigned int vreme) //For counting time in ms
    ms_counter = 0;
    while (ms_counter < vreme);
int main(void)
    ADCON1bits.ADON = 1; //begin og ADC conversion
    WriteStringUART1("START\r");  // \r is ENTER
    Delay_ms(3000);//3s delay
    while (1)
        WriteStringUART1("Potentiometer value: ");
        WriteStringUART1("  Humidity sensor value: ");
        WriteUART1(13); //ENTER
        Delay_ms(3000);//3s delay
    return 0;

Here is video of Terminal output via UART.