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
Solved! Go to Solution.
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
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
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
i think my highst priority is execution time
what do you think?
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
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.
These are double precision floating point routines. Creating project you had to tell project wizard that you want floating point sipport.
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;