DS3231 с Arduino Nano для точной синхронизации

Мне нужно синхронизировать две отдельные платы, работающие с Arduino nano. Необходимо активировать одно реле с помощью Arduino-1 через 45 минут, а другое реле с помощью Arduino-2 через 45,36 секунды. Отсчет времени начинается с момента получения сигнала от внешнего переключателя, общего для обоих.

со ссылкой на этот вопрос и по совету edgar-bonet Я использовал один RTC с температурной компенсацией для внешней синхронизации Arduino (DS3231). Я использую его вывод 32 кГц от чипа для подсчета тактов, а в Arduino использую прерывание для подсчета тактов.

Программа показана ниже.



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);
    }
  }
}

при запуске программы Результат Ожидаю точность до микросекунд но

для ввод -> Измеренное значение 1 сек -> 1.000387792 2 сек -> 2.000784208 50 сек -> 50.020926833 250 сек -> 250.104557792

Как сделать часы более точными. В техническом описании сказано, что точность часов составляет +- 2 ppm.

datasheet-ds3231

, 👍0

Обсуждение

Я не совсем уверен, что понял ваш вариант использования, потому что, по крайней мере, для начальной синхронизации между двумя устройствами существует соединение. изменчивый счетчик uint32_t. . . count = 0; остерегайтесь асинхронных неатомарных операций с многобайтовыми переменными на 8-битном микроконтроллере. Для высокоточных вычислений число с плавающей запятой может иметь ограничения: «float _multiplier = 0,032768»; 2ppm — это примерно одна секунда каждые пять дней., @6v6gt

Не могли бы вы посоветовать мне, какие переменные следует использовать? В начальном случае у меня есть общий переключатель, подключенный к моим устройствам, и я использую его как сигнал прерывания., @Lawliet

1.0000000/(1.000387792/32768) = 32755.29776.... что составляет 32755 тиков за 1 секунду, @jsotola

«через 45 минут и другое реле с использованием Arduino-2 через 45,36 секунды» не объявляет необходимую точность ... например, 45,36 может быть где-то между 44,355000 ... и 45,364999 ..., @jsotola

@jsotola, если меня устраивает такая дисперсия, какие изменения нужно сделать?, @Lawliet

Вместо того, чтобы использовать числа с плавающей запятой для указания временного интервала, почему бы не указать, скажем, 1 секунду как 32768? На первый взгляд, потеря тиков (по сравнению с вашей ссылкой) кажется линейной и составляет около 13 в секунду. Возможно, попробуйте отключить таймер 0, чтобы запретить его возможные конфликтующие прерывания, и тогда вам придется найти другое решение для delay()., @6v6gt

1. Я не могу понять, что ваш код пытается сделать, и я не вижу, как этот код относится к части вопроса «ввод -> измеренное значение». Я предлагаю вам последовать совету в [Как создать минимальный воспроизводимый пример](https://stackoverflow.com/help/minimal-reproducible-example). 2. У вас очень надуманный способ записи _delay = 32768. Пожалуйста, обратите внимание, что «0,032768» не может быть представлено как число с плавающей запятой и будет округлено до ближайшего представимого числа, которое равно 0,0327679999172687530517578125., @Edgar Bonet


1 ответ


1

Возможно, это неправильный ответ на ваш вопрос. Вместо того, чтобы сказать вам как повысить точность, я покажу вам, как ее измерить. проблема в том, что код, который вы разместили, делает слишком много вещей, и это не ясно, как он может измерять точность часов. Итак, вместо этого я предлагаем вам попробовать код ниже:

  • подключите кнопку между контактом 2 и GND
  • подключите сигнал 32768 Гц к контакту 5
  • смотрите, как мигает встроенный светодиод
const uint8_t input_pin = 5;  // 32768 Гц по цифре 5 = T1
const uint8_t clear_pin = 2;  // кнопка сброса таймера

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

    // Настройте Таймер 1 как счетчик.
    TCCR1A = 0;
    TCCR1B = _BV(CS11) | _BV(CS12);  // подсчет падающих фронтов T1
}

void loop() {
    // Отображение бита 14 счетчика на встроенном светодиоде.
    if (TCNT1 & (1 << 14)) {
        digitalWrite(LED_BUILTIN, HIGH);
    } else {
        digitalWrite(LED_BUILTIN, LOW);
    }

    // Очистить счетчик при нажатии кнопки.
    if (digitalRead(clear_pin) == LOW) {
        TCNT1 = 0;
    }
}

Этот скетч использует Таймер/счетчик 1 в качестве счетчика, чтобы подсчитайте падающие фронты сигнала 32768 Гц. Бит 14 счетчика затем должен переключаться с частотой 1 Гц. Этот бит выводится на встроенный светодиод для позвольте вам проверить его частоту. Вы можете использовать кнопку для сброса фаза моргания.

Если у вас есть очень точные часы, вы можете использовать кнопку чтобы синхронизировать моргание с тиками этих часов, а затем посмотреть, как много времени требуется, чтобы стать заметно не в фазе. Вы также можете синхронизировать мигания двух ардуино и посмотреть, как долго они остаются синхронизированными. Если вы есть область, вы могли бы измерить крошечное смещение между краями два светодиода Arduino, а затем посмотрите, как это смещение меняется со временем.

,