How to collect 1000 samples per second precisely

hello, I need to read data from a sensor at a rate of 1000 samples per second from a sensor using arduino. How can I do this accurately and efficiently?

I tried using the millis functions, but I can not get a uniform collection frequency.

time_ppg.ino (803 Bytes)

You would have to program one of the timers to cause an interrupt every 16000 clock cycles, which would disable at least one and probably two PWM outputs (you'd use one of the output captures to change the "end" count of the counter.) The timer used for millis() interrupts every 16384 clock cycles (prescaler of 64, and "interrupt on overflow" at 256), which frees both OCRs for PWM.

Check out the timer1 library, probably.

What you have described and what code you presented do not match up.

Loop could compare current mills to previous mill and
if they are the same do nothing
if they are different, do something and set previous mills to equal the current mills

Then compare current mills to a “time to serial print” mills variable and if greater that that arbitrary 2100 you selected print and update time to serial print mills to current mills.

Besides just reading the analog value 1000 times a second, what is the actual goal for the data?

This method would get you pretty close to your sample speed, but as noted above you can really dial it in to get it “exactly”.

this sounds a bit unreasonalble that you would need 1000 readings per second. to put things into perspective, even the most advanced video games on desktops with 6 core CPU's generally function at 60 to 100 frames per second and do amazing things. high definition video runs at 50 - 60 times a second. asking a little development board to run 1000 times per second is a bit unreasonable. some arduino boards only carry around 2000 bytes of ram memory for variable storage so you would max out your little board in under a couple seconds if you did accomplish this. and even if you did its pry not enough time for the regester states in your sensors to change anyways.

but the good thing is if you tell us what you are accutally trying to accomplish, im sure your board can do it. i really dont think you need 1000 readings a second

How precisely is "precisely"? Will micros() work for you?

Most arduinos use a resonator rather than a crystal, and the clock speed can drift by 5% or more in response to temperature. If you really need this kind of accuracy, purchase a clock module for ten bucks, get it to output a 1kHz square wave (which most of them will do), and hook that up to an interrupt pin.

How precisely is "precisely"? Will micros() work for you?

That is my question also, and I see little prospect of sensible progress until the OP has answered it.

And to elaborate, what is the acceptable maximum timing error (in microsecs) between successive readings? (By the way "zero" is the wrong answer).


In your code you are attempting to read the value of an analog pin multiple times per second. Similar to @Westfw’s solution, if you are using an AVR based micro controller (Nano, uno etc.) you can set a timer to directly drive the ADC at the required sample rate. This triggers an ADC interrupt when the sample conversion is complete and you can process that sample in the ADC interrupt service routine. There is an example here in a demodulator sampling an analog value at 9600 Hz (which I have also extracted successfully for one of my projects):

See AFSK_hw_init(void) and ISR(ADC_vect)

long myValues[2100];

BTY: What arduino are you using ?

Hello, I'm sorry for not making some things clear on the topic.

I need to read 1000 samples per second from a PPG sensor, because I'm developing a prototype with some intelligent processing, and the dataset I use has that sampling, so it needs to at least get close to that value.

In fact, the accuracy of reading at the moment is not as important as long as it has something close to the value above.

As for the millis () function, I got a sampling of 700 per second.

Reading the above answers, will I have to work directly with the registers?

I'm using Arduino Uno, but I plan to use it on a NodeMCU card (ESP8266). I know the specs are different and the way they work as well, but I'd like to test both boards.

I apologize if I am asking questions that may not seem so clear, but I do not have much experience with the arduino.

As for the millis () function, I got a sampling of 700 per second.

A side-effect of the slow line speed you’re printing to.

//  Variables
int PulseSensorPurplePin = 0;        // Pulse Sensor PURPLE WIRE connected to ANALOG PIN 0

int Threshold = 550;            // Determine which Signal to "count as a beat", and which to ingore.

long initMillis = 0;
long count = 0;
long values = 2100;

long myValues[2100];
unsigned long currentMillis;

// The SetUp Function:
void setup() {
  Serial.begin(9600);         // Set's up Serial Communication at certain speed.

// The Main Loop Function
void loop() {
  currentMillis = millis();
  if ((currentMillis - initMillis < values)){
    myValues[count++] = analogRead(PulseSensorPurplePin);
  }else if(currentMillis - initMillis > values && count != 0){
    Serial.print("Count  ");

I’m using Arduino Uno


Sorry, I do not understand this

A side-effect of the slow line speed you're printing to.

How many characters can you print per second?

  Serial.begin(9600);         // Set's up Serial Communication at certain speed.

How much memory does the Uno have?

long myValues[2100];

OK, maybe I mis-read your code.

However, I don't understand this

I'm using Arduino Uno

How does that code even compile for a Uno?

How does that code even compile for a Uno?

Sorry is based on Arduino Mega.

How many characters can you print per second?

  Serial.begin(9600);         // Set's up Serial Communication at certain speed.

Does the Serial communication rate influence the ability to read analog inputs?

How does that code even compile for a Uno?

It does compile for the Pro Mini without reporting any errors (IDE 1.8.9), and issues this report, which I can't believe. Where is myValues?

Sketch uses 1974 bytes (6%) of program storage space. Maximum is 30720 bytes.
Global variables use 200 bytes (9%) of dynamic memory, leaving 1848 bytes for local variables. Maximum is 2048 bytes.

Probably because myValues is treated as non-volatile WOM, so gets optimised away.

Does the Serial communication rate influence the ability to read analog inputs?

Yes, if you immediately print them out, which is what I thought you were doing at first.

Please answer the other question, but substitute "Mega", and compare that with the size of myValues.

gets optimised away

That must be it. Smart compiler!

Excuse me, but is there any way I can do this sampling?

I took a look at what @westtw said, but I did not quite understand the idea.

The sampling would be 1kHz, can I do this by saving the analog input reading?

Take a look at the blink without delay example in the IDE, but substitute micros for millis.