Библиотека времени Arduino и библиотеки RTC

Я использую RTClib.h и TimeLib.h с Uno.

В течение нескольких дней я пытался разобраться в различных доступных библиотеках RTC и в том, как использовать их с библиотекой времени Arduino.

Вопрос 1.
Если я не хочу создавать новый объект now() каждый раз в цикле, как мне синхронизировать библиотеку времени с RTC каждые x секунд? Каждый раз, когда я пытаюсь использовать функцию RTClib сейчас.hour now.minute и т. Д. Это требует, чтобы я использовал DateTime now = RTC.now() для создания объекта now().

Есть ли эквивалентная функция в RTClib как setSyncProvider(RTC.get) в библиотеке DS1307RTC?

Существует ли эквивалент setSyncInterval(5000)

Вопрос 2.
Какой RTClib я должен вызвать? В примерах используется несколько вариантов:

<RTClib.h>

"RTClib" с использованием кавычек

<RTClib.h> с большой буквы L

а иногда еще и выкрикивает что-нибудь из этого:

RTC_DS1307 RTC

или RTC_DS1307 rtc

или RTC_DS3231 rtc

Вопрос 3
a. Являются ли tmElements_t tm частью библиотеки DS1307RTC?
б. Являются ли эти тм.Час tm.Минута от RTC?
c. Есть ли эквивалент в RTClib.h?

И, наконец, я опубликовал ниже некоторый код, просто чтобы показать свое использование:

#include "RTClib.h" 
#include <Wire.h>   
#include <TimeLib.h>

RTC_DS1307 RTC;

void setup() {
  
Serial.begin(9600);
Wire.begin();  //устанавливает I2C
RTC.begin();   // инициализирует I2C для RTC


if (! RTC.begin()) {
    Serial.println("Couldn't find RTC");
}
    
// Установите время RTC на 5:10:30 3 ноября 2020 года
      RTC.adjust(DateTime(2020,11,3,5,10,30));

// Установите библиотеку времени Arduino, отличную от времени RTC, чтобы увидеть,
setTime(9, 27, 05, 14, 07, 2015);
      
}


 void loop() {

/*
// Как мне синхронизировать библиотеку времени с RTC через x секунд?
  setSyncProvider(RTC.get); // Это находится в библиотеке DS1307RTC.h
  setSyncInterval(5000);   // Есть ли такие функции в RTClib?
*/

DateTime now = RTC.now();   // Извлекает время RTC в now().  Не синхронизируется с библиотекой времени
                            // Не хочу делать это каждый цикл.

//Вывести время RTC
Serial.println();
Serial.print("RTC now.hour        ");
Serial.println(now.hour());
Serial.print("RTC now.minute      ");
Serial.println(now.minute());
Serial.print("RTC now.second:     ");
Serial.println(now.second());
Serial.println();
Serial.println();


//Печать Arduino TimeLib Время
Serial.print("Time Lib Hour:       "); 
Serial.print(hour());  
Serial.println();
Serial.print("Time Lib Min:        "); 
Serial.print(minute());  
Serial.println();
Serial.print("Time Lib Sec:        "); 
Serial.print(second());  
Serial.println();
Serial.println();

delay(1000);
  
 }

Обновлено 5 ноября 2020 года

Мне кажется, я почти понимаю. Пожалуйста, дайте мне знать, делает ли этот код то, что я думаю, что он делает, в частности:

В настройках:
Установите RTC на 5:10:30.
Установите библиотеку времени на 9:27:05 с помощью функции setTime().
Установить библиотеку времени на время RTC с указанием даты и времени сейчас (вместо записи 9:27:05)?
Установите переменные библиотеки времени в значение RTC с помощью tm.Час = сейчас.Час и т.д.

В цикле:
Каждые 5 секунд обновляйте hour(), minute() second() с указанием времени RTC.
Каждый цикл обновляет tm.час с часом () и т.д.

Я знаю, что это все еще неправильно, так как серийные отпечатки показывают тм.Час, тм.Минута, чередуя каждую петлю, как показано внизу.

#include "RTClib.h"
#include <Wire.h>
#include <TimeLib.h>

RTC_DS1307 RTC;

time_t time_provider()
{
    return RTC.now().unixtime();
}

tmElements_t tm;  //часть библиотеки времени

void setup() {
    //setSyncProvider(time_provider);
    Serial.begin(9600);
    Wire.begin();  //настраивает I2C
    RTC.begin();   //инициализирует I2C для RTC

    if (! RTC.begin()) {
        Serial.println("Couldn't find RTC");
    }

    // Установите время RTC на 5:10:30 3 ноября 2020 года
    RTC.adjust(DateTime(2020,11,3,5,10,30));

    //Установите библиотеку времени Arduino, отличную от времени RTC 9:27:05
    setTime(9, 27, 05, 14, 07, 2015);

    //Установка библиотеки времени на время RTC
    DateTime now = RTC.now();
    tm.Hour = now.hour();
    tm.Minute = now.minute();
    tm.Second = now.second();
}


void loop() {
    setSyncProvider(RTC.now);
    setSyncInterval(5000);

    // Библиотека времени время обновляется до RTC каждые 5 секунд
    tm.Hour = hour();
    tm.Minute = minute();
    tm.Second = second();

    Serial.print("tm.Hour:    ");
    Serial.print(tm.Hour);
    Serial.println();
    Serial.print("tm.Minute:  ");
    Serial.print(tm.Minute);
    Serial.println();
    Serial.print("tm.Seconds: ");
    Serial.print(tm.Second);
    Serial.println();
    Serial.println();
    delay(1000);
}

Серийные отпечатки:

tm.Hour:    5
tm.Minute:  34
tm.Seconds: 56

tm.Hour:    18
tm.Minute:  0
tm.Seconds: 0

tm.Hour:    5
tm.Minute:  34
tm.Seconds: 56

tm.Hour:    18
tm.Minute:  0
tm.Seconds: 0

tm.Hour:    5
tm.Minute:  34
tm.Seconds: 56

tm.Hour:    18
tm.Minute:  0
tm.Seconds: 0

, 👍1


2 ответа


2

Есть ли эквивалентная функция в RTClib как setSyncProvider(RTC.get) в библиотеке DS1307RTC?

Существует ли эквивалент setSyncInterval(5000)

Это функции TimeLib. Нет никакого "эквивалента", поскольку вы используете TimeLib.

Первый просто ожидает указатель на функцию, которая возвращает time_t. Что входит в эту функцию, зависит только от вас.

Какой RTClib я должен вызвать? В примерах используется несколько вариантов:

Заглавные буквы должны совпадать с именем заголовочного файла. Windows это не волнует, и OS X обычно это не волнует, но может быть настроено на это. Linux действительно заботится о нем и нуждается в том, чтобы он соответствовал. Если вы хотите, чтобы ваш код был переносимым, вы должны сохранить заглавные буквы такими же, как в файле.

а иногда еще и выкрикивает что-нибудь из этого:

Вам нужно создать объект, соответствующий вашему физическому RTC.

a. Являются ли tmElements_t tm частью библиотеки DS1307RTC?

Нет. Они являются частью TimeLib.

b. Являются ли эти тм.Час tm.Минута от RTC?

Это все, что присваивается им вызываемой функцией. Это всего лишь переменные. Они могут содержать все, что угодно.

c. Есть ли эквивалент в RTClib.h ?

Нет. Но тогда вам это и не нужно, если вы используете TimeLib.

Итак: вам нужно

  • Создайте функцию, которая получает время из RTC через любую библиотеку, которую вы хотите использовать (например, RTClib), и вычисляет количество секунд с 00:00:00 01/01/1970, которое затем возвращается как time_t.
  • Передайте это в setSyncProvider() TimeLib setSyncProvider()
  • Установите частоту синхронизации с помощью setSyncInterval().
,

-Я много читал об этих библиотеках и до сих пор в замешательстве. Спасибо за вашу помощь. Пара последующих действий: 1. Получает ли функция now.hour() время от RTC? 2. Получает ли hour() время из библиотеки времени? 3. Устанавливает ли setSyncProvider() значение hour() для RTC?, @RickH

сейчас - это время из RTC в момент, когда вы назначаете объект сейчас. .hour() - это просто час, содержащийся внутри этого объекта. hour () - это время из библиотеки TimeLib, да. setSyncProvider() ничего не отправляет в RTC, он регулярно получает время из RTC и обновляет TimeLib текущим временем., @Majenko

@Edgar Bonet - Использование PIN прерывания выглядит очень красиво и чисто. Если вывод 2 используется на Arduino для прерывания, к какому выводу подключается вывод 2 на RTC? Я предполагаю, что это в дополнение к контактам SCL и SDA (?)., @RickH

"setSyncProvider() ничего не отправляет в RTC, он регулярно получает время от RTC и обновляет TimeLib с текущим временем". Да, значит, если hour() - это время из библиотеки TimeLib, то setSyncProvider() делает hour() равным часу RTC?, @RickH

Все немного сложнее, чем это. TimeLib использует millis() для отслеживания времени. Он регулярно обновляет свое внутреннее представление о том, сколько времени зависит от setSyncInterval (). когда вы запрашиваете hour (), если прошло больше времени с тех пор, как он в последний раз получал реальное время, указанное вами в setSyncInterval (), он перейдет и получит время из RTC. В противном случае он просто скажет вам, что он * думает * о времени в соответствии со своими собственными внутренними расчетами., @Majenko

Я обновил свой пост с помощью предоставленной помощи. Почти все это поняли., @RickH

Почему выводятся альтернативные значения для tm.hour и т.д.? Смотрите нижнюю часть обновленного вопроса. Спасибо, @RickH

Потому что вы постоянно меняете поставщика синхронизации и интервал. Вы устанавливаете их один раз и только один раз в программе настройки, и больше никогда., @Majenko

Спасибо, что сработало. Глядя на мой обновленный код, чтобы убедиться, что я не обманываю себя, я получаю результаты tm.Значения библиотеки времени Hour tm.Minute. tm.Second, которые обновляются из RTC каждые 5 секунд? И разве я не создаю объект в каждом цикле?, @RickH

Да, это выглядит правильно. Хотя вам вообще не нужна структура tmElements_t, поскольку все, с чем вы имеете дело, - это простые числа. tmElements_t - это просто удобный способ объединить их все вместе, если вы хотите передать его другой функции. Просто Serial.print(hour());, @Majenko

спасибо за всю вашу помощь. Я опубликую окончательный код в качестве ответа для всех, кому еще нужно это изучить., @RickH


3

Позвольте мне сначала рассказать немного об этих библиотеках.

Библиотека времени использует millis() для хронометража. Поскольку это может быть подвержено значительному отклонению, это обеспечивает возможность периодической синхронизации с внешним поставщиком времени. Отсюда и функции setSyncProvider() и setSyncInterval().

RTClib предназначен для взаимодействия с RTC. Он не обеспечивает хронометраж сам по себе: вы получаете текущее время, запрашивая RTC через его метод now().

Эти две библиотеки могут прекрасно дополнять друг друга, так как RTClib можно использовать в качестве поставщика времени для библиотеки времени:

// Укажите время RTC в библиотеке времени.
time_t time_provider() {
    return RTC.now().unixtime();
}

void setup() {
    // ...
    setSyncProvider(time_provider);
}

Если я не хочу создавать новый объект now() [...]

На самом деле он называется объектом DateTime.

Есть ли эквивалент [для tmElements_t] в RTClib

Да, класс DateTime. Обратите внимание, что, в отличие от структуры tmElements_t, поля данных DateTime не являются общедоступными, и для их получения необходимо использовать средства доступа: year(), month(), day()...

Альтернативный метод хронометража

Поскольку вы используете Arduino Uno, существует третий метод хронометража, который вы, возможно, захотите рассмотреть. Вместо того, чтобы запрашивать RTC на каждой итерации цикла (RTClib) или интерполировать показания RTC с millis() (Библиотека времени), вы можете направить 1 Гц вывод RTC на вывод прерывания и отсчет секунд в ISR. Код синхронизации avr-libc предназначен для обеспечения хронометража таким образом. Все это сводится к следующему:

// Инициализируйте системное время из RTC.
set_system_time(RTC.now().secondstime());

// Синхронизируйте время, используя выходной сигнал RTC частотой 1 Гц.
pinMode(pin1Hz, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pin1Hz), system_tick, FALLING);

Для получения более подробной информации см. Пример прерывания скетча 1Hz.ino предоставляется с помощью RTClib.


Правка 1: Ответ на комментарий

к какому выводу [вывод прерывания Arduino] подключается к RTC?

Это зависит от RTC, который вы используете. Я предполагаю, что это DS1307, как следует из кода в вашем вопросе. Взгляните на техническое описание RTC. На странице 6 есть таблица под названием “Описание PIN”. Из этой таблицы:

pin-код: 7
название: SQW/OUT
функция: Драйвер прямоугольной волны/выходного сигнала. При включении бита SQWE, установленного на 1, вывод SQW/OUT выводит одну из четырех прямоугольных частот (1 Гц, 4 кГц, 8 кГц, 32 кГц). Вывод SQW/OUT имеет открытый сток и требует внешнего подтягивающего резистора. SQW / OUT работает с любым Применяется VCC или VBAT. Напряжение вытягивания может составлять до 5,5 В независимо от напряжения на VCC. Если этот контакт не используется, его можно оставить плавающим.

Если вы используете модуль RTC, вам нужно будет выяснить, где этот вывод находится на разъеме модуля.

В любом случае вам придется включить прямоугольный выходной сигнал частотой 1 Гц с

RTC.writeSqwPinMode(DS1307_SquareWave1HZ);

Обновление 2: Комментарий к обновлению вопроса:

// Установите время RTC на 5:10:30 3 ноября 2020 года
RTC.adjust(DateTime(2020,11,3,5,10,30));

Правильно.

// Установите библиотеку времени Arduino, отличную от времени RTC 9:27:05
setTime(9, 27, 05, 14, 07, 2015);

Правильно. Дата - 2015-07-14.

// Установка библиотеки времени на время RTC
DateTime now = RTC.now();
tm.Hour = now.hour();
tm.Minute = now.minute();
tm.Second = now.second();

Нет. Это лишь частичная инициализация переменной tm. Это никак не влияет на представление библиотеки Времени о текущем времени. Обратите внимание, что поля даты tm на данный момент не были инициализированы и вполне могут быть недействительными (например, месяц 23, день 125).

setSyncProvider(RTC.now);

Это неверно и должно было сгенерировать предупреждение компилятора. setSyncProvider() ожидает функцию, которая возвращает текущее время в виде Время Unix (простое целое число типа time_t). Вы предоставляете функцию, которая возвращает текущее время в разбитом виде (год, месяц ...) с типом DateTime. Библиотека времени этого не поймет и может выдать мусор, например, 18:00:00.

Время, возвращаемое RTC.now(), может быть преобразовано во время Unix с помощью метода unixtime(). Вот почему я дал вам time_provider() функция.

Кроме того, вы не должны вызывать setSyncProvider() и setSyncInterval() на каждой итерации цикла. Сделайте это раз и навсегда в настройка().

// Библиотека времени время обновляется до RTC каждые 5 секунд
tm.Hour = hour();
tm.Minute = minute();
tm.Second = second();

Опять же, это всего лишь обновление переменной tm. Это никак не влияет на то, что библиотека времени считает текущим временем.

,