Синхронизация внутренних часов двух ардуин
- Войдите на сайт для отправки комментариев
Пнд, 24/02/2014 - 03:19
Имеются 2 дуины, соединенные через I2C/Serial(научился и так, и так настраивать) и два датчика на них. Нужно сделать так, чтобы их внутренние часы были максимально(с точностью до десятков-сотен микросекунд) синхронизированы. На какждом из них стоит датчик и нужно, чтобы датчики включались/выключались одновременно.
Возможно ли это сделать на голой ардуине? А с использованием сторонних деталей и каких?
Читал о часах реального времени - с их помощью удастся реализовать такую точную синхронизацию?
Вы определитесь что вам нужно. Вам нужны часы (типа московское время...) или же отсчеты времени для синхронной работы (и все равно который час)?
Если второе то в чем проблема настроить одну ардуину на то, чтобы она периодически второй давала команду сброса часов? А между сбросами время считать по mills()?
Если вы озвучите задачу возможно вам смогут лучше подсказать. Не факт что вам вообще часы нужны в каком то виде. Может достаточно импульсов синхронизации
микросхема ds1307 на которую вы ссылаетесь имеет дискретность отсчета одна секунда.
Я бы попробовал протестировать такую связку: 2 дуины связаны между собой цифоровым пином (или может двумя!?), RTC подлючены только к одной (к master). Когда наступает нужное время работы с датчиком, главная выставляет на цифровом пине HIGH и начинает работу со своим датчиком, вторая дуина (без RTC, slave) в прерывании ловит сигнал мастера и тоже начинает работу со своим датчиком. Похоже нужна обратная связь по второму цифровому пину, когда слэйв поймал сигнал мастера надо отправить мастеру ответит и мастер должен снять свой сигнал (т.е. мастер тоже ловит сигнал в прерывании от слэйва). В общем логику общения по пинам надо проработать, сам не пойму пока как.
Так не получиться сделать?
axill, да, именно второе нужно: синхронизация между собой, а не относительно GMT.
А не подскажете, какой командой сбрасывать часы? Если честно, не очень понял, как мне поможет сброс времени.
Я вот попробовал сделать как: одну дуину подключаю к батарейке типа "крона", а из её разьема 5V бросаю провод на вторую дуину и запитываю ей через Vin, ну и GND, само-собой, тоже общий. Получается, что как только стартует одна дуина - стартует и вторая и часы у них тикают синхронно.
Переписла код так, чтобы незаолго до момента, когда мне нужно сделать замер, я отправляю значение переменной "a"(в которую перед самой отправкой зашиваю значение micros()+1000 микросекунд время передачи данных + 50 микросекунд про запас), вторая дуина это значение принимает и сравнивает значение своих часов с этим до тех пор, пока оно не сравняется и тогда делает замер данных с датчика. Первая дуина поступает аналогично.
Синхронность отличная, но только в первые 3-5 минут, дальше разброс становится недопустимо большим и растет... Вычитал в Сети, что это вызвано малейшими перепадами напряжения, температуры и прочим.
Я бы попробовал протестировать такую связку: 2 дуины связаны между собой цифоровым пином (или может двумя!?), RTC подлючены только к одной (к master). Когда наступает нужное время работы с датчиком, главная выставляет на цифровом пине HIGH и начинает работу со своим датчиком, вторая дуина (без RTC, slave) в прерывании ловит сигнал мастера и тоже начинает работу со своим датчиком. Похоже нужна обратная связь по второму цифровому пину, когда слэйв поймал сигнал мастера надо отправить мастеру ответит и мастер должен снять свой сигнал (т.е. мастер тоже ловит сигнал в прерывании от слэйва). В общем логику общения по пинам надо проработать, сам не пойму пока как.
Так не получиться сделать?
Идея хорошая, тем более, что некоторые RTC работают по I2C и данные с них могут снимать хоть 100 дуинок сразу. Но если axill прав и она имеет дискретность в одну секунду - вряд ли это нам поможет. Разве что, сделать расписание замеров(каждая 15-я секунда, каждая 30-я и т.д.)
Ну я просто подумал, что датчики нужно опрашивать по реальному времени, а не по внутреннему. А если нужно просто синхронизовать действия 2 дуин, то тогда RTC ваыкидываем, а связь по пинам оставляем.
А не подскажете, какой командой сбрасывать часы? Если честно, не очень понял, как мне поможет сброс времени.
вам RTC вообще не нужны, я имел в виду другое. Например значение millis() записываем в переменную в момент когда получили команду синхронизации причеи на обоих ардуинах и дальше чтобы понять сколько времени прошло от момента синхронизации из текузего значения millis() вычитаем значение нашей переменной тем саммы получим кол-во мсек прошедших с момента синхронизации
но мне видится вариант с пинами вам может даже больше подойти. Если просто нужно выполнить два действия одновременно сделайте как вам выше порекомендовали - одна ардуина на специальном пине делает импульс (например один за другим выставляем HIGH и тут же LOW), этот пин подключен у другой ардуины к пинам с прерываниями настроеными на raise.
А не подскажете, какой командой сбрасывать часы? Если честно, не очень понял, как мне поможет сброс времени.
вам RTC вообще не нужны, я имел в виду другое. Например значение millis() записываем в переменную в момент когда получили команду синхронизации причеи на обоих ардуинах и дальше чтобы понять сколько времени прошло от момента синхронизации из текузего значения millis() вычитаем значение нашей переменной тем саммы получим кол-во мсек прошедших с момента синхронизации
но мне видится вариант с пинами вам может даже больше подойти. Если просто нужно выполнить два действия одновременно сделайте как вам выше порекомендовали - одна ардуина на специальном пине делает импульс (например один за другим выставляем HIGH и тут же LOW), этот пин подключен у другой ардуины к пинам с прерываниями настроеными на raise.
Спасибо за советы! Боюсь, что через прерывания и придется делать.
Вот что нашел в гитхабе -
TimeServer:
#include <Wire.h> String timeOffsetStr; // Variable to hold time char dataFromClient[10]; // Variable to hold data from client volatile unsigned long clientTime; // Variable to hold timestamp of client void setup() { timeOffsetStr.reserve(10); // Reserve 10 bytes for unsigned long time Wire.begin(0x50); // Setup I2C slave address as 0x50 Wire.onRequest(requestEvent); // Register event for requested data Wire.onReceive(receiveEvent); // Register event for incomming data } void loop() { // Do nothing } void receiveEvent(int bytes){ int index = 0; // index of char array while(Wire.available()) // while more bytes avail { char c = Wire.read(); // receive a byte as character dataFromClient[index++] = c; // store byte in char array } clientTime = atol(dataFromClient); // convert char array to unsigned long } void requestEvent() { timeOffsetStr = String(micros() - clientTime); // convert timestamp to string volatile int timeLength = timeOffsetStr.length(); // find out how many digits are in the current time // If not 10 digits (max digit length for unsigned long), add leading zeros // This is to keep the time of I2C transfers consistent between subsequent read/writes if(timeLength == 1){ timeOffsetStr = "000000000" + timeOffsetStr; } else if(timeLength == 2){ timeOffsetStr = "00000000" + timeOffsetStr; } else if(timeLength == 3){ timeOffsetStr = "0000000" + timeOffsetStr; } else if(timeLength == 4){ timeOffsetStr = "000000" + timeOffsetStr; } else if(timeLength == 5){ timeOffsetStr = "00000" + timeOffsetStr; } else if(timeLength == 6){ timeOffsetStr = "0000" + timeOffsetStr; } else if(timeLength == 7){ timeOffsetStr = "000" + timeOffsetStr; } else if(timeLength == 8){ timeOffsetStr = "00" + timeOffsetStr; } else if(timeLength == 9){ timeOffsetStr = "0" + timeOffsetStr; } Wire.print(timeOffsetStr); // respond with padded timestamp }Timer:
#include <Wire.h> char dataFromTimeServer[10]; // char array to hold I2C data from TimeServer unsigned long timeOffset = 0; // unsigned long to hold time from TimeServer unsigned long currentSyncedTime = 0; // Last button press's time (synced) unsigned long timeOfLastSync = 0; // Timestap of last sync const int buttonPin = 10; // Pin that button is on const int syncStatusOutPin = 11; // Pin that sync status is output on const int syncStatusInPin = 22; // Pin that sync status is collected on void setup() { Serial.begin(9600); digitalWrite(buttonPin,HIGH); // enable pull up resitor attachInterrupt(buttonPin, buttonPress, FALLING); // register interrup on FALLING state pinMode(syncStatusOutPin, OUTPUT); // set it up as an output digitalWrite(syncStatusOutPin,LOW); // default state digitalWrite(syncStatusInPin, LOW); // setup pull-down pinMode(syncStatusInPin, INPUT); // set it up as an input syncTime(); // Sync time with TimeServer } void loop() { if(currentSyncedTime!=0){ Serial.println(currentSyncedTime); currentSyncedTime=0; } // Sync every 5 seconds if Time server is avail if((millis() - timeOfLastSync) > 5000 && digitalRead(syncStatusInPin) == LOW){ syncTime(); } } // Run when falling void buttonPress(){ // Record timestamp in reference frame of TimeServer currentSyncedTime = timeOffset + micros(); } // Method to read timestamp from central TimeServer over I2C void syncTime(){ while(digitalRead(syncStatusInPin) != LOW) { } // wait for server to become free digitalWrite(syncStatusOutPin,HIGH); // let others know server is busy //Serial.print("SYNCING..."); Wire.begin(); // Initialize I2c Wire.beginTransmission(0x50); // begin communication with TimeServer String timeStr = String(micros()); // convert timestamp to string volatile int timeLength = timeStr.length(); // find out how many digits are in the current time // If not 10 digits (max digit length for unsigned long), add leading zeros // This is to keep the time of I2C transfers consistent between subsequent read/writes if(timeLength == 1){ timeStr = "000000000" + timeStr; } else if(timeLength == 2){ timeStr = "00000000" + timeStr; } else if(timeLength == 3){ timeStr = "0000000" + timeStr; } else if(timeLength == 4){ timeStr = "000000" + timeStr; } else if(timeLength == 5){ timeStr = "00000" + timeStr; } else if(timeLength == 6){ timeStr = "0000" + timeStr; } else if(timeLength == 7){ timeStr = "000" + timeStr; } else if(timeLength == 8){ timeStr = "00" + timeStr; } else if(timeLength == 9){ timeStr = "0" + timeStr; } Wire.print(timeStr); // Send padded timestamp to TimeServer Wire.endTransmission(); // End comm. Wire.requestFrom(0x50, 10); // Request 10 bytes (timestamp) from TimeServer int index = 0; // index of char array while(Wire.available()) // while more bytes avail { char c = Wire.read(); // receive a byte as character dataFromTimeServer[index++] = c; // store byte in char array } digitalWrite(syncStatusOutPin,LOW); // let others know server is free timeOffset = atol(dataFromTimeServer); // convert char array to unsigned long timeOfLastSync = millis(); // update time of last sync }Попробую и так, для очистки совести, вдруг оно будет работать так, как мне нужно.