Edit 1: Answering a comment
Edit 2: Commenting on the update to the question:
// Set the RTC Time to 5:10:30 Nov 3 2020 RTC.adjust(DateTime(2020,11,3,5,10,30));
Correct.
// Set Arduino Time Library different than RTC time 9:27:05 setTime(9, 27, 05, 14, 07, 2015);
Correct. Date is 2015年07月14日.
// Setting Time Library to RTC time DateTime now = RTC.now(); tm.Hour = now.hour(); tm.Minute = now.minute(); tm.Second = now.second();
No. This is only partially initializing the tm
variable. It has no
effect on the idea the Time library has of the current time. Note that
the date fields of tm
have not been initialized at this point, and
could well be invalid (like month 23, day 125).
setSyncProvider(RTC.now);
This is incorrect, and should have generated a compiler warning.
setSyncProvider()
expects a function that returns the current time as
Unix time (a simple integer, of type time_t
). You are providing a
function that returns the current time in broken down form (year,
month...), with type DateTime
. The Time library will not understand
that and may yield garbage like, say, 18:00:00.
The time returned by RTC.now()
can be converted to Unix time with the
unixtime()
method. That's why I gave you the time_provider()
function.
Also, you are not supposed to call setSyncProvider()
and
setSyncInterval()
on every loop iteration. Do it once and for all in
setup()
.
// Time Library time updates to RTC every 5 seconds tm.Hour = hour(); tm.Minute = minute(); tm.Second = second();
Again, this is only updating the variable tm
. It has no effect on what
the Time library believes is the current time.
Edit: Answering a comment
Edit 1: Answering a comment
Edit 2: Commenting on the update to the question:
// Set the RTC Time to 5:10:30 Nov 3 2020 RTC.adjust(DateTime(2020,11,3,5,10,30));
Correct.
// Set Arduino Time Library different than RTC time 9:27:05 setTime(9, 27, 05, 14, 07, 2015);
Correct. Date is 2015年07月14日.
// Setting Time Library to RTC time DateTime now = RTC.now(); tm.Hour = now.hour(); tm.Minute = now.minute(); tm.Second = now.second();
No. This is only partially initializing the tm
variable. It has no
effect on the idea the Time library has of the current time. Note that
the date fields of tm
have not been initialized at this point, and
could well be invalid (like month 23, day 125).
setSyncProvider(RTC.now);
This is incorrect, and should have generated a compiler warning.
setSyncProvider()
expects a function that returns the current time as
Unix time (a simple integer, of type time_t
). You are providing a
function that returns the current time in broken down form (year,
month...), with type DateTime
. The Time library will not understand
that and may yield garbage like, say, 18:00:00.
The time returned by RTC.now()
can be converted to Unix time with the
unixtime()
method. That's why I gave you the time_provider()
function.
Also, you are not supposed to call setSyncProvider()
and
setSyncInterval()
on every loop iteration. Do it once and for all in
setup()
.
// Time Library time updates to RTC every 5 seconds tm.Hour = hour(); tm.Minute = minute(); tm.Second = second();
Again, this is only updating the variable tm
. It has no effect on what
the Time library believes is the current time.
Edit: Answering a comment
which pin does [the Arduino interrupt pin] connect to on the RTC?
It depends on the RTC you are using. I will assume it's a DS1307, as implied by the code in your question. Take a look at the datasheet of the RTC. On page 6, there is a table titled "Pin description". From this table:
pin: 7
name: SQW/OUT
function: Square Wave/Output Driver. When enabled, the SQWE bit set to 1, the SQW/OUT pin outputs one of four square-wave frequencies (1Hz, 4kHz, 8kHz, 32kHz). The SQW/OUT pin is open drain and requires an external pullup resistor. SQW/OUT operates with either VCC or VBAT applied. The pullup voltage can be up to 5.5V regardless of the voltage on VCC. If not used, this pin can be left floating.
If you are using an RTC module, you will have to figure out where this pin is exposed on the module's connector.
In any case, you will have to enable the 1 Hz square wave output with
RTC.writeSqwPinMode(DS1307_SquareWave1HZ);
Edit: Answering a comment
which pin does [the Arduino interrupt pin] connect to on the RTC?
It depends on the RTC you are using. I will assume it's a DS1307, as implied by the code in your question. Take a look at the datasheet of the RTC. On page 6, there is a table titled "Pin description". From this table:
pin: 7
name: SQW/OUT
function: Square Wave/Output Driver. When enabled, the SQWE bit set to 1, the SQW/OUT pin outputs one of four square-wave frequencies (1Hz, 4kHz, 8kHz, 32kHz). The SQW/OUT pin is open drain and requires an external pullup resistor. SQW/OUT operates with either VCC or VBAT applied. The pullup voltage can be up to 5.5V regardless of the voltage on VCC. If not used, this pin can be left floating.
If you are using an RTC module, you will have to figure out where this pin is exposed on the module's connector.
In any case, you will have to enable the 1 Hz square wave output with
RTC.writeSqwPinMode(DS1307_SquareWave1HZ);
Let me first give some background about these libraries.
The Time library uses millis()
for timekeeping. Since this can be
subject to significant drift, it provides a means to periodically sync
to an external time provider. Hence the functions setSyncProvider()
and setSyncInterval()
.
RTClib is meant to interface an RTC. It does not provide timekeeping on
its own: you get the current time by querying an RTC through it's
now()
method.
These two libraries can nicely complement each other, as RTClib can be used as a time provider for the Time library:
// Provide the RTC time to the Time library.
time_t time_provider() {
return RTC.now().unixtime();
}
void setup() {
// ...
setSyncProvider(time_provider);
}
If I do not want to create a new now() object [...]
It is actually called a DateTime
object.
Is there an equivalent [to
tmElements_t
] in the RTClib
Yes, the DateTime
class. Note that, unlike the
tmElements_t
structure, the data fields of DateTime
are not public,
and you have to use accessors to get them: year()
, month()
,
day()
...
Alternative timekeeping method
Since you are using an Arduino Uno, there is a third method of
timekeeping you may want to consider. Instead of querying the RTC on
every loop iteration (RTClib) or interpolating the RTC readings with
millis()
(Time library), you may route a 1 Hz output of the RTC
to an interrupt pin, and count the seconds in the ISR. The avr-libc
timing code is designed to provide timekeeping in this
fashion. It all boils down to:
// Initialize the system time from the RTC.
set_system_time(RTC.now().secondstime());
// Keep the time in sync using the 1 Hz output of the RTC.
pinMode(pin1Hz, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pin1Hz), system_tick, FALLING);
For more details, see the example sketch interrupts1Hz.ino provided with RTClib.