Использование функции 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. Можно поменять местами скетчи, т.е. первый прошить во второй и наоборот. И по результатам достоверно убедиться, рассинхронизация - это аппаратная проблема (разница в частоте кварцев) или программная (ошибка в логике работы или алгоритме).
А подать с одной платы на другую "синхроимпульс" ?
Первая, а возможно и последняя, причина такой погрешности это ваш метод измерений.
void setup() { Serial.begin(9600); uint32_t start_time = 0, stop_time = 0; digitalWrite(PIN_TX, 1); start_time = micros(); delay(10000); digitalWrite(PIN_TX, 0); stop_time = micros(); Serial.println(stop_time-start_time); }void setup() { Serial.begin(9600); uint32_t start_time = 0, stop_time = 0; while(!digitalRead(PIN_RX)); start_time = micros(); while(digitalRead(PIN_RX)); stop_time = micros(); Serial.println(stop_time-start_time); }Вторая это то, что на Nano 3.0 стоит не кварцевый резонатор, а керамический.
Первая, а возможно и последняя, причина такой погрешности это ваш метод измерений.
Согласен код был не идеален, написал другой на основе вашего.
Вторая это то, что на Nano 3.0 стоит не кварцевый резонатор, а керамический.
Проблема была, действительно, в этом. Заменил керамический резонатор на кварцевый (+ два конденсатора по 20 пФ для надёжного старта), теперь разница между двумя платами стала существенно меьше. Если раньше показания функции micros() уже спустя 1 секунду (то есть миллион значений микроса) отличались на 800-900 единиц (порядка 1 миллисекунды), то с кварцевым резонатором значение стало равно всего 2 единицам, то есть 2 микросекундам. В 500 раз лучше :))
Вывод: если необходимо работать с временными интервалами менее 1 мс, или необходимо сделать часы на Arduino Nano без использования внешнего RTC, необходимо заменить керамический резонатор на кварцевый.