0

How precisely can an Arduino nano be timed? The project I am working on needs two Arduino nano to work synchronously. Arduino one have to activate a relay after 2700 sec and Arduino two have to activate a second relay after 2700.360 sec (360 milli seconds after )

With the code given below the required accuracy is not achieved.

volatile uint32_t ovfCount = 0UL;
volatile uint32_t currentTime = 0UL;
volatile unsigned long time_prev = 0UL;
volatile unsigned long dT = 0UL;

unsigned long delayTime = 2700UL;     //Seconds
unsigned long coilActivateTime = 5UL;  // seconds

volatile unsigned long _waitTime = delayTime * 1000UL + 360UL;
uint32_t _burnTime = coilActivateTime * 1000UL;

volatile bool coilOn_flag = false;

ISR(INT0_vect) {
  
  EIMSK = 0b00000000;
  
  TCCR1B = B00011100;
  PORTB ^= (1<<0);
  ovfCount = 0;
  TIFR2 = 0;
  TCNT2 = 0;
  
}

ISR(TIMER2_OVF_vect) {
  ovfCount++;
}

ISR(TIMER1_OVF_vect) {
  //pass
}

ISR(TIMER1_COMPA_vect) {
  //pass
}

ISR(TIMER1_COMPB_vect) {
  uint8_t tcnt2 = TCNT2;
  uint32_t ovf_count = ovfCount;

  if (bit_is_set(TIFR2, TOV2) && tcnt2 < 128) {
    ovf_count++;
  }

  uint32_t totalCount = ovf_count << 8 | tcnt2;  // raw count
  // uint32_t currentTime = totalCount * 0.004;     // milli second
  currentTime = totalCount * 4UL/1000UL;  // milli second

  if (currentTime >= _waitTime) {
    PORTC ^= (1 << 5);   // relay Switch
    TCCR1A = B00000010;
    TIMSK1 = B00000101;
    PORTB |= (1<<1);
    if (coilOn_flag) {
      TCCR1B = 0;  
      PORTB ^= (1 << 1) | (1<<0); 
    }
    coilOn_flag = true;
    _waitTime = _burnTime;
    ovfCount = 0;
    TCNT2 = 0;
  }
}

void setup() {
  Serial.begin(115200);
  /*setting the pin directions*/
  DDRB |= (1 << 1) | (1 << 0); // gL, rL
  DDRC |= (1 << 5);  // relay
  DDRD &= B11111011; // interrupt- interrupt

  /* INITIAL STATE SETTING FOR THE PINS */
  PORTB &= B11111100; // rL, gL
  PORTC &= B11011111; // relay


  /* 8Bit Timer*/
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = B00000011;
  TCCR2B = B00001100;
  OCR2A = 250;
  TCNT2 = 0;
  TIFR2 = 0;
  TIMSK2 = B00000001;

  /* 16 bit timer */
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A = B10000010;
  // TCCR1B = B00011100;
  TCCR1B = 0;
  ICR1 = 62461;
  OCR1A = 6206;
  OCR1B = 624;
  TCNT1 = 0;
  TIFR1 = 0;
  TIMSK1 = B00000111;

  /* External INTERRUPT */
  EICRA = 0b00000010;
  EIFR = 0;
  EIMSK = 0b00000001;

  PORTB ^= (1<<0);
}

void loop() {
  
}

How to correct the code.?

4
  • 1
    you said nothing about the required precision of the two values ... you also did not say if there is anything wrong with the code
    – jsotola
    Jan 9, 2023 at 15:57
  • The internal clock of an Arduino is not really good for timing long durations with high precision (due to manufacturing differences and clock drift with temperature). For that a RTC (Real Time Clock) would be needed. Though: If you only need precision in the time difference between the two relay activations, then you could trigger the second Arduino from the first to start the timing there. Millisecond range is normally easily reached with Arduinos
    – chrisl
    Jan 9, 2023 at 16:24
  • why can't one Arduino control both relays?
    – Juraj
    Jan 9, 2023 at 18:34
  • both are going to be inside 2 different systems. I do start the clock on both at the same time using a common interrupt signal.
    – Lawliet
    Jan 10, 2023 at 6:09

1 Answer 1

2

The Arduino Nano is nowhere accurate enough for your application, and this has nothing to do with your code: it is a hardware limitation. 360 extra milliseconds after 2,700 seconds is a difference of only 133 ppm (parts per million). The Arduino Nano is clocked off a ceramic resonator, and these time sources carry a typical error of the order of 1,000 ppm. The best thing the code can do is count the clock cycles with perfect accuracy, which makes the software timing as good as the underlying hardware, but never better.

Some options you may try:

  1. The one that seems most obvious is to have the first Arduino somehow send a trigger signal to the second one when it activates the first relay. Or have the second Arduino sense the state of that relay. Then, all the second Arduino has to do is wait for 360 ms, which it can easily do with reasonable accuracy.

  2. If there is no way the Arduinos can communicate, then you could try to add external time sources to the Arduinos. Some RTC modules can output a 32,768 Hz signal that could be accurate enough for your needs. Look for a temperature-compensated RTC, as those are more accurate.

  3. If you cannot add extra hardware, you could try to calibrate the clocks of your Arduinos in order to compensate for their relative drift. Keep in mind though that the drift rate is temperature-dependent, and wanders randomly even at constant temperature. First read the article Arduino clock frequency accuracy, by Joris_VR, to get an idea of the accuracy you could expect from such calibration.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.