ADC interpretation

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

ADC interpretation

Jump to solution
1,092 Views
GMVS
Contributor III

please help

this shouldnt be a difficult question to answer and it gets freaking frustrating to have 40 views and no response of anykind

 

i'm trying to use the adc, lets forget about EMI and coupling for the time being

 

assume this

ADC 0 = 0V

ADC 255 = 650V

 

if i get a 237 from the ADC

the voltage should be 237*650/255=604

at least that's what i want...

 

but it doesn't works, i assume its due type

 

if i do this

 

unsigned char ADCmeasure;

unsigned int Voltage;

ADC1_Measure(1);

ADC1_GetValue8(ADCReadBuffer);

ADCm=ADCReadBuffer[0];

Voltage=(int)ADCm*650/255;

 

it compiles but is not correct

i think because ADCmeasure*650 might not fit on a int

 

 

if i do this

 

unsigned int ADCm;

long Voltage;

ADC1_Measure(1); //measure

ADC1_GetValue8(ADCReadBuffer); //record

ADCm=(int)ADCReadBuffer[0]; //get first number and cast it to int

Voltage=ADCm*2.54902; //interpret it

ADCm=Voltage; //truncate it

 

it breaks saying

_DMUL_RC, _DSTRUNC, _DUFLOAT are not defined

 

 

if i do this

 

unsigned int ADCm;

long Voltage;

ADC1_Measure(1); //measure

ADC1_GetValue8(ADCReadBuffer); //record

ADCm=(int)ADCReadBuffer[0]; //get first number and cast it to int

Voltage=ADCm*650/255; //interpret it

ADCm=Voltage; //truncate it

 

it compiles but still is not correct

i think because it is messing with the sign or something for supposedly negative stuff

 

 

 

so how do i do this?

do i rather make the table of what each adc step mean and just look out for it?

would that be faster than dividing and multiplying on a 8 bit mcu?

 

thanks

 

 

 

Labels (1)
0 Kudos
1 Solution
798 Views
bigmac
Specialist III

Hello,

It should be possible to stay with a 16-bit calculation, since it will be more efficient than a 32-bit calculation.

In place of the expression

Voltage = (int)ADCm * 650 / 255;

instead use the following equivalent, whose intermediate result will not overflow a 16-bit value.
unsigned int Voltage;

...

Voltage = (unsigned int)ADCm * 130 / 51;

For the case of the 32-bit calculation, another way of forcing this would be -

long Voltage;

...

Voltage = ADCm * 650L / 255;

Regards,

Mac

View solution in original post

0 Kudos
5 Replies
799 Views
bigmac
Specialist III

Hello,

It should be possible to stay with a 16-bit calculation, since it will be more efficient than a 32-bit calculation.

In place of the expression

Voltage = (int)ADCm * 650 / 255;

instead use the following equivalent, whose intermediate result will not overflow a 16-bit value.
unsigned int Voltage;

...

Voltage = (unsigned int)ADCm * 130 / 51;

For the case of the 32-bit calculation, another way of forcing this would be -

long Voltage;

...

Voltage = ADCm * 650L / 255;

Regards,

Mac

0 Kudos
798 Views
GMVS
Contributor III

excelent! this is what worked the best, thanks a lot!

you too kef

one last question, optional tho

i need to show this converted value on a 2x16 LCD

after your answer i came up with this

void hex2dec(unsigned int hex, char *dec)

{

  unsigned int temp=0;

  if (hex==0) {

  *dec = '0';

  return;

  }

  while(hex!=0){

  temp=hex%10;  // <------------this...

  *dec = (char) temp + '0';

  hex=hex/10;   // <------------and this are gonna take a lot of time to get done, won't they? and they require a lot of code, aren't they?

  dec--;

  }

}

void main(){

/*somewhere in the main*/

  ADC1_Measure(1);

  ADC1_GetValue8(ADCReadBuffer);

  ADCm=ADCReadBuffer[0];

  Voltage=(unsigned int)ADCm*130/51;

  strcpy(blaf, "ADC: 0x    ,    V");

  hex2ascii((int)ADCm, banner+10);

  hex2dec(Voltage, banner+15);

  LCD_clear();

  LCD_sendString(banner);

/*way more code*/

}

but before that i had this

unsigned char HVBm[][4] = {

/*all (255) equivalent values in asacii for ADC measures*/    //<------- 1 k of memory gone

}

void main (){

/*somewhere in the main*/

ADC1_Measure(1);

ADC1_GetValue8(ADCReadBuffer);

strcpy(blaf, "ADC: 0x    , "+ 0 );

  hex2ascii((int)ADCm, blaf+10);

  LCD_clear();

  LCD_sendString(blaf);

  LCD_sendString(HVBm[ADCm]);

  LCD_sendChar("V");

//code code code

}

which approach would be better? in the end both present the info the way i want it

but i'm limited in

  • memory (i wouldn't like to have an array using a whole 1K just for this),
  • program size (i cant make the code too large, c code may appear short but asm might get wild)
  • execution time (there's a lot to do and so little time... this is a design requirement)

i think my highst priority is execution time

what do you think?

0 Kudos
798 Views
bigmac
Specialist III

Hello,

From your template string, I am guessing that you wish to display the raw ADC data as a hexadecimal value, followed by the scaled decimal value representing the voltage?  Assuming this is so, I have "streamlined" and rationalised the code to some extent, as follows -

#include <string.h>

//                        0000000000111111
//                        0123456789012345
const byte template1[] = "ADC: 0x--,   0 V";


void Show_ADC_result( word value)
{
   byte buf[17], i, c;

   // Copy template to buffer (779 cycles)
   (void)strcpy( buf, template1);

   // Insert hexadecimal value in template (49-65 cycles)
   c = ((value & 0xF0) >> 4) + '0';  // Upper nybble
   if (c > '9')  c += 7;
   buf[7] = c;
   c = (value & 0x0F) + '0';         // Lower nybble
   if (c > '9')  c += 7;
   buf[8] = c;

   // Insert scaled decimal value in template (215 + 671 cycles)
   value = value * 130 / 51;         // Scale value
   for (i = 13; value; i--) {
      buf[i] = (value % 10) + '0';
      value /= 10;
   }

   LCD_clear();          // Minimum 1640 us
   LCD_sendString( buf); // Minimum 640 us (16 * 40 us)
}

Not including the LCD operations, the processing will require about 1750 cycles.  For a bus frequency of 10 MHz, this would amount to a period of 175 microseconds.  However, the LCD operations are notoriously slow.  When these are implemented in the usual manner, the minimum durations, required by the display, are as I have indicated.  In comparison, the time required for the string processing is insignificant.  Depending on the actual implementation of the LCD functions, the delays could be much longer than the minimum requirement.

To speed the function execution time, you might use a more complex LCD write method, where the individual characters of the string are actually written during a periodic timer interrupt, thus avoiding the need to wait for the total write period within the above function.

I also question whether you need to clear the LCD and home the cursor, as you are doing.  Since the data string writes to all 16 positions of a display line, simply over-write the previous data.  This would then require only that the cursor be positioned to the start of the display line, requiring 40 microseconds (rather than 1640 microseconds).

Regards,

Mac

0 Kudos
798 Views
kef
Specialist I

Look up table should be the fastest and the best, provided you have space for it.

But the speed of LCD display routine is usually not important. You may lower refresh frequency, you may use preemptive RTOS, etc.

0 Kudos
798 Views
kef
Specialist I
  • _DMUL_RC, _DSTRUNC, _DUFLOAT are not defined

These are double precision floating point routines. Creating project you had to tell project wizard that you want floating point sipport.

  • unsigned int ADCm;
  • long Voltage;
  • Voltage=ADCm*650/255; //interpret it

Though Voltage is long, expression on the right is calculates as all int, as a result multiply overflows and you see weird result. Try typecasting one or both multipliers to get expected result:

Voltage=(long)ADCm*650/255;