Reputation:
I am measuring AC Voltage and I am calculating rms value for ADC.
I have an array which is having 128 samples of my signal. while squaring number I get an error.
unsigned long int calval=0;
unsigned int loop;
float adcbufval;
for(loop=0;loop<128;loop++)
{
printf("adcval %d = %d\t ", loop, adc_temp[loop]);
calval = (adc_temp[loop])*(adc_temp[loop]);
printf("\t %ld \n", calval);
}
output:
adcval 1 = 168 28224
adcval 2 = 32 1024
adcval 3 = -88 7744
adcval 4 = -211 44521 // sqr(211) 44521 , it fine here
adcval 5 = -314 33060 // sqr(314) 98596-65536 = 33060 instead of 98596.
adcval 6 = -416 41984
adcval 7 = -522 10340
adcval 8 = -655 35809
adcval 9 = -773 7705
adcval 10 = -889 3889
Though I defined 'calval' as unsigned long int (range 0-4,294,967,295), it get over flowed at 65536 value. In normal C compiler its working fine. Any suggestions?
Hardware is dsPIC30f5011 / MPLAB 8.8x
Upvotes: 0
Views: 180
Reputation: 4751
You haven't shown it (or I've overlooked it), but if adc_temp[]
is an array of int, then to safely square the values you must cast at least one side of the multiplication to long
before doing so. Otherwise the result of the multiplication will still be int
, and it will only be converted to unsigned long
for the assignment, after overflow has already occurred.
Like so:
calval = (long)(adc_temp[loop])*(adc_temp[loop]);
That cast may be unsigned long
if adc_temp[]
is also unsigned.
Upvotes: 3
Reputation: 5128
According to the datasheet the dsPIC30f5011 is a 16bit microcontroller, according to C99 you are correct unsigned long
should be 2^32. However it appears that the compiler you are using treats long
as an alias for int
which is still compliant with C90 which simply required sizeof(short) <= sizeof(int) <= sizeof(long)
. You might have better luck if you really need 32bit math using unsigned long long
.
Upvotes: 0