I have been working on a lamp that mimics the sunlight spectrum throughout the day. It is expected to stay on from 9am-5pm, stay off from 5pm to 9am the next day, and continue as such. I used the delay function to achieve this. Yesterday I turned on my lamp at 9am, so I expected it to turn on again at 9am today. However, it only turned on at 9.40am. I looked at certain possibilities like a watchdog timer and the millis function. However, I am not sure what is wrong with my code, so I will attach it below here. Nothing is wrong with the circuitry.
int redPin=7;
int bluePin=13;
int greenPin=3;
unsigned long dt=1800000;
unsigned long dt2=57600000;
void setup() {
// put your setup code here, to run once:
pinMode(redPin,OUTPUT);
pinMode(bluePin,OUTPUT);
pinMode(greenPin,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,13);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,16);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,20);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,24);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,27);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,30);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,33);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,37);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,34);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,31);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,26);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,23);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,19);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,15);
delay(dt);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,11);
delay(dt);
analogWrite(greenPin,165);
analogWrite(redPin,255);
analogWrite(bluePin,7);
delay(dt);
analogWrite(greenPin,0);
analogWrite(redPin,0);
analogWrite(bluePin,0);
delay(dt2);
}
Your code is not based on real time. And isn't able to give the satisfaction for output
So make it real time using functions or other tools so you can manage your satisfactory output
As already mentioned, an RTC is recommended as a time base.
My recommendation is to design a structured array that contains the switching time and the values for the leds.
This array can be maintained to easily add events.
A service will take care of this data structure and switch the leds accordingly.
precise timing can be achieved by using an external RTC - Real Time Clock
here is a tutorial about this
A improvment without external RTC
The chrystal or oscillator is working at 16 MHz but is not that precise and the frequency has a temperature-drift
If your arduino is - more or less - always working in the same temperature
if the temperature is constant the deviation is constant.
Then you could measure the deviation between real time and arduino-time and then do a correction once every hour
so the arduino-time comes closer to real time
let the arduino run for one or more days and then look at the deviation between realtime and arduino-time
For switching thins on/off it is useful to use minute of day or seconds of day
minute of day = hours * 60 + minutes
seconds of day = hours * 3600 + minutes * 60 + seconds
you obtain a single number that is easier to compare bigger smaller than
dealing with multiple if-conditions about hour , minute and second
Problem is that a Mega doesn't have a crystal oscillator. At least not for the MCU clock.
It has a ceramic resonator, which is not very accurate and drifts with temperature.
Perfectly ok for most tasks, just not very good for time keeping.
Experiment with the delays until it's close enough, or
Use a RTC, or
use an Arduino with a real crystal and/or NTP (internet time).
I have been working on a lamp, and basically I need it to turn on at 9am, turn off at 5pm, while the brightness of the lamp changes every half hour. So I need to use an analogWrite function. After using the delay function on Arduino, I figured it was very imprecise, which is why I'm going for the RTC. I have the DS1307 Module V03.
#include "Arduino.h"
#include "uRTCLib.h"
// uRTCLib rtc;
uRTCLib rtc(0x68);
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup() {
Serial.begin(9600);
delay(3000); // wait for console opening
URTCLIB_WIRE.begin();
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
rtc.set(50, 59, 23, 7, 13, 1, 22) ;
// rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
// set day of week (1=Sunday, 7=Saturday)
}
void loop() {
rtc.refresh();
Serial.print("Current Date & Time: ");
Serial.print(rtc.year());
Serial.print('/');
Serial.print(rtc.month());
Serial.print('/');
Serial.print(rtc.day());
Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek()-1]);
Serial.print(") ");
Serial.print(rtc.hour());
Serial.print(':');
Serial.print(rtc.minute());
Serial.print(':');
Serial.println(rtc.second());
delay(1000);
}
The sketch prints the current hour, minute and second. A simple if statement could test any or all of there values and take action if they matched what you were looking for
Your two topics on the same or similar subject have been merged.
Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.
Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.
Repeated duplicate posting could result in a temporary or permanent ban from the forum.
Could you take a few moments to Learn How To Use The Forum
It will help you get the best out of the forum in the future.
Here is a code-version that assigns the time-data to variables and then uses the variables instead of direct function-calls and demontrates the use of miniuteOfDay
#include "Arduino.h"
#include "uRTCLib.h"
// uRTCLib rtc;
uRTCLib rtc(0x68);
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int myYear;
int myMonth;
int myDay;
int myDayOfWeek;
int myHour;
int myMinute;
int mySecond;
int minuteOfDay;
// 23*3600+59*60+59 = 86399 which is a to big number for int
long secondsOfDay;
int MinOfDay_9OClock = 9 * 60;
void setup() {
Serial.begin(9600);
delay(3000); // wait for console opening
URTCLIB_WIRE.begin();
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
myYear = 22;
myMonth = 1;
myDay = 13;
myDayOfWeek = 7;
myHour = 23;
myMinute = 59;
mySecond = 50;
// using variables make comments obsolete
rtc.set(mySecond, myMinute, myHour, myDayOfWeek, myDay, myMonth, myYear) ;
//rtc.set(50, 59, 23, 7, 13, 1, 22) ;
// rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
// set day of week (1=Sunday, 7=Saturday)
}
void loop() {
rtc.refresh();
myYear = rtc.year();
myMonth = rtc.month();
myDay = rtc.day();
myHour = rtc.hour();
myMinute = rtc.minute();
mySecond = rtc.second();
minuteOfDay = myHour * 60 + myMinute;
secondsOfDay = myHour * 3600 + myMinute * 60 + mySecond;
Serial.print("Current Date & Time: ");
Serial.print(myYear);
Serial.print('/');
Serial.print(myMonth);
Serial.print('/');
Serial.print(myDay);
Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
Serial.print(") ");
Serial.print(myHour);
Serial.print(':');
Serial.print(myMinute);
Serial.print(':');
Serial.println();
Serial.print("minuteOfDay:");
Serial.print(minuteOfDay);
Serial.print(" secondsOfDay:");
Serial.println(secondsOfDay);
if (minuteOfDay < MinOfDay_9OClock) {
Serial.println("it is before 9 o' clock");
}
else {
Serial.println("it is past 9 o' clock");
}
delay(1000);
}
You should consequently divide your code into functional parts where each part does
one thing
in the sense of lines of code that build a senseful unit like
set RTC-Time, print time, etc.
So here is a code-version that uses this principle consequently
This is the code-structure overview
and this is the whole code well organised in functions.
Additionally this code-version uses non-blocking timing with an easy to use function called TimePeriodIsOver()
/*structure (= function-call hierachry) of the code
* setup()
* - calls setRTC_Time()
*
* loop()
* - calls UpDateTime()
- calls rtc.year() etc.
- calls TimePeriodIsOver()
- conditionally calls PrintTime()
*/
#include "Arduino.h"
#include "uRTCLib.h"
// uRTCLib rtc;
uRTCLib rtc(0x68);
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int myYear;
int myMonth;
int myDay;
int myDayOfWeek;
int myHour;
int myMinute;
int mySecond;
int minuteOfDay;
// 23*3600+59*60+59 = 86399 which is a to big number for int
long secondsOfDay;
int MinOfDay_9OClock = 9 * 60;
unsigned long myTimer;
void setup() {
Serial.begin(9600);
delay(3000); // wait for console opening
URTCLIB_WIRE.begin();
setRTC_Time();
}
void loop() {
UpDateTime();
// check if more than 1000 milliseconds have passed by
// since last time the 1000-ms-period-was-over
if ( TimePeriodIsOver(myTimer,1000) ) {
// if REALLY 1000 milliseconds have passed by
PrintTime();
}
}
void setRTC_Time() {
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
myYear = 22;
myMonth = 1;
myDay = 13;
myDayOfWeek = 7;
myHour = 23;
myMinute = 59;
mySecond = 50;
// using variables makes comments obsolete
rtc.set(mySecond, myMinute, myHour, myDayOfWeek, myDay, myMonth, myYear) ;
// set day of week (1=Sunday, 7=Saturday)
}
void UpDateTime() {
rtc.refresh();
myYear = rtc.year();
myMonth = rtc.month();
myDay = rtc.day();
myHour = rtc.hour();
myMinute = rtc.minute();
mySecond = rtc.second();
minuteOfDay = myHour * 60 + myMinute;
secondsOfDay = myHour * 3600 + myMinute * 60 + mySecond;
}
void PrintTime() {
Serial.print("Current Date & Time: ");
Serial.print(myYear);
Serial.print('/');
Serial.print(myMonth);
Serial.print('/');
Serial.print(myDay);
Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
Serial.print(") ");
Serial.print(myHour);
Serial.print(':');
Serial.print(myMinute);
Serial.print(':');
Serial.println();
Serial.print("minuteOfDay:");
Serial.print(minuteOfDay);
Serial.print(" secondsOfDay:");
Serial.println(secondsOfDay);
if (minuteOfDay < MinOfDay_9OClock) {
Serial.println("it is before 9 o' clock");
}
else {
Serial.println("it is past 9 o' clock");
}
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
Hi, Stefan I have been trying to work with your code, except I come across 2 problems. The first being, the time printed, instead of being 22/1/13 (Sunday) 23:59:50, is 81/13/7 (Tuesday) 19:50:0. It fixes after a few resets on the board, but this error pops up randomly. The second being, I tried to form an "if" statement, such that when the time reaches midnight, an LED turns on. Haven't had any luck with that either. Below is my code and a picture of my circuitry.
/*structure (= function-call hierachry) of the code
* setup()
* - calls setRTC_Time()
*
* loop()
* - calls UpDateTime()
- calls rtc.year() etc.
- calls TimePeriodIsOver()
- conditionally calls PrintTime()
*/
#include "Arduino.h"
#include "uRTCLib.h"
// uRTCLib rtc;
uRTCLib rtc(0x68);
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int myYear;
int myMonth;
int myDay;
int myDayOfWeek;
int myHour;
int myMinute;
int mySecond;
int minuteOfDay;
// 23*3600+59*60+59 = 86399 which is a to big number for int
long secondsOfDay;
int MinOfDay_9OClock = 9 * 60;
unsigned long myTimer;
void setup() {
Serial.begin(9600);
delay(3000); // wait for console opening
pinMode(12,OUTPUT);
URTCLIB_WIRE.begin();
setRTC_Time();
}
void loop() {
UpDateTime();
// check if more than 1000 milliseconds have passed by
// since last time the 1000-ms-period-was-over
if ( TimePeriodIsOver(myTimer,1000) ) {
// if REALLY 1000 milliseconds have passed by
PrintTime();
}
}
void setRTC_Time() {
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
myYear = 22;
myMonth = 1;
myDay = 13;
myDayOfWeek = 7;
myHour = 23;
myMinute = 59;
mySecond = 50;
// using variables makes comments obsolete
rtc.set(mySecond, myMinute, myHour, myDayOfWeek, myDay, myMonth, myYear) ;
// set day of week (1=Sunday, 7=Saturday)
}
void UpDateTime() {
rtc.refresh();
myYear = rtc.year();
myMonth = rtc.month();
myDay = rtc.day();
myHour = rtc.hour();
myMinute = rtc.minute();
mySecond = rtc.second();
minuteOfDay = myHour * 60 + myMinute;
secondsOfDay = myHour * 3600 + myMinute * 60 + mySecond;
}
void PrintTime() {
Serial.print("Current Date & Time: ");
Serial.print(myYear);
Serial.print('/');
Serial.print(myMonth);
Serial.print('/');
Serial.print(myDay);
Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
Serial.print(") ");
Serial.print(myHour);
Serial.print(':');
Serial.print(myMinute);
Serial.print(':');
Serial.print(mySecond);
Serial.println();
Serial.print("minuteOfDay:");
Serial.print(minuteOfDay);
Serial.print(" secondsOfDay:");
Serial.println(secondsOfDay);
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
if("minuteofDay"== 0){
digitalWrite(12,HIGH);
}
}
P.S. Sorry to keep troubling, but I've been trying to figure out how the TimeOver() function works, and I am not too sure about that block of code. Could you help elaborate more on that?
Also, I found this code from another topic in the forum. The code works, but how can I set the time? There seems to be no code for setting the time and date values. Thanks
you put the if-condition into the function TimePeriodIsOver
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
if ("minuteOfDay" == 0) {
digitalWrite(12, HIGH);
}
}
There is a spelling-error
you wrote minuteofDay
but it has to be
minuteOfDay
CAPITAL "O"
What was the reason for you to put it inside this function?
The condition that you defined itself does not work
if ("minuteOfDay" == 0) {
what your condition is
compare if fixed string with charactersequence minuteofDay is the same as number zero
which of course is never true
the double-hyphen make the characters a string
"minuteOfDay"
it works if you code it without the double-hyphen
if ("minuteOfDay" == 0) { // double-hyphen is WRONG
if (minuteOfDay == 0) { // WITHOUT double-hyphen it works
but you should not put it into the function TimePeriodIsOver
This would counteract massively on the concept that each function does one thing
The function TimePeriodIsOver does what its name says:
check if a certain period of time is over
The name says absolutely nothing about:
"and if its midnight switch on a LED!"
You would have almost hidden away the LED-switching and you and everybody else would have to analyse the code very very carefully to detect ah ! here the LED is switched on !
You should use self-explaining names for everything
for two reasons
it makes the code easier to read
if you change the value that is represented by this name there is exactly one place to change the value
example: you want to change the LED from IO-pin 12 to IO-pin 8
With a self-explaining name you can't forget the third place where you have coded "12" to change it to "8" because there is only one place to change it
and you are done !
Because at all other places in your code the nameLED_Pin is used
.
.
I defined to new constants
const int MOD_to_Switch_On = 0 * 60; // M)inutes-O)f-D)ay
const long SOD_to_switch_off = 1 * 60 + 10; // S)econds-Of-D)ay at 00:01:10
which are used to switch on / off the LED at the bottom of loop
if (minuteOfDay == MOD_to_Switch_On) {
digitalWrite(LED_Pin, HIGH);
}
if (secondsOfDay == SOD_to_switch_off) {
digitalWrite(LED_Pin, LOW);
}
The self-explaining names make commenting obsolete
The code explains itself
if it does not occur regular but only from time to time I suspect this is a bad signal problem or a wrong RTC-type problem
the constructor has anoption for a second parameter
define explicitly the your RTC-type
This name "URTCLIB_MODEL_DS1307" is defined in the uRTC.h-file of the library
// uRTCLib rtc; // URTCLIB_MODEL_DS1307
//uRTCLib rtc(0x68);
uRTCLib rtc(0x68,URTCLIB_MODEL_DS1307); // define EXPLICIT the model
Does the RTC-module have pullup-resistors?
On the I2C-bus do all pins have secure contact?
So here is a version with the modifications like describes above
/*structure (= function-call hierachry) of the code
setup()
- calls setRTC_Time()
loop()
- calls UpDateTime()
- calls rtc.year() etc.
- calls TimePeriodIsOver()
- conditionally calls PrintTime()
*/
#include "Arduino.h"
#include "uRTCLib.h"
// uRTCLib rtc; // URTCLIB_MODEL_DS1307
//uRTCLib rtc(0x68);
uRTCLib rtc(0x68,URTCLIB_MODEL_DS1307); // define EXPLICIT the model
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int myYear;
int myMonth;
int myDay;
int myDayOfWeek;
int myHour;
int myMinute;
int mySecond;
int minuteOfDay;
// 23*3600+59*60+59 = 86399 which is a to big number for int
long secondsOfDay;
const int MinOfDay_9OClock = 9 * 60;
const int MOD_to_Switch_On = 0 * 60; // M)inutes-O)f-D)ay
const long SOD_to_switch_off = 1 * 60 + 10; // S)econds-Of-D)ay at 00:01:00
unsigned long myTimer;
const byte LED_Pin = 12; // define constants ofr IO-pin numbers
void setup() {
Serial.begin(9600);
delay(3000); // wait for console opening
pinMode(LED_Pin, OUTPUT);
URTCLIB_WIRE.begin();
setRTC_Time();
}
void loop() {
UpDateTime();
// check if more than 1000 milliseconds have passed by
// since last time the 1000-ms-period-was-over
if ( TimePeriodIsOver(myTimer, 1000) ) {
// if REALLY 1000 milliseconds have passed by
PrintTime();
}
if (minuteOfDay == MOD_to_Switch_On) {
digitalWrite(LED_Pin, HIGH);
}
if (secondsOfDay == SOD_to_switch_off) {
digitalWrite(LED_Pin, LOW);
}
}
void setRTC_Time() {
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
myYear = 22;
myMonth = 1;
myDay = 13;
myDayOfWeek = 7;
myHour = 23;
myMinute = 59;
mySecond = 50;
// using variables makes comments obsolete
//void uRTCLib::set(const uint8_t second, const uint8_t minute, const uint8_t hour, const uint8_t dayOfWeek, const uint8_t dayOfMonth, const uint8_t month, const uint8_t year) {
//rtc.set( mySecond, myMinute, myHour, myDayOfWeek, myDay, myMonth, myYear) ;
rtc.set(mySecond, myMinute, myHour, myDayOfWeek, myDay, myMonth, myYear) ;
// set day of week (1=Sunday, 7=Saturday)
}
void UpDateTime() {
rtc.refresh();
myYear = rtc.year();
myMonth = rtc.month();
myDay = rtc.day();
myHour = rtc.hour();
myMinute = rtc.minute();
mySecond = rtc.second();
minuteOfDay = myHour * 60 + myMinute;
secondsOfDay = myHour * 3600 + myMinute * 60 + mySecond;
}
void PrintTime() {
Serial.print("Current Date & Time: ");
Serial.print(myYear);
Serial.print('/');
Serial.print(myMonth);
Serial.print('/');
Serial.print(myDay);
Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
Serial.print(") ");
Serial.print(myHour);
Serial.print(':');
Serial.print(myMinute);
Serial.print(':');
Serial.print(mySecond);
Serial.println();
Serial.print("minuteOfDay:");
Serial.print(minuteOfDay);
Serial.print(" secondsOfDay:");
Serial.println(secondsOfDay);
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
If you want to understand the function TimePeriodIsOver you can read this tutorial about non-blocking timing