Just to as a complement to Majenko's answer (which I second), there are
a couple of flaws in your program that may be related to your problem:
lowest
is always zero, as it is initialized to 0 and cannot increase
- your computation of the mean is incorrect: the mean is the sum of the
readings divided by their number
- you fail to reset
lowest
and highest
between consecutive runs of
8000 samples
- there is no point in putting all of
loop()
inside an infinite loop.
Assuming you really intend to print summary statistics on runs of
8000 samples, as your code suggests, I would write it like this:
const int SENSOR_PIN = A0;
const int SAMPLE_COUNT = 8000;
const uint32_t SAMPLE_PERIOD = 125; // 125 us
void loop()
{
long sum = 0;
int lowest = INT_MAX, highest = 0;
uint32_t lastTime = micros();
for (int i = 0; i < SAMPLE_COUNT; i++) {
// Wait until it's time.
while (micros() - lastTime < SAMPLE_PERIOD) ;
lastTime += SAMPLE_PERIOD;
// Take and process the sample.
int sensorValue = analogRead(SENSOR_PIN);
sum += sensorValue;
highest = max(highest, sensorValue);
lowest = min(lowest, sensorValue);
}
float mean = (float) sum / SAMPLE_COUNT;
Serial.print("mean: "); Serial.print(mean);
Serial.print(", minimum: "); Serial.print(lowest);
Serial.print(", maximum: "); Serial.println(highest);
Serial.flush();
}
Edit: I changed the code in order to keep a roughly constant
sampling rate of 8000 samp/s. The main change is that, before
taking a reading, we wait until it's time to do so (until
micros() - lastTime >= SAMPLE_PERIOD
).
Note that lastTime
could be updated with lastTime = micros()
, in
which case it would have hold the time we last took a sample. By
updating it with lastTime += SAMPLE_PERIOD
it instead holds the time
we shoud have taken the last sample. This is the right choice for
enforcing a given average sampling rate.
Running on an Uno: I have no experience with the Due, but here are
some remarks that would apply to an Uno, or any other AVR-based Arduino:
analogRead()
takes about 110 µs, which means we cannot sample
more than one channel, and we only have about 15 µs to process
the sample. Here the processing is simple enough that the Arduino can
do it in this limited time.
- There is some jitter in the sampling, because
micros()
has a limited
resolution of 4 µs, because of the timer interrupt kicking in
from time to time, and because the while
loop takes a finite amount
of time.
If I were to do something similar on an Uno, I would forgo
analogRead()
, configure the ADC to be triggered by a timer, and set
the timer to trigger the DC every 125 µs. Not only would this get
rid of the jitter, it would also allow the CPU to do its job in parallel
with the ADC, instead of just sitting idle and waiting until the ADC is
done. This would allow for more complex per-sample processing.
About the Due: As I said, I have no experience with this board. It
has a more capable processor, but this tells you nothing about the speed
of its ADC. I would expect to face the same issues as with the Uno,
though maybe to a lesser degree. I guess it should be possible to
trigger the ADC from a timer, but I have no idea how to do so.