Uno: signal sampling at 1 kHz

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:

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;*
    }
    [/quote]
 Serial.begin(9600);

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.

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.

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

Why only seven bits?

Why only seven bits?

Typo. Thanks.

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

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

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.

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...

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.

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".

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.