0

I need to synchronize two separate circuit boards working with Arduino Nano. The need is to activate one relay using Arduino-1 after 45 minutes, and another relay using Arduino-2 after 45.36 seconds. The time starts from the point of reception of input from an external switch common to both.

With ref to This question, and from the advice of edgar-bonet I have used one temperature-compensated RTC for timing the Arduinos externally (DS3231). I am using it's 32kHz pin from the chip for counting the ticks and in the Arduino using the interrupt to count the ticks.

The program is shown below.

float _sec = 1;

float secTime =  _sec * 1000UL; // second->millis
uint32_t coilTime = 5 * 1000UL; // second->millis

volatile uint32_t count = 0;
/*
 * 32768 ticks in 1 sec
 * 0.032768 tick in 1 us
 */

float _multiplier = 0.032768; // 32768 Hz

uint32_t _delay = secTime * _multiplier * 1000UL ;

volatile bool onFlag = false;

ISR(INT1_vect, ISR_NOBLOCK) {
  count = count + 1UL;
  if (_delay == count) {
    PORTC |= (1 << 5);
    onFlag = true;
    EIMSK = 0;
  }
}

ISR(INT0_vect) {
  /* INTERRUPT re-initalization */
  EIMSK = 0;
  EICRA = B00001100; // INT0 - clear ; INT1 -  set
  EIFR  = 0;
  PORTB ^=  (1 << 0) | (1 << 1); // setting Green off and red on
  count = 0;
  EIMSK = B00000010; // INT0 - inactive ; INT1 - active
} 

void setup() {
  Serial.begin(115200);

  /* PIN initialization */
  DDRB |= (1 << 0) | (1 << 1); // red led and green led

  pinMode(3, INPUT_PULLUP); // timer unit
  pinMode(2, INPUT); // interrupt unit

  DDRC |= (1 << 3) | (1 << 4) | (1 << 5); // relay, OUT_1, OUT_2

  /* LEDs state update */
  PORTB &=  ~(1 << 1); // red off.
  PORTB |= (1 << 0); // green on.

  PORTC &= ~(1 << 3); // A3-off

  /* INTERRUPT initalization */
  EICRA = B00000011; // INT0 - set ; INT1 - not set
  EIMSK = B00000001; // INT0 - active ; INT1 - inactive
  EIFR  = 0;
}

void loop() {

  if (onFlag) {

    PORTB |= (1 << 0); // setting green on

    delay(500);
    PORTC ^= (1 << 5);
    //    PORTB ^= (1 << 0) | (1 << 1);
    PORTB ^= (1 << 1); // setting red off
    while (true) {
      TCCR2B = 0;
      count = 0;
      PORTB ^= (1 << 0);
      delay(500);
    }
  }
}

When running the program, the result I am expecting is the accuracy of microseconds but for:

input -> Measured value 1 sec -> 1.000387792 2 sec -> 2.000784208 50 sec -> 50.020926833 250 sec -> 250.104557792

How do I make the clock more precise? In the data sheet it is said that the clock is accurate to +- 2ppm.

datasheet-ds3231

7
  • I'm not completely sure I understand your use case because, at least for the initial synchronisation, there is a connection between the 2 devices. volatile uint32_t count . . . count = 0; beware of asynchronous non-atomic operations on multi-byte variables on an 8bit MCU. For high precision calculations, float may have limitations: float _multiplier = 0.032768; 2ppm is about one second every five days.
    – 6v6gt
    Commented Jan 26, 2023 at 12:24
  • Can you please advise me on the correct variables to be used? In the initial case, I have a common switch connected to my devices and I use that as the interrupt signal.
    – Lawliet
    Commented Jan 26, 2023 at 15:36
  • 1.0000000 / (1.000387792 / 32768 ) = 32755.29776 .... that makes 32755 ticks in 1 second
    – jsotola
    Commented Jan 26, 2023 at 17:04
  • 1
    after 45 min and another relay using Arduino-2 after 45.36 seconds does not declare the necessary precision ... for example, 45.36 can be anywhere between 44.355000... and 45.364999...
    – jsotola
    Commented Jan 26, 2023 at 17:17
  • 1
    Instead of using floats to specify the time interval, why not specify say 1 second as 32768? At a quick glance, the loss of ticks (in comparison to your reference) seems linear at around 13 per second. Maybe try switching off timer 0 to inhibit its possibly clashing interrupts and then you'll have to find another solution for delay().
    – 6v6gt
    Commented Jan 27, 2023 at 6:58

2 Answers 2

1

This may not be a proper answer to your question. Instead of telling you how to improve the accuracy, I will show you how to measure it. The issue is that the code you posted is doing too much stuff, and it is not clear how it could be measuring the clock accuracy. So, instead I suggest you try the code below:

  • connect a push button between pin 2 and GND
  • connect the 32768 Hz signal to pin 5
  • watch the built-in LED blink
const uint8_t input_pin = 5;  // 32768 Hz on digital 5 = T1
const uint8_t clear_pin = 2;  // button to clear timer

void setup() {
    pinMode(input_pin, INPUT_PULLUP);
    pinMode(clear_pin, INPUT_PULLUP);
    pinMode(LED_BUILTIN, OUTPUT);

    // Configure Timer 1 as a counter.
    TCCR1A = 0;
    TCCR1B = _BV(CS11) | _BV(CS12);  // count falling edges of T1
}

void loop() {
    // Display bit 14 of the counter on the builtin LED.
    if (TCNT1 & (1 << 14)) {
        digitalWrite(LED_BUILTIN, HIGH);
    } else {
        digitalWrite(LED_BUILTIN, LOW);
    }

    // Clear the counter on button press.
    if (digitalRead(clear_pin) == LOW) {
        TCNT1 = 0;
    }
}

What this sketch does is use Timer/counter 1 as a counter in order to count the falling edges of the 32768 Hz signal. Bit 14 of the counter should then toggle at 1 Hz. This bit is output on the built-in LED to let you check its frequency. You can use the push button to reset the phase of the blinks.

If you have a very accurate clock at hand, you can use the push button to synchronize the blinks with the ticks of that clock, and then see how long it takes to get visibly out of phase. You can also synchronise the blinks of two Arduinos and see for how long they stay in sync. If you have a scope, you could measure a tiny offset between the edges of the two Arduino's LEDs, then see how this offset evolves with time.

0

It looks like you have a drift problem (?) Some of the DS3231 RTC modules on the market have significantly more drift than the datasheet spec and the only way to know if you have one of those is to tune the aging register and test it. In a stable temperature environment you can usually get a -SN to a millisecond per day of clock drift.

This can be done with an Uno and a cheap GPS module: https://thecavepearlproject.org/2024/10/22/setting-accurate-rtc-time-with-a-gps-the-ds3231-aging-offset-to-reduce-drift/

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.