hello all, i have an atmega 1280 and what i am trying to do is measure the voltage in an analog pin.
the voltage i am trying to measure is going to be changing almost every 4milliseconds.
My questions is i guess would be what would be the best way to measure that voltage?
Here is what i have so far (voltage will be between 0.2V to 0.8V max so i changed the analogreference to INTERNAL1V1
[code]float powerConsumption(int PIN) {
analogReference (INTERNAL1V1); // measure up to 1.1V
long currentDRAINpin = 0;
double currentDRAIN = 0.0;
double VOLTScurrentDRAIN = 0.0;
double power = 0.0;
//read 5000 samples to stabilise value
for (int i=0; i<5000; i++) {
currentDRAINpin += analogRead(PIN);
delay(1);
}
currentDRAIN = (1.0*currentDRAINpin)/5000;
VOLTScurrentDRAIN = currentDRAIN * (1.1 / 1024.0);
// Calculate the power consumption assuming 8V input
power = (VOLTScurrentDRAIN*8)/(0.025*50);
Serial.print(currentDRAINpin);
Serial.print(" , ");
Serial.print(currentDRAIN,4);
Serial.print(" , ");
Serial.print(VOLTScurrentDRAIN,4);
Serial.print(" , ");
Serial.println(power,4);
}
[/code]
I would think from what i read that the sampling rate of the arduino is adequate for this kind of measurement right?
As you can see i try to take 5000 samples so i can get a more stable value.
Is there a better more efficient way? Are 5000 times too much?
5000 is way too much, 8, 16 or 32 will do quite well. ( a power of 2 will be fast for the MCU if the math is integer) and 16/32 will prevent overflow during the summing.
AS the UNO can do about 8000 ADC's per second, 4 milliseconds equal about 32 measurements
in the sample below I use float to be as exact as possible, int math has rounding errors. Some numbers are pre-calculated to keep as much accuracy as possible.
furthermore I reduce the number of vars, and declare the vars when I need them.
float powerConsumption(int PIN)
{
// MEASURE
analogReference (INTERNAL1V1); // measure up to 1.1V
float currentDRAIN = 0;
for (int i = 0; i < 32; i++) currentDRAIN += analogRead(PIN);
currentDRAIN /= 32.0;
// MATH
double VOLTScurrentDRAIN = currentDrain * 0.001074219; // == *1.1/1024; optimized
double power = VOLTScurrentDRAIN * 6.4; // == *8)/(0.025*50); optimized
// OUTPUT
Serial.print(currentDRAIN,4);
Serial.print(" , ");
Serial.print(VOLTScurrentDRAIN,4);
Serial.print(" , ");
Serial.println(power,4);
return power; // was missing;
}
Note: it would be more precise to calc power directly from currentDrain
You should always take some Arduino with you, wherever you go
jackwp +1 (good suggestion)
// dividing by a power of two is faster (at least for integers), note that you can select any weights to match preferred behavior
average = average * 3 + newReading / 4;
average = average * 5 + newReading * 3 / 8;
average = average * 7 + newReading / 8;
average = average + newReading * 7 / 8;
hello all, once again, thanks for all suggestions!
So i tried the code proposed, and i tried the averaging as well, now my code looks like this:
float powerConsumption(int PIN)
{
// MEASURE
analogReference (INTERNAL1V1); // measure up to 1.1V
int times = 32;
float currentDRAIN = 0;
float averageDRAIN = 0;
for (int i = 0; i < times; i++) {
currentDRAIN = analogRead(PIN);
averageDRAIN = (((averageDRAIN * i) + currentDRAIN))/(i + 1);
}
// MATH
double VOLTScurrentDRAIN = averageDRAIN * 0.001074219; // == *1.1/1024; optimized
double power = VOLTScurrentDRAIN * 6.4; // == *8)/(0.025*50); optimized
// OUTPUT
Serial.print(currentDRAIN); // last reading
Serial.print(" , ");
Serial.print(currentDRAIN,4); // avg reading
Serial.print(" , ");
Serial.print(VOLTScurrentDRAIN,4); // reading in volts
Serial.print(" , ");
Serial.println(power,4); // power consumption
}
I am getting better results, but still not good enough
When i attach a multimeter and read the voltage i get around .06 to .07 volts
When i read with arduino every 5 sec i readings from 0.03 to 0.08.
What would be the best way to make it as "smooth" as the multimeter?
That is a pretty small voltage. Are you using Vref on the arduino, or just the 5 volt reference?
You may also consider using an op amp to get the voltage a bit higher.
i am using the :
analogReference (INTERNAL1V1); // measure up to 1.1V
It seems it can read the voltage fine, its just that the average voltage is not the same as i get with the multimeter...
Some time it is but not if i average it...
sorry yes you are correct this is actually done just to print stuff (placeholder) i am not taking into account these values,I only really care about the power and the voltage.
so before i was getting values like 0.030 to 0.080
now i am getting more "constant values" from like 0.050 to 0.060
According to my multimeter i should be getting more like 0.060 to 0.068
so according to robtillaart the uno (which i think the mega 1280 that i have is the same as far as adc readings go) can do about 8000 ADC's per second, 4 milliseconds equal about 32 measurements.
I thought i needed to measure 4 ms of adc samples but i think i need more like 1 second of measurements and average it out.
Having said that i think i need to do 8000 readings????
what is the best way ?
Thanks
8000 readings seems extreme. Averaging the last 6 would be good as I see it. What are you reading anyway? How fast does it change?
What is your goal here?
yes 5000 was extreme 8000 is more extreme
I am trying to read a voltage that varies in times of 4 to 40 ms. there are spikes that it will go to .7 volts but there are times where its going to read around .5 volts. and thats why i want to find the average. I am reading the voltage off a hardware and depending on the voltage i can get the power consumption of this device from that specific pin.
The goal is to find the average power consumption computed from that voltage.
I know 8000 is very extreme but now i get more "constant" voltages between 0.0551 to 0.0558.
Its just that i was expecting to read something like 0.06xx. MAybe i am wrong or the multimeter is just reading the spikes most of the time...
i am not sure
A multimeter will probably average over a significant fraction of a second. If you want to replicate that, and you are taking a reading every 4ms, try summing 1024 readings into an unsigned long variable, then divide the sum by 1024 to get the average.
0.055 volts is really small. It is possible you are picking up some stray signals to cause variations.
Keep the wire as short as possible, and consider using shielded cable.
If you don't yet have a capacitor on the analog line, and placed around at several places, it may help to add some.
If you have more than one volt meter, check with both. maybe the volt meter is not 100% accurate.
In your sketch, try taking two analog readings, discard the first, and use the second.
The assumption seems to be that the Voltmeter is correct.
I suggest it's not unless you have a rather hi end voltmeter.
Perhaps you might check the levels using a calibrated scope?
The scope will show the peaks better if the signals are somewhat repetitive.
hello all thanks for the replies...
So i did think about the vlotmeter and wrong calculations and did try it with a scope.
I ended up also making the program to take measurements every 1 ms and for 100 times and was able to plot the results.
I think i had a wrong factor in my math. After that everything worked out fine!
So the cable is as short as possible and the measurements are now perfect ...
Thanks again!