How to Get Faster Serial Port Output

I’m tryin to get data from a force sensor via Arduino Uno R3. This sensor tryin to catch a rifle’s recoil force. So, this recoil motion is happening just in 10-15 miliseconds.

I can get one data point in every ~750 microseconds right now. This cause me to get a rough recoil force graphic. So I need to read more data in a shorter time span. I assume minimum 10 data points in one milisecond.

What should I do in the next step?

  • Upgrade to Arduino Due for faster clock speed and ADC (i don’t know if I can read faster data from USB port even if I upgrade to a faster board)
  • Change the way to read data. Maybe not using USB but writing data in a SD card???
  • Change codes
int analogToGram;
 
void setup(void) {
  Serial.begin(2000000);
}

void loop(void) {
  while (analogRead(A0) != 0){;
    Serial.print(micros());
    Serial.print(",");
    Serial.println(map(analogRead(A0), 0, 1023, 0, 10000));
  }
}

15mS worth of data at (say) 5K samples per second is only 5x15 samples = 75. You could store this in a buffer and send all samples back when the recoil has completed. With the right Arduino you could easily store 1000 samples and if you use a circular buffer then you won't have to know when the recoil starts; just when it ends (detecting the bang and a timer could be used to indicate that).

You need to separate getting the data from sending it. If you try to send the data as it's aquired you are limited by the serial port speed, as you have discovered. Write the data into a buffer as fast as possible, then, once the data has been collected send it out over serial.

1 Like

Reduce the code to only do one analogRead per lopp. Frop the map function and print the raw data. Map doesn't adf any information, only consumes time.

You can use an ESP32 and its dual cores. One core could be doing the sampling and, independently, the other core can be doing the data 'saving'.

A ring buffer can serve as the interface between the 2 tasks.

As a note:

The ESP32 has a built in Ring Buffer available though the OS, freeRTOS. See: FreeRTOS Additions - ESP32 - — ESP-IDF Programming Guide latest documentation.

I used the ring buffer in a project that graphed Myoware info to an OLED screen. I used a ESP32 WROVER, which allowed me to use a 3MB ring buffer of floats.

I believe the analogRead limits your as well. It is possible to make faster readings but the default speed is low.

Thank you everybody for support! Now I can read almost 10 datas in 1 millisecond. This is almost perfect.

But we have another problem which we can’t understand.

Here is the code I wrote after your suggestions,

int sensor[200];
long microsecond[200];
 
void setup(void) {
  Serial.begin(9600);
}

void loop(void) {
  start:
  if(analogRead(A0) == 0)
  {
    goto start;
  }
  
  for(int i=1; i<201; i++)
  {
    sensor[i] = analogRead(A0);
    microsecond[i] = micros();
  }

  for(int i=1; i<201; i++)
  {
    Serial.print(microsecond[i]);
    Serial.print(",");
    Serial.println(map(sensor[i], 0, 1023, 0, 10000));
    delay(20);
  }
  delay(3000);
}

The problem is, we can’t see all three “Serial.print” values on screen in the same line. It prints just one array inside the last “for” loop. Either we choose “microsecond” array or just commas, or just “sensor” array where we use “map”. When we ask for all three values to print, nothing comes on screen.

For example,

for(int i=1; i<201; i++)
  {
    Serial.print(microsecond[i]);
    //Serial.print(",");
    //Serial.println(map(sensor[i], 0, 1023, 0, 10000));
    delay(20);
  }

This code works. But if I delete “//” from next line, it doesn’t give anything.

WYSIWIC: what you see is what you coded :wink:

If you always use println() then each output ends up in its own line. Use print() instead except for the last output on a line which remains println().

Also fix your for loops: index should go from 0 to 199.

DrDiettrich:
WYSIWIC: what you see is what you coded :wink:

If you always use println() then each output ends up in its own line. Use print() instead except for the last output on a line which remains println().

That's right :slight_smile: sorry, my mistake. I was trying different methods. Actually I knew this (print() vs. println()) and tried this way too but it still doesn't work.

Ookay now it miraculously started to work. Thanks again everyone

Hi,
Do you need to sample the recoil through its entire motion, or are you just interested in the maximum value?

If maximum value, just make a sample hold / peak detect circuit and you don’t need all that high speed sampling?

Tom… :slight_smile:

TomGeorge:
Hi,
Do you need to sample the recoil through its entire motion, or are you just interested in the maximum value?

If maximum value, just make a sample hold / peak detect circuit and you don't need all that high speed sampling?

Tom.... :slight_smile:

Hey,

We need entire motion and graph.Thats why we are looking for high sampling rate.