Какую точность можно ожидать при синхронизации 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
-> Время, затраченное на буферизацию/обработку Arduinoz
-> Время, необходимое для передачи 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 = "";
}
}
@Storca, 👍3
Обсуждение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).
Спасибо за ответ :); синхронизация времени GPS и UTC также может быть хорошим вариантом для точной синхронизации времени., @Storca
Время передачи, конечно, не будет незначительным. Чтобы оценить его, можно использовать расчет задержки приема-передачи, который (примерно) соответствует тому, как протокол 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 можно повторить несколько раз. В этом случае вы можете рассчитать стандартное отклонение, которое покажет вам, насколько велик «джиттер» ваших часов.
Именно так я и поступлю в своем проекте. Думаю, это дешевый способ получить точность до миллисекунды :), @Storca
- Что является более быстрой альтернативой parseInt()?
- Библиотека Parola и часы DS3231
- Как установить время ожидания, например Serial.setTimeout() для Serial.read()?
- Последовательный буфер остается пустым, как только он становится пустым один раз.
- Используйте DS3231 с батареей и VCC одновременно
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
- В чем разница между Serial.write и Serial.print? И когда они используются?
Какую Arduino вы используете?, @Majenko
Я использую Arduino Uno или Nano с ATMega238P, @Storca
Как это "быстрее, чем ожидалось"? Что вы отправляете и как вы измеряете/вычисляете, насколько быстро это должно быть?, @Majenko
Какое отношение имеет точная скорость передачи данных к синхронизации времени? У вас есть клиент NTP, вы же не собираетесь использовать сам последовательный порт в качестве источника времени, не так ли? Пожалуйста, уточните свой вопрос и четко сформулируйте, чего вы пытаетесь добиться., @Edgar Bonet
@EdgarBonet Я думаю, проблема в том, что у ПК есть время X, и он передает его в X. Arduino заканчивает прием этого указанного времени в Y - разница между X и Y является временем, необходимым для выполнения передачи через последовательный порт. Если вы знаете YX, то вы можете добавить (YX) к X, чтобы получить время завершения передачи., @Majenko
@Majenko да, именно это я и пытаюсь спросить, извините, если не совсем ясно выразился., @Storca
@Majenko Я сделал простую эхо-программу, которая считывает данные с последовательного порта и возвращает сообщение со скоростью 300 бод. Итак, согласно Википедии, для передачи одного бита со скоростью 300 бод требуется ~3 мс. Если я передам 22 символа, то время отправки и чтения данных составит 2*22*8*3 = 1056 мс или ~1 с (это то, что я получил, протестировав это, так что я ошибся в своем вопросе, извините за это). В моем случае мне нужно передать 35 символов; 7,4 микросекунды на бит при скорости 57600 бод; таким образом, время, необходимое для отправки, составит 7,4 * 35 * 8 = 2072, то есть смещение составит 2 мс. Извините, что задаю вопрос, на который я мог бы ответить сам..., @Storca
8N1 — это 10 бит, а не 8 бит. Один стартовый бит, восемь бит данных и один стоповый бит. И затем могут быть пробелы между каждым байтом. И затем, конечно, есть буферизация в Arduino, чтобы добавить в смесь., @Majenko
Добавьте объяснение "быстрее, чем ожидалось" к вашему вопросу. Вопрос должен быть сам по себе, без необходимости искать комментарии для недостающей информации. *"Извините, что задал вопрос, на который я смог ответить сам"* Это не проблема, просто напишите ответ на свой вопрос, чтобы помочь другим, у кого есть такой же вопрос. На самом деле, это поощряется на Stack Exchange., @per1234
@Majenko Если я правильно понимаю, мне нужно добавить еще 2 бита к каждому байту, чтобы получить представление о времени передачи, это составит 7,4 * 35 * (8+2) ~ 2,6 мс смещения, @Storca
@per1234 «быстрее, чем ожидалось» было моей ошибкой, я полагал, что последовательный порт передавал данные быстрее, чем должен, но я ошибался. Кстати, спасибо всем, кто пытался мне помочь :), @Storca