The following example program demonstrates basic analog input on the dsPIC30F4011. Only one of the ADC module’s four converters is used (AD0) and only one channel at a time is read. The sampling time is controlled manually and is currently set to 1µs, which should be adequate for any source impedance below the recommended maximum value of 5kΩ. The total time per measurement (including the sampling and conversion) should be less than 2.5µs.
I haven’t tested this thoroughly yet, but I have successfully used it to control the duty cycle of an LED (i.e. its brightness) with a pot connected to AN0 (pin 2).
//
// This is a simple analog input example for the dsPIC30F4011
// It configures the lowest 8 PORTB pins as analog inputs, then reads
// the voltage on AN0 repeatedly. The input voltage determines
// the brightness of an LED on RD0 by varying its duty cycle
// in proportion to the analog input reading.
//
// Written by Ted Burke - last updated 5-12-2010
//
#include <libpic30.h>
#include <p30f4011.h>
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Clock speed = 7.5MHz x 16, i.e. 30 MIPS
_FWDT(WDT_OFF); // Watchdog timer off
void configure_pins();
unsigned int read_analog_channel(int n);
int main()
{
long int n;
// Set up which pins are which
configure_pins();
while(1)
{
// Read the analog channel. The result is an
// integer between 0 and 1023 inclusive.
n = read_analog_channel(0);
// LED on
_LATD0 = 1;
__delay32(30*n); // m us
// LED off
_LATD0 = 0;
__delay32(30*(1023 - n)); // (1023-n) us
}
return 0;
}
void configure_pins()
{
// Configure digital I/O
LATD = 0;
TRISD = 0b11111110;
// Configure analog inputs
TRISB = 0x01FF; // Port B all inputs
ADPCFG = 0xFF00; // Lowest 8 PORTB pins are analog inputs
ADCON1 = 0; // Manually clear SAMP to end sampling, start conversion
ADCON2 = 0; // Voltage reference from AVDD and AVSS
ADCON3 = 0x0005; // Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us
ADCON1bits.ADON = 1; // Turn ADC ON
}
// This function reads a single sample from the specified
// analog input. It should take less than 2.5us if the chip
// is running at about 30 MIPS.
unsigned int read_analog_channel(int channel)
{
ADCHS = channel; // Select the requested channel
ADCON1bits.SAMP = 1; // start sampling
__delay32(30); // 1us delay @ 30 MIPS
ADCON1bits.SAMP = 0; // start Converting
while (!ADCON1bits.DONE); // Should take 12 * Tad = 1.2us
return ADCBUF0;
}

I love THAT post BUT i wanted to leave a comment on the previous post in which you gave the blinking LED code. On my dsPIC the blink was so fast it couldnt be seen and it took me minutes !! to figure out that it WAS working. I had to increase the time to 50000000 to get a good blink. Its blinking now.
Richard
hi! how can 1.2us time for adc in above code.
Hi Krish,
The 1.2us time that I mention in my comments depends on a few things:
Hopefully that explains it!
Ted
hi! i m using ADCON3=0×0109 as per your calculation its 1.98us bit it takes it iakes 4.08us sampling manully start and end auto end ,then conversion is also automatic.
Hi Krish,
It sounds like the extra time results from several factors:
The sampling delay is necessary to allow the sampling capacitor to charge up to the same voltage that is connected to the pin. This takes a little time because it is basically a simple RC circuit with associated time constant (T=RC, where C is the 4.4pF sampling capacitor, and R is equal to the sum of the 3.25kOhm resistance of the input circuit and the source resistance of the external analog voltage source). See Figure 20-2 in section 20.7 of the dsPIC30F4011 datasheet for more details of the analog input equivalent circuit.
I implement the sampling delay manually in my read_analog_channel function. I chose a delay of 1us, which was based on an assumed RC time constant of 200ns, which corresponds to a source impedance of just over 40kOhm. You may have heard of the rule of thumb that an RC circuit reaches steady state after 5 time constants? Well, that’s why I made the sampling time equal to five times the estimated time constant.
In reality, the required sampling time depends on the source impedance of the sensor (or whatever you have connected to the pin). If the analog voltage source has a very low source impedance (or if you use a unity-gain op-amp buffer for example), a shorter sampling time might be adequate. Conversely, if your analog voltage source has a very high source impedance, even 1us may not be enough for the sampling capacitor voltage to settle to the correct value.
Also, I see that your ADCON3 value sets SAMC = 1. Is it possible that this activates automatic sampling time? If so, I think the conversion time will be 13 x Tad rather than 12 x Tad.
Ted
hi! actually i am using Rs=4.7k and start sampling by setting SAMP=1 manually, then sampling will stop automatically and conversion auto trigger , i think it takes 13tad time , total impedance 4.7k(rs)+3.25k=7.95 as per thumb rule it gives value of 174.9ns so 0.174us time . now go for total time 13tad gives 2.145us now if we go for total ime 13 tad plus thumb rule time its value is 2.319us
now i am confuse how its 4.08us.
How exactly did you measure that it’s 4.08us?
before calling function read_analog_channel(); i set one i/o pin as logic 1 and at the end of this function that i/o pin will logic zero.
before calling function read_analog_channel(); i set one i/o pin as logic 1 and at the end of this function that i/o pin will logic zero. and measure time between gpio toggle.
Ok, that’s a good way of doing it. Please try placing the i/o pin set and reset inside the read_analog_channel function to find out how much of the delay is due to the overhead of the function call. If it turns out to be a big part of it, then there are ways you can work around it (e.g. making it an inline function).