12

I am using an Arduino Uno to send time and voltage information over the serial port to Python to plot. However the interval timings between successive time stamps appears to be increasing over time, affecting my plotting. This is especially true when the baud rate is set to 9600, where my initial time differences maybe 1320 and increases to 16400 after a relatively short period of time. When this rate is put to maximum of 115200 bps the change is slower and less noticeable, from around 1340 to 1500 even after a relatively long run of sending. All times are given in microseconds.

I would like to know if I can reduce or eliminate this effect, and if not understand why it exists. I have read things about interrupts and delays causing this, but I do not fully appreciate the complexity of the electronics at hand and would like to know:

  1. Can I get greater precision in the timing?
  2. What causes this change in timing?

Here is what I currently have:

#include <eHealth.h>

extern volatile unsigned long timer0_overflow_count;
float fanalog0;
int analog0;
unsigned long time;    

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

void loop() { 
  while (Serial.available()>0){  
    serialByte=Serial.read();
    if (serialByte=='S'){        
      while(1){
        fanalog0=eHealth.getECG();  
        // Use the timer0 => 1 tick every 4 us
        time=(timer0_overflow_count << 8) + TCNT0;        
        // Microseconds conversion.
        time=(time*4);   
        //Print in a file for simulation
        //Serial.print(time);
        //Serial.print(" ");
        Serial.print(fanalog0,5);
        Serial.print("\n");

        if (Serial.available()>0){
          serialByte=Serial.read();
          if (serialByte=='F')  break;
        }
      }
    }
  }
}
asheeshr
  • 3,847
  • 3
  • 26
  • 61
hawkar
  • 553
  • 2
  • 6
  • 12

3 Answers3

4

Use a timer and ISR (interrupt service routine) to make timing more accurate.

Take a look at my 1ms timed interrupt Proof of Concept. The idea is to have a reasonably accurate 1ms 'heartbeat' in the system that can be used to trigger other events. In the PoC it is used to blink an LED at ½Hz, but having access to the new variables millisecondCounter and secondCounter enables you to trigger events in the main loop at arbitrary (but accurately timed) moments.

jippie
  • 2,901
  • 14
  • 23
3

I can think of a few things that can impact the "consistency" of the serial write timings:

  • size of the data to be printout

this may be the most obvious thing to think of, but indeed the more you print, the more it'll take to handle it.

Solution: print format the string into a string of known length.

  • using buffered serial

on unix you can access the serial port using a buffered or an unbuffered way. Using the buffered way for a long time may make it a bit slower as the buffer fills, usually it happens when data is incoming faster than you're reading it…

Solution: use the unbuffered serial line (e.g.: on Darwin/OSX it's /dev/cu.usbmodemXXX instead of /dev/tty.usbmodemXXX)

  • priority of the timers

it looks like your using a TC interrupt, and AVRs have priorities in the way interrupts are handled, I don't know the order of priority for the Atmega328, and it's not one of the most documented feature around, so I don't know how safe is TC0 versus the UART interrupt.

Solution: look up further in the documentation/datasheet about interrupt priorities and change the timer if needed ; and/or do a test without having the other timer running.

  • the data you're reading from takes more time to read from over time

some drivers need to average or do some operations over the previous values, so the more values you measure, the longer the buffer is, and the longer it takes to calculate the value, until you've reached the maximum size of the buffer.

Solution: look at the source code of the library you're using, and either optimize it, remove the calcul if there's one or take that increasing processing time into account.

  • avoiding the arduino framework overhead

but if you really want to optimize serial output from the arduino, you should avoid using the arduino overhead… But it's way less elegant and comfortable to use.

I'm pretty sure there are other points I'm missing, but that's the first things that I'd check before digging further.

HTH

zmo
  • 1,518
  • 10
  • 16
2

Your code includes the duration of the output in subsequent measurements. Thus depending on the length of the output you will measure different times. This can be fixed by formating to fixed length output.

The next issue is that the UNO has a very poor timebase. Have a look here for a comparison of different Arduino types vs. the DCF77 time reference.

Conclusion: if you need precise timing either get an Arduino with crystal or go for an RTC. I can highly recommend DS3231 / DS3232 RTCs since these usually achieve 2 ppm accuracy out of the box.

Udo Klein
  • 141
  • 3