Folks,
I’m working on a project/sketch that uses a RTC (DS3231) to keep time. I’ve never used a RTC before, or any time related functions – except delay, as far as I know. In the sketch, I’d like to specific certain times for a LED to light (the LED is just a place holder for a relay which will be added later). During online research I found that most folks suggest using the Unix based time format for ease of use. I’d like to light the LED on each day of advent at 5pm (essentially the period between Thanksgiving and Christmas). My current code checks to see if the current time is in a one-minute window. For example: between 5:00pm and 5:01pm. I’m using a one-minute time frame so that Arduino doesn’t have to worry about hitting 5:00pm right on the button. If for some reason the timing of the read is off a little, I won’t miss the general time to light the LED – hopefully within a few seconds.
The issue I'm having is the LED comes on and stays on, and the serial monitor won't resume displaying the current time even after 61 seconds have elapsed.
I’m relatively new to programming and Ardunio so there is a steep learning curve for me.
Best,
Tony
#include <Wire.h> // include wire library
#include "DS3231.h" // include DS3231 library
RTClib RTC; // WHAT IS THIS STATEMENT?
int ledpin = 13; // set LED pin
int delaytime = 61000; // set delay time of 61 seconds
uint32_t alarmtimelower = 1605195600; // set lower "alarm" time in seconds
uint32_t alarmtimeupper = alarmtimelower + 60; // set upper "alarm" time by adding 60 seconds
void setup () {
Serial.begin(115200); // begin serial
Wire.begin(); // begin wire
pinMode(ledpin, OUTPUT); // set LED pin to output
}
void loop () {
DateTime now = RTC.now(); // IS DATETIME A VARIABLE? WHY DIDN'T WE HAVE TO DECLARE IT?
if (now.unixtime() > alarmtimelower && now.unixtime() < alarmtimeupper ) { // check to see if current time is in range
digitalWrite(ledpin,HIGH); // if in range, turn on LED
delay(delaytime); // keep LED on for 61 seconds
digitalWrite(ledpin, LOW); // turn LED off
}
Serial.print(now.year(), DEC); // send time to serial monitor for reference
Serial.print('/'); // etc.
Serial.print(now.month(), DEC); // etc.
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
Serial.print(" since midnight 1/1/1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L); // WHAT DOES THE "L" MEAN? LONG?
Serial.println("d");
}
This number won't fit in an int. It will fit in an unsigned int, if you like:
int delaytime = 61000; // set delay time of 61 seconds
I don't see why you need a delay() statement though, since you already bracket the 60 seconds by testing the start and end RTC time in your 'if' statement.
Example:
if (now.unixtime() > alarmtimelower && now.unixtime() < alarmtimeupper ) { // check to see if current time is in range
digitalWrite(ledpin,HIGH); // if in range, turn on LED
}
else {
digitalWrite(ledpin, LOW); // turn LED off
}
This is not perfectly elegant but it would give you something to start with.
I never thought of it like that. The current code will keep the LED HIGH for the duration in the IF statement. But, where would I turn the LED off?
Spoke too soon. I will review your suggestions. Thank you.
The code changes worked. Thank you. In this project there are some shift registers wired to trigger a relay which in turn will allow a higher voltage source to flow to a solenoid. When the solenoid is activated an arm is retracted which allows the little boxes to tilt forward, one each day, and drop it's contents. I was thinking of keeping the relay open for 1/4 second or maybe 1/2 - one second at the most. How would I go about incorporating something like this in my code? It's all been a challenge but I'm getting close to getting it done. The coding is the last part. And for me I think the hardest part.
Sure. Then I would code the action time stamps with state change detection, so that I know when the time becomes a certain value, not when it is a certain value. It's easy to follow a state change detection with a timed delay using millis(). To detect state changes, you have to maintain a variable that contains the last measured state.
Concretely, you would look at when the time exceeds your time stamp and also the state is set to "not detected yet". You immediately start a millis() timer that controls the relay, and set the state to "detected" (so it won't be triggered again the very next second). To re-arm the system, you would set a new time stamp some time in the future, and reset the state to "not detected yet" again.
By the way, you asked,
Serial.print(now.unixtime() / 86400L); // WHAT DOES THE "L" MEAN? LONG?
The answer is "yes". But it's redundant in this expression because now.unixtime() is an unsigned long, so the compiler must use unsigned long arithmetic to divide it by anything. It's only when the data type of an element of an expression is unspecified, that default int arithmetic is used to evaluate an expression.
@aarg Thank you. I've never coded a state machine before, although I have looked over the Blink Without Delay sketch once. I'll start there. Quick question, would I use Unix time to determine if it's time to turn on the relay, and use millis to manage how long the relay is on?
tperry724:
@anon57585045 Thank you. I've never coded a state machine before, although I have looked over the Blink Without Delay sketch once. I'll start there. Quick question, would I use Unix time to determine if it's time to turn on the relay, and use millis to manage how long the relay is on?
I suggested that because you might want to have the relay on for some time that is not an exact multiple of seconds (actually your example was like that). I suppose if the relay is on for minutes or longer, and seconds are a small enough unit, it would make more sense to use the same timer (in this case the RTC time) to trigger both "on" and "off" transitions.
This code is supposed to report that "int mynumber =5" is between 3 and 6. It reports that it's within all ranges for some reason. I cannot figure it out. It must be obvious. Please let me know what I'm doing wrong.
Best,
Tony
int mynumber = 5;
int delaytime = 1000;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
if (mynumber > 0 && mynumber <=3); {
Serial.println("You number is between 1 and 3.");
}
if (mynumber > 3 && mynumber <=6); {
Serial.println("You number is between 3 and 6.");
}
if (mynumber > 6 && mynumber <=9); {
Serial.println("Your number is between 6 and 9.");
}
Serial.println("Your number is out of range.");
delay(delaytime);
}