Go Down

Topic: Uno: signal sampling at 1 kHz (Read 964 times) previous topic - next topic

jw_p

For a project that I'm working on, I need to sample an analog signal at exactly 1 kHz, preferably for 1 or 2 seconds and send the data via serial (well this, among other things, but this is the biggest challenge).  I'm already trying this for a few days, without big success.
My first approach was to write signal to memory and then send the whole array, but the memory of the Uno is not big enough to hold all the 1000 samples (this might be easier to do on an Arduino Mega)....
Another difficulty is to time the loop. Of course there is the delay() function, but with this function, one iteration will certainly take longer then 1 ms. I've tried to overcome this by using the micros() timer in a while loop (thereby reducing the jitter of one iteration).

Probably, I'm in a complete wrong direction and there is something much easier for this...any tips or tricks are welcome!

So far, a snippet of my code is:
Quote

int buf[100]; //the buffer, needs to be size 1000?
unsigned long t0;
unsigned long t1;
int val;

void setup() {
  Serial.begin(9600);
}

void loop() {
  for (int i = 0; i < 100; i++){
    buf = timedLoop(); // fill the buffer
  }
  for (int i = 0; i < 100; i++){
    Serial.print(buf, DEC);
    Serial.print(","); // generate comma-separated values
    Serial.flush(); // make sure all the data is written
  }
}

int timedLoop() {
  t0 = micros();
  val = analogRead(0); //read the signal from AI0
  do
  {
    t1 = micros() - t0;
  } while (t1 < 1000); // execute this while loop for max 1000 micros
  return val;
}



AWOL

Code: [Select]
Serial.begin(9600);
I'd bump that way up for a start - it takes over 1ms to transmit a single digit at that speed.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

michael_x

If you reduce resolution (byte)(analogRead(A0) >> 3) you should be able to buffer about 1000 and you can send them easily in binary.

I built a kind of oscilloscope that way ( display 1000 values horizontally and 255 pixel high is sufficient resolution for me)
With standard analogRead I could chould choose the x resolution to anything above 200 ms.

Of course it was not continuous, but just captured 200 ms / 500 ms / 1 sec / 2 sec snapshots.

AWOL

Quote
If you reduce resolution (byte)(analogRead(A0) >> 3)

Why only seven bits?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

michael_x

Quote
Why only seven bits?

Typo. Thanks.

BTW, I've read that if you type /4, compiler creates a shift operation? 

jw_p


I'd bump that way up for a start - it takes over 1ms to transmit a single digit at that speed.


If you reduce resolution (byte)(analogRead(A0) >> 3) you should be able to buffer about 1000 and you can send them easily in binary.

OK, two great tips (although the first one was pretty obvious, but I totally overlooked it...).
So far it reduced two problems:
- Buffering the data
- Sending the data

I'm still not sure about the timing thing in a while loop...

michael_x


Code: [Select]

int timedLoop() {
  unsigned long tnow;
  do
      tnow = micros();
  while ( (tnow - t0) < 1000 );  // waits until time has come
  t0 += 1000;
  val = analogRead(0); //read the signal from AI0
  return val;
}


As you increment t0 by the number of micros in a milli (1000 ), you can take any time ( < 1 ms ) for your timedLoop() and don't experience a drift.


Magician

There is TimerOne library, you can set sampling interval exactly at 1 kHz.  Probably, you also don't have to store samples in a buffer, at 115200 kbps you could stream data "real time".

PaulS

Quote
For a project that I'm working on, I need to sample an analog signal at exactly 1 kHz, preferably for 1 or 2 seconds

You want to do something for one or 2 seconds, 1000 times per second? You need a time stretcher.

Go Up