Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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
 
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:
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.

Latest threads

New Articles From Microcontroller Tips

Back
Top