DS3231 с Arduino Nano для точной синхронизации
Мне нужно синхронизировать две отдельные платы, работающие с Arduino nano. Необходимо активировать одно реле с помощью Arduino-1 через 45 минут, а другое реле с помощью Arduino-2 через 45,36 секунды. Отсчет времени начинается с момента получения сигнала от внешнего переключателя, общего для обоих.
со ссылкой на этот вопрос и по совету edgar-bonet Я использовал один RTC с температурной компенсацией для внешней синхронизации Arduino (DS3231). Я использую его вывод 32 кГц от чипа для подсчета тактов, а в Arduino использую прерывание для подсчета тактов.
Программа показана ниже.
float _sec = 1;
float secTime = _sec * 1000UL; // second->millis
uint32_t coilTime = 5 * 1000UL; // second->millis
volatile uint32_t count = 0;
/*
* 32768 ticks in 1 sec
* 0.032768 tick in 1 us
*/
float _multiplier = 0.032768; // 32768 Hz
uint32_t _delay = secTime * _multiplier * 1000UL ;
volatile bool onFlag = false;
ISR(INT1_vect, ISR_NOBLOCK) {
count = count + 1UL;
if (_delay == count) {
PORTC |= (1 << 5);
onFlag = true;
EIMSK = 0;
}
}
ISR(INT0_vect) {
/* INTERRUPT re-initalization */
EIMSK = 0;
EICRA = B00001100; // INT0 - clear ; INT1 - set
EIFR = 0;
PORTB ^= (1 << 0) | (1 << 1); // setting Green off and red on
count = 0;
EIMSK = B00000010; // INT0 - inactive ; INT1 - active
}
void setup() {
Serial.begin(115200);
/* PIN initialization */
DDRB |= (1 << 0) | (1 << 1); // red led and green led
pinMode(3, INPUT_PULLUP); // timer unit
pinMode(2, INPUT); // interrupt unit
DDRC |= (1 << 3) | (1 << 4) | (1 << 5); // relay, OUT_1, OUT_2
/* LEDs state update */
PORTB &= ~(1 << 1); // red off.
PORTB |= (1 << 0); // green on.
PORTC &= ~(1 << 3); // A3-off
/* INTERRUPT initalization */
EICRA = B00000011; // INT0 - set ; INT1 - not set
EIMSK = B00000001; // INT0 - active ; INT1 - inactive
EIFR = 0;
}
void loop() {
if (onFlag) {
PORTB |= (1 << 0); // setting green on
delay(500);
PORTC ^= (1 << 5);
// PORTB ^= (1 << 0) | (1 << 1);
PORTB ^= (1 << 1); // setting red off
while (true) {
TCCR2B = 0;
count = 0;
PORTB ^= (1 << 0);
delay(500);
}
}
}
при запуске программы Результат Ожидаю точность до микросекунд но
для ввод -> Измеренное значение 1 сек -> 1.000387792 2 сек -> 2.000784208 50 сек -> 50.020926833 250 сек -> 250.104557792
Как сделать часы более точными. В техническом описании сказано, что точность часов составляет +- 2 ppm.
datasheet-ds3231
@Lawliet, 👍0
Обсуждение1 ответ
Возможно, это неправильный ответ на ваш вопрос. Вместо того, чтобы сказать вам как повысить точность, я покажу вам, как ее измерить. проблема в том, что код, который вы разместили, делает слишком много вещей, и это не ясно, как он может измерять точность часов. Итак, вместо этого я предлагаем вам попробовать код ниже:
- подключите кнопку между контактом 2 и GND
- подключите сигнал 32768 Гц к контакту 5
- смотрите, как мигает встроенный светодиод
const uint8_t input_pin = 5; // 32768 Гц по цифре 5 = T1
const uint8_t clear_pin = 2; // кнопка сброса таймера
void setup() {
pinMode(input_pin, INPUT_PULLUP);
pinMode(clear_pin, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
// Настройте Таймер 1 как счетчик.
TCCR1A = 0;
TCCR1B = _BV(CS11) | _BV(CS12); // подсчет падающих фронтов T1
}
void loop() {
// Отображение бита 14 счетчика на встроенном светодиоде.
if (TCNT1 & (1 << 14)) {
digitalWrite(LED_BUILTIN, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
// Очистить счетчик при нажатии кнопки.
if (digitalRead(clear_pin) == LOW) {
TCNT1 = 0;
}
}
Этот скетч использует Таймер/счетчик 1 в качестве счетчика, чтобы подсчитайте падающие фронты сигнала 32768 Гц. Бит 14 счетчика затем должен переключаться с частотой 1 Гц. Этот бит выводится на встроенный светодиод для позвольте вам проверить его частоту. Вы можете использовать кнопку для сброса фаза моргания.
Если у вас есть очень точные часы, вы можете использовать кнопку чтобы синхронизировать моргание с тиками этих часов, а затем посмотреть, как много времени требуется, чтобы стать заметно не в фазе. Вы также можете синхронизировать мигания двух ардуино и посмотреть, как долго они остаются синхронизированными. Если вы есть область, вы могли бы измерить крошечное смещение между краями два светодиода Arduino, а затем посмотрите, как это смещение меняется со временем.
- Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg
- Точность синхронизации Arduino nano
- Проблема с использованием Arduino Mega Timer2 с прерыванием PinChange
- Разница между «time_t» и «DateTime»
- Создание таймера с использованием часов реального времени с указанием времени начала и остановки
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- 4-битный счетчик вверх и вниз
- Включить и отключить отдельные прерывания
Я не совсем уверен, что понял ваш вариант использования, потому что, по крайней мере, для начальной синхронизации между двумя устройствами существует соединение.
изменчивый счетчик uint32_t. . . count = 0;
остерегайтесь асинхронных неатомарных операций с многобайтовыми переменными на 8-битном микроконтроллере. Для высокоточных вычислений число с плавающей запятой может иметь ограничения: «float _multiplier = 0,032768»; 2ppm — это примерно одна секунда каждые пять дней., @6v6gtНе могли бы вы посоветовать мне, какие переменные следует использовать? В начальном случае у меня есть общий переключатель, подключенный к моим устройствам, и я использую его как сигнал прерывания., @Lawliet
1.0000000/(1.000387792/32768) = 32755.29776
.... что составляет 32755 тиков за 1 секунду, @jsotola«через 45 минут и другое реле с использованием Arduino-2 через 45,36 секунды» не объявляет необходимую точность ... например, 45,36 может быть где-то между 44,355000 ... и 45,364999 ..., @jsotola
@jsotola, если меня устраивает такая дисперсия, какие изменения нужно сделать?, @Lawliet
Вместо того, чтобы использовать числа с плавающей запятой для указания временного интервала, почему бы не указать, скажем, 1 секунду как 32768? На первый взгляд, потеря тиков (по сравнению с вашей ссылкой) кажется линейной и составляет около 13 в секунду. Возможно, попробуйте отключить таймер 0, чтобы запретить его возможные конфликтующие прерывания, и тогда вам придется найти другое решение для delay()., @6v6gt
1. Я не могу понять, что ваш код пытается сделать, и я не вижу, как этот код относится к части вопроса «ввод -> измеренное значение». Я предлагаю вам последовать совету в [Как создать минимальный воспроизводимый пример](https://stackoverflow.com/help/minimal-reproducible-example). 2. У вас очень надуманный способ записи
_delay = 32768
. Пожалуйста, обратите внимание, что «0,032768» не может быть представлено как число с плавающей запятой и будет округлено до ближайшего представимого числа, которое равно 0,0327679999172687530517578125., @Edgar Bonet