Какую точность можно ожидать при синхронизации DS3231 с последовательным портом ПК?

Суть здесь в том, чтобы синхронизировать модуль DS3231 (на Arduino) через последовательный порт со временем NTP на компьютере.

Проблема здесь в том, что я хотел бы знать, сколько времени занимает последовательная передача и передача по I2C, потому что если ПК отправляет время в момент времени t1 и передает его в Arduino, Arduino декодирует его и отправляет в DS3231, время t1 принимается в момент времени t2, больший, чем t1.

PC (t1) => Serial(t1+x) => Arduino(t1+x+y) => I2C(t1+x+y+z) => DS3231(t2=t1+x+y+z)
  • t1 -> время NTP, записанное ПК
  • x -> Время, затраченное на последовательную передачу
  • y -> Время, затраченное на буферизацию/обработку Arduino
  • z -> Время, необходимое для передачи I2C на частоте 100 кГц
  • t2 -> Время получения сообщения DS3231

Можно ли пренебречь точностью в миллисекунду?

Я нашел таблицу в Википедии, которая отображает время на бит на скорость передачи. Я планирую использовать скорость передачи 57600.

Я проверил смещение, используя простую программу эха, доступную здесь на скорости 300 бод:

String buff="";

void setup() {
  // put your setup code here, to run once:
Serial.begin(300);
}

void loop() {
  if(Serial.available())
  {
    while(Serial.available())
    {
      buff += char(Serial.read());
    }
    Serial.print(buff);
    buff = "";
  }
}

, 👍3


2 ответа


Лучший ответ:

2

Я поддерживаю общую идею ответа Дмитрия Григорьева: ваш лучший вариант измерять время прохождения туда и обратно и использовать половину этого времени в качестве оценки время в одну сторону. Иначе у вас будет слишком много неизвестных. Для например, вы не знаете, сколько времени требуется вашей ОС для обработки исходящего сообщение и отправьте его через USB на USB/последовательный мост внутри Arduino. В качестве оптимизации я бы отправил информацию о времени и синхронизирующий строб как два отдельных сообщения, причем последнее является один байт. Таким образом, задержка строба синхронизации ( имеет значение только задержка) сведена к минимуму.

Задержка последовательной связи

Я провел небольшое исследование, чтобы попытаться определить это. На скорости 57600 бит/с, теоретическое время на бит составляет около 17,4 мкс, как указано в Статья Википедии, на которую вы ссылаетесь. На практике фактическое время может быть округляется в большую или меньшую сторону в зависимости от возможностей UART и тактовой частоты скорость. Вы не указали, какой Arduino вы используете. В следующем, Я предположу, что Arduino на базе AVR работает на частоте 16 МГц, что предположительно, наиболее распространенный.

UART в AVR ограничивает время передачи бита кратным 8 тактов ЦП, т.е. 0,5 мкс при работе на частоте 16 МГц. Таким образом, максимально близкое к идеальному время составляет 17,5 мкс. Однако библиотека ядра Arduino имеет жестко запрограммированную совместимость исключение, которое в этом очень специфическом случае устанавливает бит длительность на 17 мкс вместо этого. Поскольку вы, по-видимому, настраиваете порт /8N1, который является портом по умолчанию, тогда время на байт будет равно 170 мкс (1 стартовый бит, 8 бит данных и 1 стоповый бит).

На самом деле, при передаче одного байта время передачи составляет немного меньше. UART может сообщить, что байт получен, как как только это будет сделано, взяв требуемые три образца стоп-бита, что происходит немного после середины этого стоп-бита. Теоретическое время, необходимое для передачи одного байта, составляет около 9,56 длительности одного бита, или около 162,56 мкс при 57600/8N1.

Я провел простой тест обратной связи с закороченными TX и RX моего Uno. вместе. Я использовал таймер для измерения времени выполнения следующего кода:

Serial.write('.');
while (!Serial.available()) continue;

Результат составил 182,38 мкс или около 10,73 бит длительности. A Часть этого времени уходит на выполнение Serial.write() и Serial.available(). Чтобы приблизиться к чистой аппаратной задержке, Я также замерил время выполнения низкоуровневой версии двух строк выше:

UDR0 = '.';
while (!bit_is_set(UCSR0A, RXC0)) continue;

Это должно быть запущено с отключенными прерываниями. Время выполнения теперь от 164,19 до 164,81 мкс, т.е. от 9,66 до 9,69 бит длительности.

Альтернативный подход

В заключение я бы рекомендовал вам рассмотреть возможность покупки GPS-модуля с выход 1PPS. Этот 1PPS — это логический сигнал 1 Гц с нарастающим края плотно прилегают к началу секунд UTC. Обычно вы получаете точность в десятки наносекунд. Поскольку это всего лишь логика сигнал, который вы можете легко сравнить с выходным сигналом 1 Гц вашего RTC модуль, вы избавляетесь от всех проблем с задержками, которые возникают у компьютеров (ваш клиент NTP) или каналы передачи данных (USB, последовательный порт, I2C).

,

2

Время передачи, конечно, не будет незначительным. Чтобы оценить его, можно использовать расчет задержки приема-передачи, который (примерно) соответствует тому, как протокол NTP реализован в первую очередь.

  • в момент времени ПК T1, ПК отправляет текущее время T1 в Arduino через UART
  • Arduino устанавливает время T1 в DS3231 через I2C
  • Arduino считывает время T2 с DS3231 через I2C
  • Arduino отправляет время T2 на ПК через UART. Это происходит в момент времени T3 с точки зрения ПК.

Теперь ПК может оценить задержку полукругового движения R как (T3-T2)/2. Смотрите следующую диаграмму, которая обозначает текущее время от POW ПК и RTC

        |--UART--|--I2C--|--------|--I2C--|--UART--|
PC      T1              T1+R     T2+R           T3=T2+2R
DS3231  -                T1       T2              T2+R

Далее, в момент времени T4, ПК отправляет значение (T4+R) через UART. Это приведет к тому, что DS3231 будет установлен на (T4+R), что произойдет ровно через время R после T4, так что теперь оба тактовых генератора будут установлены на одно и то же значение.

Оценку R можно повторить несколько раз. В этом случае вы можете рассчитать стандартное отклонение, которое покажет вам, насколько велик «джиттер» ваших часов.

,