I am reading analog sensor data using Arduino nano, and the required sampling rate is around 1kHz. I am using the AnalogReadSerial example provided by Arduino with a delay of 1ms, so I am expecting to get around 1000 samples per second or slightly less due to the ADC conversion delay. However, the maximum number of samples I am able to get in my laptop a little bit less than 200 samples per seconds. I have tried increasing the baud rate to 115200 but that was not helpful. Am I missing something here, or is there something I need to do to get my data at the required sampling rate?
Below is AnalogReadSerial code I used for reference:
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(115200);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
delay(1); // delay in between reads for stability
}
1 Answer 1
As I said in a comment, your code on my Uno gives me 791.5 samples/s. This is about 1263 μs per sample:
- about 110 μs for
analogRead()
, including 104 μs for the conversion proper - presumably 1000 μs for
delay(1)
- 153 μs for the rest of the code, mostly formatting
sensorValue
in ASCII
According to these timings, if it were not for the call to delay()
,
the Arduino should be able to complete the loop in one millisecond, and
still have 737 μs to spare. The simplest way to achieve this is to
follow the Blink Without Delay strategy:
void loop() {
static uint32_t last_conversion_time = micros();
if (micros() - last_conversion_time >= 1000) {
last_conversion_time += 1000;
Serial.println(analogRead(A0));
}
}
This does give me 1000 samples per second. Note that
last_conversion_time
is updated by adding 1000 μs rather than
setting it to micros()
, so this is actually a variation on the Blink
Without Delay strategy. Updating last_conversion_time
in this fashion
ensures that whenever the program gets late and misses the exact
microsecond it wanted, the small timing errors do not accumulate.
For the maximum possible timing accuracy, it would be more appropriate to trigger the ADC by a timer, but that approach is more complex and requires carefully reading the datasheet of the microcontroller.
-
I would not call it BlinkWithoutDelay strategy. It is different. It would be better to initialize last_conversion_time with micros() so it doesn't have to catch up with 1ms increments the time lost in setup() .2022年01月18日 21:09:09 +00:00Commented Jan 18, 2022 at 21:09
-
@Juraj: I edited the answer to account for your comments. I would usually prefer letting
last_conversion_time
be initialized to zero, unlesssetup()
is really slow (not the case here): this saves the cost of a guard variable and a test at each loop iteration. But then, maybe I tend to micro-optimize too much...Edgar Bonet– Edgar Bonet2022年01月18日 21:34:28 +00:00Commented Jan 18, 2022 at 21:34
Explore related questions
See similar questions with these tags.
millis()
before and afterint sensorValue = analogRead(A0);
... then print the two valuesssty
because the default was 9600. Right now, I am getting data at a rate similar to yours @Edgar Bonet, which is better but still a little bit shy of the required rate. @PMF your calculations make sense and this baudrate should be within my laptop's and Arduino nano's limits, which is still confusing to me. I will remove the delay and check if that makes any difference.