ADC produces very different values

Status
Not open for further replies.
Here is the new code:

main.c
Code:
//***************************************************/
// Include Header File
//***************************************************/

#include "p24FJ128GA110.h"
#include "adc.h"

//***************************************************/
// Define Constants Variables
//***************************************************/

//***************************************************/
int main (void)
{
	initADC(0xFFEF);  //make rb2  AN4 an analog input
	TRISB = 0xff00; //Make all B outputs
	int a, j;
	T1CON = 0x8030; // TMR1 on, prescale 1:256 Tclk/2
	while(1)  
		{
			a = 0;
			for ( j=16; j >0; j--)
			{
				TMR1 = 0;
				while ( TMR1 < 3900); // 3900 x 256 x Tcy ~= 1sec
				a += readADC(4);
			}
			a >>= 4;
			if(a > 255)
			{
				PORTB = 0b10000000; //turn on LED on pin B7
			}
		}
};	
//end of code

adc.c
Code:
#include <p24FJ128GA110.h>
#include "adc.h"
int readADC( int sensor)
{
    AD1CHS  = sensor;               // select analog input channel
    AD1CON1bits.SAMP = 1;       // start sampling, automatic conversion will follow
    while (!AD1CON1bits.DONE);   // wait to complete the conversion
    return ADC1BUF0;            // read the conversion result
} // readADC
void initADC( int amask) 
{
    AD1PCFG = amask;    // select analog input pins
    AD1CON1 = 0x00E0;   // auto convert after end of sampling 
    AD1CSSL = 0;        // no scanning required 
    AD1CON3 = 0x1F02;   // max sample time = 31Tad, Tad = 2 x Tcy = 125ns >75ns
    AD1CON2 = 0;        // use MUXA, AVss and AVdd are used as Vref+/-
    AD1CON1bits.ADON = 1; // turn on the ADC
} //initADC

adc.h
Code:
#ifndef __ADCDRV_H__
#define __ADCDRV_H__ 
int readADC( int sensor);
void initADC( int amask);
#endif
 
To see the value the ADC is receiving, I am adding a breakpoint and then moving the cursor over this line:

Code:
			if(a > 255)

the "a" tells me the value.
 
You need to set these bits

ADCON1bits.FORM = 0;
ADCON1bits.SSRC = 7;
ADCON1bits.ASAM = 1;
 
Read this over and see if it don't help

Code:
//Functions:
//ADC_Init() is used to configure A/D to convert 16 samples of 1 input
//channel per interrupt. The A/D is set up for a using the ADRC oscillator
//Automatic conversion trigger is applied after 1Tad of sampling time.
//The input pin being acquired and converted is AN4.
void ADC_Init(void)
{
        //ADCON1 Register
        //Set up A/D for Automatic Sampling
        //Use internal counter (SAMC) to provide sampling time
        //Set up A/D conversrion results to be read in unsigned integer format.
        //Set up Sequential sampling for multiple S/H amplifiers
        //All other bits to their default state
        ADCON1bits.FORM = 0;
        ADCON1bits.SSRC = 7;
        ADCON1bits.ASAM = 1;

        //ADCON2 Register
        //Set up A/D for interrupting after 16 samples get filled in the buffer
        //All other bits to their default state
        ADCON2bits.SMPI = 15;

        //ADCON3 Register
        //We will set up the ADRC as the A/D conversion clock
        //so that the A/D converter can operate when the device is in
        //SLEEP mode. Also, 1 Tad period is allocated for sampling time.
        //The conversion rate for the ADRC oscillator is depends on whether
        //the device is a dsPIC30F or dsPIC33F device and also whether the
        //A/D module is a 10-bit or 12-bit A/D converter.
        //Please refer to the device Datasheet for "ADRC" conversion rate.
        ADCON3bits.SAMC = 1;
        ADCON3bits.ADRC = 1;

        //ADCHS Register
        //Set up A/D Channel Select Register to convert AN4 on Mux A input
        //of CH0 S/H amplifiers
        ADCHS = 0x0004;

        //ADCSSL Register
        //Channel Scanning is disabled. All bits left to their default state
        ADCSSL = 0x0000;

        //ADPCFG Register
        //Set up channels AN4 as analog input and configure rest as digital
        ADPCFG = 0xFFFF;
        ADPCFGbits.PCFG4 = 0;

        //Clear the A/D interrupt flag bit
        IFS0bits.ADIF = 0;

        //Set the A/D interrupt enable bit
        IEC0bits.ADIE = 1;

        //Turn on the A/D converter
        //This is typically done after configuring other registers
        ADCON1bits.ADON = 1;

}
 
Last edited:
Okay here are the values:
Voltage -> ADC Value
.5V -> 4
1V -> 5
1.5V -> 7
2V -> 10
2.5V -> 17
3V -> 47

Are these correct? Is it working? I only checked the values on one of my pics.

I had to adjust the code to work:
Code:
#include <p24FJ128GA110.h>
#include "adc.h"

//Functions and Variables with Global Scope: 
void __attribute__((__interrupt__)) _ADC1Interrupt(void);

int TempSensor = 0;

//Functions:
//ADC_Init() is used to configure A/D to convert 16 samples of 1 input
//channel per interrupt. The A/D is set up for a using the ADRC oscillator
//Automatic conversion trigger is applied after 1Tad of sampling time.
//The input pin being acquired and converted is AN4.
void ADC_Init(void)
{
        //ADCON1 Register
        //Set up A/D for Automatic Sampling
        //Use internal counter (SAMC) to provide sampling time
        //Set up A/D conversrion results to be read in unsigned integer format.
        //Set up Sequential sampling for multiple S/H amplifiers
        //All other bits to their default state
        AD1CON1bits.FORM = 0;
        AD1CON1bits.SSRC = 7;
        AD1CON1bits.ASAM = 1;

        //ADCON2 Register
        //Set up A/D for interrupting after 16 samples get filled in the buffer
        //All other bits to their default state
        AD1CON2bits.SMPI = 15;

        //ADCON3 Register
        //We will set up the ADRC as the A/D conversion clock
        //so that the A/D converter can operate when the device is in
        //SLEEP mode. Also, 1 Tad period is allocated for sampling time.
        //The conversion rate for the ADRC oscillator is depends on whether
        //the device is a dsPIC30F or dsPIC33F device and also whether the
        //A/D module is a 10-bit or 12-bit A/D converter.
        //Please refer to the device Datasheet for "ADRC" conversion rate.
        AD1CON3bits.SAMC = 1;
        AD1CON3bits.ADRC = 1;

        //ADCHS Register
        //Set up A/D Channel Select Register to convert AN4 on Mux A input
        //of CH0 S/H amplifiers
        AD1CHS = 0x0004;

        //ADCSSL Register
        //Channel Scanning is disabled. All bits left to their default state
        AD1CSSL = 0x0000;

        //ADPCFG Register
        //Set up channels AN4 as analog input and configure rest as digital
        AD1PCFG = 0xFFFF;
        AD1PCFGbits.PCFG4 = 0;

        //Clear the A/D interrupt flag bit
        IFS0bits.AD1IF = 0;

        //Set the A/D interrupt enable bit
        IEC0bits.AD1IE = 1;

        //Turn on the A/D converter
        //This is typically done after configuring other registers
        AD1CON1bits.ADON = 1;
}

//_ADCInterrupt() is the A/D interrupt service routine (ISR). 
//The routine must have global scope in order to be an ISR. 
//The ISR name is chosen from the device linker script. 
void __attribute__((__interrupt__)) _ADC1Interrupt(void) 
// , no_auto_psv 
{
     TempSensor = ADC1BUF0 * 100;
      //Clear the A/D Interrupt flag bit or else the CPU will
      //keep vectoring back to the ISR
      IFS0bits.AD1IF = 0;
}
 
change this
Code:
TempSensor = ADC1BUF0 * 100;
To this
Code:
TempSensor = ADC1BUF0;

And see what you get
 
Sorry that is not in these values. I added that at the end to test something. All the values I provided did not have the *100.
 
Here try the whole code
Code:
//Functions and Variables with Global Scope:
int main (void);
void ADC_Init(void);
void __attribute__((__interrupt__)) _ADCInterrupt(void);

unsigned int conversionResult[16];
volatile unsigned int *ptr;

int main (void)
{
        ADPCFG = 0xFFFF;        //Set AN pins to Digital mode for ICD 2 debugging
        ADC_Init();             //Initialize the A/D converter

        while (1)               //Loop Endlessly - Execution is interrupt driven
        {                       //from this point on.
                Sleep();
        }

        return 0;
}

//Functions:
//ADC_Init() is used to configure A/D to convert 16 samples of 1 input
//channel per interrupt. The A/D is set up for a using the ADRC oscillator
//Automatic conversion trigger is applied after 1Tad of sampling time.
//The input pin being acquired and converted is AN4.
void ADC_Init(void)
{
        //ADCON1 Register
        //Set up A/D for Automatic Sampling
        //Use internal counter (SAMC) to provide sampling time
        //Set up A/D conversrion results to be read in unsigned integer format.
        //Set up Sequential sampling for multiple S/H amplifiers
        //All other bits to their default state
        ADCON1bits.FORM = 0;
        ADCON1bits.SSRC = 7;
        ADCON1bits.ASAM = 1;

        //ADCON2 Register
        //Set up A/D for interrupting after 16 samples get filled in the buffer
        //All other bits to their default state
        ADCON2bits.SMPI = 15;

        //ADCON3 Register
        //We will set up the ADRC as the A/D conversion clock
        //so that the A/D converter can operate when the device is in
        //SLEEP mode. Also, 1 Tad period is allocated for sampling time.
        //The conversion rate for the ADRC oscillator is depends on whether
        //the device is a dsPIC30F or dsPIC33F device and also whether the
        //A/D module is a 10-bit or 12-bit A/D converter.
        //Please refer to the device Datasheet for "ADRC" conversion rate.
        ADCON3bits.SAMC = 1;
        ADCON3bits.ADRC = 1;

        //ADCHS Register
        //Set up A/D Channel Select Register to convert AN4 on Mux A input
        //of CH0 S/H amplifiers
        ADCHS = 0x0004;

        //ADCSSL Register
        //Channel Scanning is disabled. All bits left to their default state
        ADCSSL = 0x0000;

        //ADPCFG Register
        //Set up channels AN4 as analog input and configure rest as digital
        ADPCFG = 0xFFFF;
        ADPCFGbits.PCFG4 = 0;

        //Clear the A/D interrupt flag bit
        IFS0bits.ADIF = 0;

        //Set the A/D interrupt enable bit
        IEC0bits.ADIE = 1;

        //Turn on the A/D converter
        //This is typically done after configuring other registers
        ADCON1bits.ADON = 1;

}

//_ADCInterrupt() is the A/D interrupt service routine (ISR).
//The routine must have global scope in order to be an ISR.
//The ISR name is chosen from the device linker script.
//If the device is in SLEEP mode, the A/D interrupt wakes
//the device up. The device vectors to the A/D ISR upon wake-up.
void __attribute__((__interrupt__)) _ADCInterrupt(void)
{
        int i = 0;
        ptr = &ADCBUF0;
        while (i < 16)
        {
                conversionResult[i++] = *ptr++;
        }

        //Clear the A/D Interrupt flag bit or else the CPU will
        //keep vectoring back to the ISR
        IFS0bits.ADIF = 0;

}




/*
EOF
*/
 
I would look at conversionResult
Okay, here are the latest numbers. I am going to run them on my other pic as well.

volts - > ADC value
.5V -> 154
1V -> 311
1.5V -> 467
2V -> 625
2.5V -> 778
3V -> 933

Do these look correct? They do not match the calculation of (input/3.3)*256.
 
Last edited:
You are sampling at 10 bits or 1024 values.

Therefore all the calculations will be ( ADC V/ 3.3V * 1024). Use this as the basis for your coding.
 
Okay, here are the latest numbers. I am going to run them on my other pic as well.

volts - > ADC value
.5V -> 154
1V -> 311
1.5V -> 467
2V -> 625
2.5V -> 778
3V -> 933

Do these look correct? They do not match the calculation of (input/3.3)*256.

your on the money now there real close

This is wrong
Do these look correct? They do not match the calculation of (input/3.3)*256.
 
Last edited:
Your 310 per volt
.5 would be 155 you got 154
1 would be 310 you got 311
1.5 would be 465 you got 467

Your on the money now

ADC is 1024 / volts

Or
.5 / 3.3 x1024 = 155.15
 
Last edited:
YEAHHHHHHHHHHH!!!!!!! Now I just need to insert this new code into my old code so everything else works. Thank you sooooo much.
 
Actually before I use the new code I go back to the original problem. I have a LM34DZ to get the temp. When connected I get a value of 217. If I convert this I get 67335. I would guess that converts to 67 degrees. But I just want to make sure.
 
I would have to read the data sheet to be of any help with that.

But you have to watch for negative values.
 
I just did some tests with different temps and they appear to register correctly. Next step is to add 3 more ADCs on AN2, AN3, and AN5. Let me see if I can figure it out on my own.
 
Okay so I was able to sample four channels at a time and they appear to be providing over the correct values. How do I get the average value for an array? The code is posted below.

I am trying to get the average values for the following arrays:

Code:
unsigned int ADC_AN2[16];
unsigned int ADC_AN3[16];
unsigned int ADC_AN4[16];
unsigned int ADC_AN5[16];

Code:
//***************************************************/
// Include Header File
//***************************************************/

#include "p24FJ128GA110.h"

//Functions and Variables with Global Scope:
int main (void);
void ADC_Init(void);
void __attribute__((__interrupt__)) _ADC1Interrupt(void);

unsigned int ADC_AN2[16];
unsigned int ADC_AN3[16];
unsigned int ADC_AN4[16];
unsigned int ADC_AN5[16];


//***************************************************/
// Define Constants Variables
//***************************************************/

//***************************************************/

int main (void)
{
        AD1PCFG = 0xFFFF;        //Set AN pins to Digital mode for ICD 2 debugging
        ADC_Init();             //Initialize the A/D converter

        while (1)               //Loop Endlessly - Execution is interrupt driven
        {                       //from this point on.
                Sleep();
        }

        return 0;
}

//ADC_Init() is used to configure A/D to convert 16 samples of 1 input
//channel per interrupt. The A/D is set up for a using the ADRC oscillator
//Automatic conversion trigger is applied after 1Tad of sampling time.
//The input pin being acquired and converted is AN4.
void ADC_Init(void)
{
        //ADCON1 Register
        //Set up A/D for Automatic Sampling
        //Use internal counter (SAMC) to provide sampling time
        //Set up A/D conversrion results to be read in unsigned integer format.
        //Set up Sequential sampling for multiple S/H amplifiers
        //All other bits to their default state
        AD1CON1bits.FORM = 0;
        AD1CON1bits.SSRC = 7;
        AD1CON1bits.ASAM = 1;

        //ADCON2 Register
        //Set up A/D for interrupting after 16 samples get filled in the buffer
        //All other bits to their default state
        AD1CON2bits.SMPI = 15;
		AD1CON2bits.CSCNA = 1; //Scan Input Ports

        //ADCON3 Register
        //We will set up the ADRC as the A/D conversion clock
        //so that the A/D converter can operate when the device is in
        //SLEEP mode. Also, 1 Tad period is allocated for sampling time.
        //The conversion rate for the ADRC oscillator is depends on whether
        //the device is a dsPIC30F or dsPIC33F device and also whether the
        //A/D module is a 10-bit or 12-bit A/D converter.
        //Please refer to the device Datasheet for "ADRC" conversion rate.
        AD1CON3bits.SAMC = 1;
        AD1CON3bits.ADRC = 1;

        //ADCHS Register
        //Set up A/D Channel Select Register to convert AN4 on Mux A input
        //of CH0 S/H amplifiers
        AD1CHS = 0x0004;

        //ADCSSL Register
        //Channel Scanning is enabled. All bits left to their default state
        AD1CSSLbits.CSSL2 =1; // Channel Scanning is Enabled for AN2 
        AD1CSSLbits.CSSL3 =1; // Channel Scanning is Enabled for AN3 
        AD1CSSLbits.CSSL4 =1; // Channel Scanning is Enabled for AN4 
        AD1CSSLbits.CSSL5 =1; // Channel Scanning is Enabled for AN5   

        //ADPCFG Register
        //Set up channels AN2, AN3, AN4, AN5 configure rest as digital
        AD1PCFG = 0xFFFF;
        AD1PCFGbits.PCFG2 = 0; //AN2 in analog mode
        AD1PCFGbits.PCFG3 = 0; //AN3 in analog mode
        AD1PCFGbits.PCFG4 = 0; //AN4 in analog mode
		AD1PCFGbits.PCFG5 = 0; //AN5 as Analog Input 

        //Clear the A/D interrupt flag bit
        IFS0bits.AD1IF = 0;

        //Set the A/D interrupt enable bit
        IEC0bits.AD1IE = 1;

        //Turn on the A/D converter
        //This is typically done after configuring other registers
        AD1CON1bits.ADON = 1;
}

//_ADCInterrupt() is the A/D interrupt service routine (ISR).
//The routine must have global scope in order to be an ISR.
//The ISR name is chosen from the device linker script.
//If the device is in SLEEP mode, the A/D interrupt wakes
//the device up. The device vectors to the A/D ISR upon wake-up.
void __attribute__((__interrupt__)) _ADC1Interrupt(void)
{
        int i = 0;
        while (i < 16)
        {
                ADC_AN2[i] = ADC1BUF0;
                ADC_AN3[i] = ADC1BUF1;
                ADC_AN4[i] = ADC1BUF2;
                ADC_AN5[i++] = ADC1BUF3;
        }

        //Clear the A/D Interrupt flag bit or else the CPU will
        //keep vectoring back to the ISR
        IFS0bits.AD1IF = 0;
}



//end of code
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…