Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] 12 bit adc calculation

Status
Not open for further replies.

dhakeparag81

Full Member level 2
Joined
Jun 6, 2012
Messages
131
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,298
Location
INDIA
Activity points
2,406
Hi there,

I use 12 bit ADC AMC7820 to get digital value.
After getting the ADC result i want to convert it into voltage(in float).
formula for conversion is

v= ADC/4096;
v= 5/v;

but i didn't get the correct result.
i use pic18f 87k22 controller for interfacing with ADC.

please help me out...
 
Last edited:

hi,
i think this will do:
v=4096/ADC;
V=5/v;
do you use :
int v=0;
float V=0.00;
?


then try this:
V=(float)(5*(ADC/4096));
or simply:
V= (float) (ADC*0.001220703);
:cool:
 
Last edited:

then try this:
V=(float)(5*(ADC/4096));

The OP has not specified a compiler, however I do not believe the above solution will yield the expected result. The order of precedence enforced by the parentheses will essentially be carried out as integer math and THEN cast as a float.

I would suggest the following:

Code:
float V;  // depending on the compiler,  types float and double may actually represent the same type (C18).

V=5.0*ADC/4096.0;

The above statement utilizes implicit promotion to type float/double.


BigDog
 

Thanks for reply,

According to you
Code:
float V;  
V=5.0*ADC/4096.0;

but it gives result which is not expected

the array where i store the 12bit ADC result is integer

i attache the screen shot of the result
where temp_f array is result after calculation of v.
 

Attachments

  • adc_1.JPG
    adc_1.JPG
    140 KB · Views: 188

Please post your code using the CODE or SYNTAX tags, rather than a screen shot.

Also what compiler are you using, Microchip C18?

BigDog
 

i would suggess you the following solution

v=(5.000*(adc_value))/4096


i hope this will help you


(irfan ahmad)
 

i use MPLAB v8.80
and compiler mplabc18 v3.40



Code:
unsigned int array1[10]={0},array2[10]={0};
unsigned float array3[10]={0};
float temp_f[10]={0};
float v=0,v2=0;

void main()
{
 OSCTUNE = 0X80;
    OSCCON=0x76;						//0X76;             //16MHz
    OSCCON2=0X00;

    INTCON=0xE0;
    T0CON=0x88;                      // timer-0 16-bit, no prescalar.
    TMR0H=0x63;
    TMR0L=0xBF;                     // 10msec timer-0.  

    ANCON0=0x00;                   // make all analog channel as digital I/O.
    ANCON1=0x00;                   // make all analog channel as digital I/O.
    ANCON2=0x00;

    ODCON1=0x00;
    ODCON2=0x00;
    PADCFG1=0x20; 

    CM1CON=0x00;                    // comparator1 OFF.
    CM2CON=0x00;                    // comparator2 OFF.
    CM3CON=0x00;                    // comparator3 OFF.    
    MEMCONbits.EBDIS=1;

    ADCON0=0x00;                   // make all analog channel as digital I/O.
    CM1CON=0x00;                    // comparator1 OFF.
    CM2CON=0x00;                    // comparator2 OFF.
    CM3CON=0x00;                    // comparator3 OFF.

    TRISDbits.TRISD6=0;               // make RD6 as output for SCK.  
    TRISDbits.TRISD5=1;               // make RD5 as input for SDI. 
    TRISDbits.TRISD4=0;               // make RD4 as output for SDO.
    TRISDbits.TRISD3=0;              //// make RD3 as output for CS.
    TRISDbits.TRISD2=0;               // make RD2 as output for RESET. 
 	
 	PORTE=0x00;
    TRISE=0x00;                         // make PORTE as output for lcd datalines.

    PORTC=0x00;
    TRISCbits.TRISC0=0;                 // make RC0 as output for rs
    TRISCbits.TRISC1=0;                 // make RC0 as output for rw
    TRISCbits.TRISC2=0;                 // make RC0 as output for en
 	
 	
 	
 	
 	spi_init();
 
 	RESET=0;
	nop();
	RESET=1;
	nop();
	
	CS=0;
	write_adc(0x0880);
	nop();
	write_adc(0x0009);
	CS=1;
	
scan:

	read_all_channel(&array1[0]);         //reading all 8 channels of ADC
	check_valid(&array1[0],&array2[0]); //Checking MSB nibble for address and data valid bit
	
	voltage_conv(&array2[0]);       //converting ADC data to floating point value as voltage.
	
 	goto scan;

}

void read_all_channel(unsigned int *ptr)
{
	nop();
	nop();
	nop();
	
	CS=0;
	write_adc(0x0880);
	nop();
	write_adc(0x0009);
	CS=1;
	
	CS=0;
	
	write_adc(0x8000);

    nop();
    spi_read();
    
    *ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
         
 	nop();
	nop();
    spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
    spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();	
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	CS=1;
	nop();
	
   	RESET=0;
	nop();
	RESET=1;
		
}

void voltage_conv(unsigned int *ptr)
{	
	unsigned char p=0;
	i=0;
	
	for(i=0;i<8;i++)
	{
		data=0;
		data = *ptr;
		
		//data_f=((5*data) /( 4096.0));
		v = (5.0*data)/4096.0;
	
		temp_f[i] = v;
		
		ptr++;	
		
	}
		
}


other functions like spi_init() which is use for initialization not pasted
to focus on specific function

- - - Updated - - -

thanks irfan,
but i dont think its work
because when we compile the code it convert into assembly and do certain optimization
i think i have to tell compiler specifically to do the instruction as it is

but how?
 

If ADC is integer then you need to do the cast directly on that so (float)ADC. Also, to be on the safe side, make any constants floats.

Keith
 

hi Keith,
i don,t understand
what you want to say?
 

You must use V= ((float)ADC)/4096.0; to be safe. The first thing you should do before you use ADC is cast it to a float (with extra brackets if you are unsure of the precedence). Adding .0 to the 4096 will ensure that is a float.

Keith
 

If ADC is integer then you need to do the cast directly on that so (float)ADC. Also, to be on the safe side, make any constants floats.

Sorry, but I disagree.

If the compiler is compliant with C89/C90, which C18 meets this requirement, then the recommendation I made will certainly yield the expected result.

Multiplication of a float literal and an integer triggers implicit promotion/cast to the type of higher rank.

Therefore the following operation will implicitly cast the type int ADC to type float,

Code:
0.5 * ADC

Explicit casting is not required.


@dhakeparag81

I've only had a chance to glance at your code, but there several possible reasons the code is not functioning as expected.

I certain one of us will find the cause of the issue.


BigDog
 
  • Like
Reactions: FvM

    FvM

    Points: 2
    Helpful Answer Positive Rating
My point about casting is it works and you are not relying on knowing what the compiler is/is not doing. If you try it and the problem is still there then you know to look elsewhere for the problem.

Keith
 

Before we go any further please answer a few questions.

Is this design in physical hardware or a simulation?

Have you verified the ADC (AMC7820) is functioning correctly?

Have you managed to fill an array with output from the ADC (AMC7820) and the values obtained seem reasonable?

BigDog
 

This design is in physical hardware

AMC7820 working correctly because with AMC7820 Texas Instruments provide one software
this software connect with parallel port and show the voltage and hex value.
i check the ADC result which comes in hex with formula

result=(5*adc/4096)

result was correct and also crosscheck with software.

now i paste the whole code There is some trial and error method i was use as i dont have enough knowledge about compiler
basically in voltage_conv() routine

Code:
#include<p18f87k22.h>
#include<spi.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>

#define SDO LATDbits.LATD4
#define SDI PORTDbits.RD5
#define SCK LATDbits.LATD6
#define CS LATDbits.LATD3
#define RESET LATDbits.LATD2



#define rs PORTCbits.RC0
#define rw PORTCbits.RC1
#define en PORTCbits.RC2
#define ldata PORTE


void nop(void);
void T0_ISR(void);
void spi_init(void);
void spi_read(void);
void voltage_conv(unsigned int *ptr);
void write_adc(unsigned int val);
void read_all_channel(unsigned int *ptr);

void check_valid(unsigned int *ptr1, unsigned int *ptr2);
void copy_float(unsigned int *ptr_i, unsigned float *ptr_f);


void lcd_init(void);
void lcd_clear(void);
void lcd_cmd(unsigned char);
void lcd_data(unsigned char value);





unsigned int array1[10]={0},array2[10]={0};
unsigned float array3[10]={0};

unsigned char rec_arr[4]={0};
unsigned char rec_cnt=0,i=0;
unsigned float voltage_array[10]={0};
unsigned int temp_i[10]={0};
unsigned float temp_f[10]={0};

unsigned char address=0;
unsigned float data_f=0;
unsigned int data=0, data_i=0;
unsigned char valid_add_chk=0;
unsigned float v=0,v2=0;

//unsigned char lsb=0,msb=0;

#pragma interrupt chk_isr         // used for high priority interrupt only.

void chk_isr(void)
{
     if(INTCONbits.TMR0IF==1)        // Timer0 causes interrupt.....?
         T0_ISR();                    // yes then execute Timer0 programe.
     
}
#pragma code HI_PRIO_INT=0x0008      // high priority interrupt location.

void HI_PRIO_INT(void)
{
  _asm
  goto chk_isr
 _endasm
} 
#pragma code
//----------------------------------------------------------------------------------------------------------------------------------------------

void T0_ISR()
{   
      TMR0H=0x63;                    //0x63;
      TMR0L=0xBF;                           // load timer0 for 10msec delay.
      INTCONbits.TMR0IF=0;
}


void main (void)
{
    OSCTUNE = 0X80;
    OSCCON=0x76;						//0X76;             //16MHz
    OSCCON2=0X00;

    INTCON=0xE0;
    T0CON=0x88;                      // timer-0 16-bit, no prescalar.
    TMR0H=0x63;
    TMR0L=0xBF;                     // 10msec timer-0.  

    ANCON0=0x00;                   // make all analog channel as digital I/O.
    ANCON1=0x00;                   // make all analog channel as digital I/O.
    ANCON2=0x00;

    ODCON1=0x00;
    ODCON2=0x00;
    PADCFG1=0x20; 

    CM1CON=0x00;                    // comparator1 OFF.
    CM2CON=0x00;                    // comparator2 OFF.
    CM3CON=0x00;                    // comparator3 OFF.    
    MEMCONbits.EBDIS=1;

    ADCON0=0x00;                   // make all analog channel as digital I/O.
    CM1CON=0x00;                    // comparator1 OFF.
    CM2CON=0x00;                    // comparator2 OFF.
    CM3CON=0x00;                    // comparator3 OFF.

    TRISDbits.TRISD6=0;               // make RD6 as output for SCK.  
    TRISDbits.TRISD5=1;               // make RD5 as input for SDI. 
    TRISDbits.TRISD4=0;               // make RD4 as output for SDO.
    TRISDbits.TRISD3=0;              //// make RD3 as output for CS.
    TRISDbits.TRISD2=0;               // make RD2 as output for RESET. 
 	
 	PORTE=0x00;
    TRISE=0x00;                         // make PORTE as output for lcd datalines.

    PORTC=0x00;
    TRISCbits.TRISC0=0;                 // make RC0 as output for rs
    TRISCbits.TRISC1=0;                 // make RC0 as output for rw
    TRISCbits.TRISC2=0;                 // make RC0 as output for en
 	
 	
 	
 	
 	spi_init();
 
 	RESET=0;
	nop();
	RESET=1;
	nop();
	
	CS=0;
	write_adc(0x0880);
	nop();
	write_adc(0x0009);
	CS=1;
	
scan:

	read_all_channel(&array1[0]);
	check_valid(&array1[0],&array2[0]);
	copy_float(&array2[0], &array3[0]);
	voltage_conv(&array2[0]);
	
 	goto scan;
}

void read_all_channel(unsigned int *ptr)
{
	nop();
	nop();
	nop();
	
	CS=0;
	write_adc(0x0880);
	nop();
	write_adc(0x0009);
	CS=1;
	
	CS=0;
	
	write_adc(0x8000);

    nop();
    spi_read();
    
    *ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
         
 	nop();
	nop();
    spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
    spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();	
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	nop();
	spi_read();
	
	*ptr = rec_arr[0];
    *ptr <<= 8;
    *ptr += rec_arr[1];
    ptr++;
	
	nop();
	CS=1;
	nop();
	
   	RESET=0;
	nop();
	RESET=1;
		
}


void spi_init(void)
{
    OpenSPI2(SPI_FOSC_64, MODE_01, SMPEND);                // CKP=0 & CKE=1, sample data at end
    SSP2CON1bits.SSPEN=1;
    SSP2CON1bits.CKP=0;
    SSP2STATbits.CKE=1;

}

void spi_read(void)
{ 
    INTCONbits.GIE=0; 
    rec_cnt=0x00;
    while(rec_cnt<0x02)
    {       
		 rec_arr[rec_cnt]=ReadSPI2();	    // Read in byte sent		 
         rec_cnt++;  
         
    }
  	    
	INTCONbits.GIE=1;      
}

void write_adc(unsigned int val)
{
	unsigned int temp,temp1;
	temp=(val & 0xFF);
	temp1=(val >> 8 );
	
	WriteSPI2(temp1);
	
	WriteSPI2(temp);
	
} 

void check_valid(unsigned int *ptr1, unsigned int *ptr2)
{
	for(valid_add_chk = 1; valid_add_chk <= 15; valid_add_chk+=2)
	{
		address = (*ptr1 >> 8);
		address >>= 4;
		if(valid_add_chk == address)
		{
			
			*ptr2 = (float)*ptr1;
			*ptr2 <<= 4;
			*ptr2 >>=4;
		
			ptr1++;
			ptr2++;
		}	
		
	}	
}

void copy_float(unsigned int *ptr_i, unsigned float *ptr_f)
{
	unsigned char j=0;
	for(i=0; i<8; i++)
	{
		*ptr_f = (*ptr_i * 1.0);
		ptr_f++;
		ptr_i++;
		
	}
	for(i=0;i<8;i++)
	{
		array1[i] = array3[i];
	}	
	
}	
	

void voltage_conv(unsigned int *ptr)
{	
	unsigned char p=0;
	i=0;
	
	for(i=0;i<8;i++)
	{
		data=0;
		data = *ptr;
		data = (int)(5*data);
		v = (float)(data/4095.0);
		//data_f=((5*data) /( 4096.0));
	//	v = ((5.0*data)/4096.0);
	
		temp_f[i] =(float) v;
		
		ptr++;	
		
	}
		
}	


void lcd_init(void)
{
	en=0;
	nop();
	lcd_cmd(0x38);                    // LCD 2 lines, 5x7 matrix.(Function set)
	nop();
   	//lcd_cmd(0x0E);                   // display ON, cursor blinking.
   	lcd_cmd(0x0C);                   // display ON, cursor off.
   	nop();
   	lcd_cmd(0x01);                   // clear LCD.
   	nop();
   	lcd_cmd(0x06);                  // increment cursor i.e. shift cursor to right.(Entery mode)
   	nop();
   	lcd_cmd(0x80);                  // line-1, position-0.	
   	nop();
}

void lcd_clear(void)
{
   	lcd_cmd(0x01);                   // clear LCD.
   	nop();
}

void lcd_cmd(unsigned char value)
{
	ldata = value;
	rs = 0;
  	rw = 0;
  	en = 1;
	nop();
  	en = 0;
}


void lcd_data(unsigned char value)
{
	ldata = value;
   	rs = 1;
   	rw = 0;
   	en = 1;
   	nop();
   	en = 0;
}

	

void nop()
{
    unsigned char q=0;
    for(q=0;q<200;q++);
}

- - - Updated - - -

hi Keith,
I tried as you suggest but its not working.
 

You indicated you were not getting the expected results.

What results were you getting? How are you monitoring these results, by setting breakpoints in the code?

I would suggest simplifying the task to an absolute minimum.

Simply obtain a raw ADC value from the AMC7820 via the SPI interface and output the data on your LCD.

Don't even attempt to convert it to floating point, just raw data.


BigDog
 

why are you storing the same value in an array ten times? Do you just want to convert the adc value into float and display in lcd as string?
 

The code you posted doesn't actually do the casting as I suggested but as Bigdog suggested, it shouldn't be necessary.

The simple way to debug the problem is to trace the initial ADC value through the code and see where it goes wrong. A few breakpoints, some single stepping and watching some variables should soon find the problem.

If you reach the LCD routine with the correct float value then maybe it is simply a problem with displaying the value.

Keith
 

After getting result from ADC i store it in array 8 times not 10 times
because i have 8 channel ADC, for future usage i store it in array
ADC gives 16 bit data in that MSB nibble is for address
AD2 AD1 AD0 DV
Where,
AD2-AD0=address
DV= data valid bit
after neglecting MSB nibble i store data in array2
i.e 12 bit
i moniter the result in watch window (see my attachment)
i m not connect the LCD yet

now i attach the image after converting for voltage

in file new_1 the array temp_f is unsigned float
with display property IEEE float
and filled with result after completing voltage-conv() routine

in file new_2 array2 is unsigned int after checking valid data and neglecting MSB nibble

I have to convert ADC data into float because i m gonna connect PT100 temperature register and pressure sensor

- - - Updated - - -

yes i have that evaluation module
and due to some mistake i burn the AMC7820
and now I solder new one and work on it

- - - Updated - - -

hi internetuser2k12,
i am not storing 10 time it only 8 times as ADC has 8 channel.

Even the calculation are pretty simple

result = ADC_DATA / 4096
voltage = 5 * result;

still i didnt get yet.

- - - Updated - - -

i also posted thread about AMC7820 when i m in trouble with interfacing
But unfortunately no one help that time but its ok thats my fault i underestimate the RESET pin
that was active low and pulled down internally.
 

Attachments

  • new_1.JPG
    new_1.JPG
    129.9 KB · Views: 85
  • new_2.JPG
    new_2.JPG
    119.5 KB · Views: 96
Last edited:

Are you reading from 8 adc channels? I see that all the 8 elements of the array are holding the same value. Can't you use adc that comes with pic18F87K22. It has 12 bit adc. Is your adc input between 0 and 5 volts. Are you sure you are getting a max value of 4095 for 5 volts?

If you are reading from only 1 channel then you don't have to store the value 8 times.

See the attachment. I am using internal 12 bit adc of PIC18F87K22.
 

Attachments

  • ss18.jpg
    ss18.jpg
    255 KB · Views: 79
Last edited:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top