Использование функции micros()
- Войдите на сайт для отправки комментариев
Доброго времени суток!
Стоит задача определить момент наступления двух разных событий на двух разных платах Arduino Nano 3.0, и затем понять произошли эти события в одно и тоже время или же в разное. Надо сказать, что события периодически повторяются и значения периода можно удалить без влияния на результат измерения. Короче говоря, нужно сделать прибор, который определяет подключены две коробки с платами Arduino к одной фазе 220В или это разные фазы.
Идея была следующая: сначала определить момент наступления события (момент перехода через нуль) на одной плате с помощью функции micros(), далее передать это значение по радиоканалу RF24 на другую плату. На другой плате определить момент наступления события и вычесть из него принятое значение, получив таким образом значение, из которого можно вычесть лишнее число периодов. И получить либо нуль - если фазы совпадают, либо не нуль - и определить по полученному числу сдвиг фазы. Да, ещё необходимо в начале вычислить разницу между часами на разных платах, ведь функция micros() отсчитывает время от момента включения. Для этого используется функция синхронизации: по проводу от одной платы Arduino к другой передаётся импульс и фиксируется время на каждой плате в момент передачи импульса, после чего эта дельта используется в формуле при вычислении. Используется именно проводное соединение для синхронизации, так как задержка при передачи по цифровому радиоканалу RF24 может достигать 5-10 мс, при этом период регистрируемого сигнала 20 мс.
Так вот, при использовании функции синхронизации было замечено, что время дельты постоянно различается.
После чего был проведён следующий эксперимент: производится фиксация времени на первой плате, отправка импульса (перепада 0-1), приём имульса и фиксация времени на второй плате, далее эксперимент повторяется через 1 секунду. Разница между временами на первой и второй платах растёт с каждым измерением на 800 мкс. То есть получается, что через 1000 секунд разница времени между платами составит 0,8 секунды. Неужели, это нормально??
Скетч первой платы:
... unsigned long Time_Fix = 0; int cnt = 1; void loop(void) { // Начальная задержка delay(2000); while (true) { digitalWrite(PIN_TEST_TX, HIGH); Time_Fix = micros(); delay(10); digitalWrite(PIN_TEST_TX, LOW); Serial.print(cnt); Serial.print(" / Time = "); Serial.println(Time_Fix); delay(900); cnt++; } }
Результат для первой платы:
1 / Time = 2907648
2 / Time = 3818200
3 / Time = 4728756
4 / Time = 5639316
5 / Time = 6549872
6 / Time = 7460424
7 / Time = 8370980
8 / Time = 9281532
9 / Time = 10192100
10 / Time = 11102712
Скетч второй платы:
... unsigned long Time_Fix = 0; int cnt = 1; void loop(void) { // Начальная задержка delay(500); while (true) { while (digitalRead(PIN_TEST_RX) == LOW); Time_Fix = micros(); Serial.print(cnt); Serial.print(" / Time = "); Serial.println(Time_Fix); delay(100); cnt++; } }
Результат для второй платы:
1 / Time = 1654700
2 / Time = 2564392
3 / Time = 3474084
4 / Time = 4383784
5 / Time = 5293472
6 / Time = 6203160
7 / Time = 7112852
8 / Time = 8022548
9 / Time = 8932248
10 / Time = 9842000
Разница времени через 10 секунд:
(9842000 - 1654700) - (11102712 - 2907648) = 8195064 - 8187300 = 7764 мс,
то есть ~ 800 мс за 1 секунду
1. Первая мысль: раз от одной платы можно бросить провод ко второй плате, не проще ли все измерения проводить на одном устройстве?
2. Синхронизироваться можно и по каналу передачи, имеющему задержку. Естественно, передача должна осуществляться поочередно в обоих направлениях с целью вычисления времени задержки.
3. Часы устройств работают от кварцевых генераторов, а последние имеют погрешность. Нужно смотреть по даташтиам, 0.08% - это много или мало. Для часового уварца безусловно много, а для обычного, может, и нормально.
4. Можно поменять местами скетчи, т.е. первый прошить во второй и наоборот. И по результатам достоверно убедиться, рассинхронизация - это аппаратная проблема (разница в частоте кварцев) или программная (ошибка в логике работы или алгоритме).
А подать с одной платы на другую "синхроимпульс" ?
Первая, а возможно и последняя, причина такой погрешности это ваш метод измерений.
Вторая это то, что на Nano 3.0 стоит не кварцевый резонатор, а керамический.
Первая, а возможно и последняя, причина такой погрешности это ваш метод измерений.
Согласен код был не идеален, написал другой на основе вашего.
Вторая это то, что на Nano 3.0 стоит не кварцевый резонатор, а керамический.
Проблема была, действительно, в этом. Заменил керамический резонатор на кварцевый (+ два конденсатора по 20 пФ для надёжного старта), теперь разница между двумя платами стала существенно меьше. Если раньше показания функции micros() уже спустя 1 секунду (то есть миллион значений микроса) отличались на 800-900 единиц (порядка 1 миллисекунды), то с кварцевым резонатором значение стало равно всего 2 единицам, то есть 2 микросекундам. В 500 раз лучше :))
Вывод: если необходимо работать с временными интервалами менее 1 мс, или необходимо сделать часы на Arduino Nano без использования внешнего RTC, необходимо заменить керамический резонатор на кварцевый.