Digital clock with many functions - follow-up
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
This is a follow-up from Digital clock with many functions
I used the review mentioned above to optimize the code, but the code can still be made better.
I made a digital clock with the use of an RTC (DS3231) and an LCD (16x2).
Current functions:
- Display time
- Display date (different formats)
- Display temperature (Celsius and Fahrenheit)
- Display day of the week (English and Dutch)
- Display week number
- Display number of day in the year
- Humidity (%)
- Dew point (Celsius and Fahrenheit)
- Change summer -> winter time (this will be done automatically, once set correctly)
Future functions:
- Menu (controlled using the buttons on the LCD shield)
- Alarm (already possible with predefining it at the start)
- Timer
- Stopwatch
- Local time of different locations
I want to implement these future functions as quickly as possible. Please feel free to give feedback and your opinion about what could be better/more efficient.
Github
Clock.ino:
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include <Timezone.h> // https://github.com/JChristensen/Timezone
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
#include <Streaming.h> // http://arduiniana.org/libraries/streaming/
#include <Wire.h> // https://www.arduino.cc/en/Reference/Wire
#include <LiquidCrystal.h> // https://www.arduino.cc/en/Reference/LiquidCrystal
#include <DHT.h> // https://github.com/adafruit/DHT-sensor-library
#include "Date.h"
#define DHTPIN 2 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
/* EXPLANATION DIFFERENT FUNCTIONS FOR CLOCK (WILL ONLY BE USED ON THE HOMEPAGE)
TIME
'h' = hours
'm' = minutes
's' = seconds
'a' = alarm 1 (not atm)
'A' = alarm 2 (not atm)
WEATHER
'T' = temperature
'H' = humidity (no sensor atm)
'P' = dew point (no sensor atm)
DATE
'd' = day of week
'D' = day
'M' = month
'S' = month (short string)
'Y' = year
'w' = weeknumber
'n' = daynumber
MISCELLANEOUS
'l' = current location (need to create a array of enums/strings which can be used in Settings)
DELIMTERS
':' = delimiter
'-' = delimiter
'/' = delimiter
'.' = delimiter
'|' = delimiter
' ' = delimiter
*/
const int kNumLCDCols = 16;
const int kNumLCDRows = 2;
const int kSerialBaud = 9600;
const int kLPin = 13;
const int kNumLCDChars = kNumLCDCols * kNumLCDRows;
char homepage[kNumLCDCols] = "h:m:s", "d D-M-Y", "T H", "w n";
const size_t kNumSupportedLanguages = 2;
const size_t kNumDaysPerWeek = 7;
const size_t kNumMonthsPerYear = 12;
const size_t kNumLabels = 5;
const size_t numberOfPages = (sizeof(homepage) / sizeof(char)) / kNumLCDChars;
const String days[kNumSupportedLanguages][kNumDaysPerWeek] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "zo", "ma", "di", "wo", "do", "vr", "za";
const String months[kNumSupportedLanguages][kNumMonthsPerYear] = "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "jan", "feb", "mrt", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec";
const String labels[kNumLabels] = "T", "RH", "DP", "D", "Wk";
const char degreesSymbol = 223;
enum languages_t EN, NL;
enum degreesFormats_t CELSIUS, FAHRENHEIT;
enum hourFormats_t HourFormat12, HourFormat24;
typedef struct
uint8_t hourFormat; // 12 or 24 hour format (AM/PM is not displayed)
uint8_t language; // The language for several labels
uint8_t degreesFormat; // Celsius or Fahrenheit
boolean labels; // Display temperature, weeknumber and daynumber with label
Settings;
Settings settings = HourFormat24, NL, CELSIUS, true;
unsigned long previousMillis = 0; // will store last time lcd was updated (page 1)
unsigned long oldMillis = 0; // will store last time lcd switched pages
TimeChangeRule myDST = "MDT", Last, Sun, Mar, 2, 2 * 60; //Daylight time/Summertime = UTC + 2 hours
TimeChangeRule mySTD = "MST", Last, Sun, Oct, 2, 1 * 60; //Standard time/Wintertime = UTC + 1 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev
int language_id;
int rowX = 0;
int rowY = 2;
float tem;
float hum;
float dew;
const long refreshRate = 1000;
const long switchPages = 3000;
void setup()
Serial.begin(9600);
lcd.begin(kNumLCDCols, kNumLCDRows);
// setSyncProvider() causes the Time library to synchronize with the
// external RTC by calling RTC.get() every five minutes by default.
setSyncProvider(RTC.get);
if (timeStatus() != timeSet) lcd << ("RTC SYNC FAILED");
pinMode(kLPin, OUTPUT);
digitalWrite(kLPin, LOW);
void loop()
mainLoop();
void mainLoop()
// check to see if it's time to refresh the lcd; that is, if the difference
// between the current time and last time you refreshed the lcd is bigger than
// the interval at which you want to refresh the lcd.
unsigned long currentMillis = millis();
defineLanguageId();
tem = dht.readTemperature();
hum = dht.readHumidity();
if (currentMillis - previousMillis >= refreshRate)
// save the last time you refreshed the lcd
previousMillis = currentMillis;
// display the date and time according to the specificied order with the specified settings
displayPage(rowX, rowY);
if (currentMillis - oldMillis >= switchPages)
oldMillis = currentMillis;
if (rowY == numberOfPages * 2)
rowX = 0;
rowY = 2;
lcd.clear();
else
rowX += 2;
rowY += 2;
lcd.clear();
void displayPage(int rowStart, int rowEnd)
time_t utc, local;
utc = now();
local = myTZ.toLocal(utc, &tcr);
// calculate which day and week of the year it is, according to the current local time
DayWeekNumber(year(local), month(local), day(local), weekday(local));
lcd.setCursor(0, 0);
// for-loop which loops through each row
for (int row = rowStart; row < rowEnd; row++)
// if row == odd, then we are on the second line, so move the cursor of the lcd
if (not(row % 2 == 0)) lcd.setCursor(0, 1);
// for-loop which loops through each char in row
for (int pos = 0; pos < 15; pos++)
displayDesiredFunction(row, pos, local);
void displayDesiredFunction(int row, int pos, time_t l)
switch (homepage[row][pos]) '
break;
case ' ':
displayDelimiter(' '); // display ' '
break;
void displayHours(time_t l)
(settings.hourFormat == HourFormat24) ? printI00(hour(l)) : printI00(hourFormat12(l));
void displayTemperature()
if (settings.labels)
lcd << labels[0] << ": ";
lcdDisplayTempDew(tem);
void displayHumidity()
if (settings.labels)
lcd << labels[1] << ": ";
lcd << int(hum) << "%";
void displayDewPoint()
dew = calculateDewPoint(tem, hum);
if (settings.labels)
lcd << labels[2] << ": ";
lcdDisplayTempDew(dew);
void lcdDisplayTempDew(float val)
(settings.degreesFormat == CELSIUS) ? lcd << int(val) << degreesSymbol << "C" : lcd << celsiusToFahrenheit(val) << (char)223 << "F";
float calculateDewPoint(float t, float h)
float a = 17.271;
float b = 237.7;
float temp = (a * t) / (b + t) + log(h * 0.01);
float Td = (b * temp) / (a - temp);
return Td;
void displayWeekday(int val)
lcd << days[language_id][val - 1];
void displayNumber(char val)
if (val == 'd')
if (settings.labels == true)
lcd << labels[3] << ": ";
printI00(DW[0]);
else
if (settings.labels == true)
lcd << labels[4] << ": ";
printI00(DW[1]);
void displayMonthShortStr(int val)
lcd << months[language_id][val];
void displayLocation()
//lcd << settings.location;
void defineLanguageId()
switch (settings.language)
case EN:
language_id = 0;
break;
case NL:
language_id = 1;
void printI00(int val)
if (val < 10) lcd << '0';
lcd << _DEC(val);
void displayDelimiter(char delim)
lcd << delim;
void setTimeRTC(unsigned int hours, unsigned int minutes, unsigned int seconds, unsigned int d, unsigned int m, unsigned int y)
setTime(hours, minutes, seconds, d, m, y);
RTC.set(now());
int celsiusToFahrenheit(const float celsius)
return static_cast<int>(celsius * 1.8 + 32);
Date.h:
short DW[2];
void DayWeekNumber(unsigned int y, unsigned int m, unsigned int d, unsigned int w)
int ndays = 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334; // Number of days at the beginning of the month in a not leap year.
int numLeapDaysToAdd = 0;
if ((y % 4 == 0 && y % 100 != 0)
c++ datetime arduino
add a comment |Â
up vote
1
down vote
favorite
This is a follow-up from Digital clock with many functions
I used the review mentioned above to optimize the code, but the code can still be made better.
I made a digital clock with the use of an RTC (DS3231) and an LCD (16x2).
Current functions:
- Display time
- Display date (different formats)
- Display temperature (Celsius and Fahrenheit)
- Display day of the week (English and Dutch)
- Display week number
- Display number of day in the year
- Humidity (%)
- Dew point (Celsius and Fahrenheit)
- Change summer -> winter time (this will be done automatically, once set correctly)
Future functions:
- Menu (controlled using the buttons on the LCD shield)
- Alarm (already possible with predefining it at the start)
- Timer
- Stopwatch
- Local time of different locations
I want to implement these future functions as quickly as possible. Please feel free to give feedback and your opinion about what could be better/more efficient.
Github
Clock.ino:
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include <Timezone.h> // https://github.com/JChristensen/Timezone
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
#include <Streaming.h> // http://arduiniana.org/libraries/streaming/
#include <Wire.h> // https://www.arduino.cc/en/Reference/Wire
#include <LiquidCrystal.h> // https://www.arduino.cc/en/Reference/LiquidCrystal
#include <DHT.h> // https://github.com/adafruit/DHT-sensor-library
#include "Date.h"
#define DHTPIN 2 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
/* EXPLANATION DIFFERENT FUNCTIONS FOR CLOCK (WILL ONLY BE USED ON THE HOMEPAGE)
TIME
'h' = hours
'm' = minutes
's' = seconds
'a' = alarm 1 (not atm)
'A' = alarm 2 (not atm)
WEATHER
'T' = temperature
'H' = humidity (no sensor atm)
'P' = dew point (no sensor atm)
DATE
'd' = day of week
'D' = day
'M' = month
'S' = month (short string)
'Y' = year
'w' = weeknumber
'n' = daynumber
MISCELLANEOUS
'l' = current location (need to create a array of enums/strings which can be used in Settings)
DELIMTERS
':' = delimiter
'-' = delimiter
'/' = delimiter
'.' = delimiter
'|' = delimiter
' ' = delimiter
*/
const int kNumLCDCols = 16;
const int kNumLCDRows = 2;
const int kSerialBaud = 9600;
const int kLPin = 13;
const int kNumLCDChars = kNumLCDCols * kNumLCDRows;
char homepage[kNumLCDCols] = "h:m:s", "d D-M-Y", "T H", "w n";
const size_t kNumSupportedLanguages = 2;
const size_t kNumDaysPerWeek = 7;
const size_t kNumMonthsPerYear = 12;
const size_t kNumLabels = 5;
const size_t numberOfPages = (sizeof(homepage) / sizeof(char)) / kNumLCDChars;
const String days[kNumSupportedLanguages][kNumDaysPerWeek] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "zo", "ma", "di", "wo", "do", "vr", "za";
const String months[kNumSupportedLanguages][kNumMonthsPerYear] = "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "jan", "feb", "mrt", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec";
const String labels[kNumLabels] = "T", "RH", "DP", "D", "Wk";
const char degreesSymbol = 223;
enum languages_t EN, NL;
enum degreesFormats_t CELSIUS, FAHRENHEIT;
enum hourFormats_t HourFormat12, HourFormat24;
typedef struct
uint8_t hourFormat; // 12 or 24 hour format (AM/PM is not displayed)
uint8_t language; // The language for several labels
uint8_t degreesFormat; // Celsius or Fahrenheit
boolean labels; // Display temperature, weeknumber and daynumber with label
Settings;
Settings settings = HourFormat24, NL, CELSIUS, true;
unsigned long previousMillis = 0; // will store last time lcd was updated (page 1)
unsigned long oldMillis = 0; // will store last time lcd switched pages
TimeChangeRule myDST = "MDT", Last, Sun, Mar, 2, 2 * 60; //Daylight time/Summertime = UTC + 2 hours
TimeChangeRule mySTD = "MST", Last, Sun, Oct, 2, 1 * 60; //Standard time/Wintertime = UTC + 1 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev
int language_id;
int rowX = 0;
int rowY = 2;
float tem;
float hum;
float dew;
const long refreshRate = 1000;
const long switchPages = 3000;
void setup()
Serial.begin(9600);
lcd.begin(kNumLCDCols, kNumLCDRows);
// setSyncProvider() causes the Time library to synchronize with the
// external RTC by calling RTC.get() every five minutes by default.
setSyncProvider(RTC.get);
if (timeStatus() != timeSet) lcd << ("RTC SYNC FAILED");
pinMode(kLPin, OUTPUT);
digitalWrite(kLPin, LOW);
void loop()
mainLoop();
void mainLoop()
// check to see if it's time to refresh the lcd; that is, if the difference
// between the current time and last time you refreshed the lcd is bigger than
// the interval at which you want to refresh the lcd.
unsigned long currentMillis = millis();
defineLanguageId();
tem = dht.readTemperature();
hum = dht.readHumidity();
if (currentMillis - previousMillis >= refreshRate)
// save the last time you refreshed the lcd
previousMillis = currentMillis;
// display the date and time according to the specificied order with the specified settings
displayPage(rowX, rowY);
if (currentMillis - oldMillis >= switchPages)
oldMillis = currentMillis;
if (rowY == numberOfPages * 2)
rowX = 0;
rowY = 2;
lcd.clear();
else
rowX += 2;
rowY += 2;
lcd.clear();
void displayPage(int rowStart, int rowEnd)
time_t utc, local;
utc = now();
local = myTZ.toLocal(utc, &tcr);
// calculate which day and week of the year it is, according to the current local time
DayWeekNumber(year(local), month(local), day(local), weekday(local));
lcd.setCursor(0, 0);
// for-loop which loops through each row
for (int row = rowStart; row < rowEnd; row++)
// if row == odd, then we are on the second line, so move the cursor of the lcd
if (not(row % 2 == 0)) lcd.setCursor(0, 1);
// for-loop which loops through each char in row
for (int pos = 0; pos < 15; pos++)
displayDesiredFunction(row, pos, local);
void displayDesiredFunction(int row, int pos, time_t l)
switch (homepage[row][pos]) '
break;
case ' ':
displayDelimiter(' '); // display ' '
break;
void displayHours(time_t l)
(settings.hourFormat == HourFormat24) ? printI00(hour(l)) : printI00(hourFormat12(l));
void displayTemperature()
if (settings.labels)
lcd << labels[0] << ": ";
lcdDisplayTempDew(tem);
void displayHumidity()
if (settings.labels)
lcd << labels[1] << ": ";
lcd << int(hum) << "%";
void displayDewPoint()
dew = calculateDewPoint(tem, hum);
if (settings.labels)
lcd << labels[2] << ": ";
lcdDisplayTempDew(dew);
void lcdDisplayTempDew(float val)
(settings.degreesFormat == CELSIUS) ? lcd << int(val) << degreesSymbol << "C" : lcd << celsiusToFahrenheit(val) << (char)223 << "F";
float calculateDewPoint(float t, float h)
float a = 17.271;
float b = 237.7;
float temp = (a * t) / (b + t) + log(h * 0.01);
float Td = (b * temp) / (a - temp);
return Td;
void displayWeekday(int val)
lcd << days[language_id][val - 1];
void displayNumber(char val)
if (val == 'd')
if (settings.labels == true)
lcd << labels[3] << ": ";
printI00(DW[0]);
else
if (settings.labels == true)
lcd << labels[4] << ": ";
printI00(DW[1]);
void displayMonthShortStr(int val)
lcd << months[language_id][val];
void displayLocation()
//lcd << settings.location;
void defineLanguageId()
switch (settings.language)
case EN:
language_id = 0;
break;
case NL:
language_id = 1;
void printI00(int val)
if (val < 10) lcd << '0';
lcd << _DEC(val);
void displayDelimiter(char delim)
lcd << delim;
void setTimeRTC(unsigned int hours, unsigned int minutes, unsigned int seconds, unsigned int d, unsigned int m, unsigned int y)
setTime(hours, minutes, seconds, d, m, y);
RTC.set(now());
int celsiusToFahrenheit(const float celsius)
return static_cast<int>(celsius * 1.8 + 32);
Date.h:
short DW[2];
void DayWeekNumber(unsigned int y, unsigned int m, unsigned int d, unsigned int w)
int ndays = 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334; // Number of days at the beginning of the month in a not leap year.
int numLeapDaysToAdd = 0;
if ((y % 4 == 0 && y % 100 != 0)
c++ datetime arduino
In your previous question you said in a comment that the code was in C. Is it now still in C? Then you should remove the C++ tag.
â mkrieger1
Jan 17 at 15:21
@mkrieger1 This looks like C++ to me, not C (for example, there is nostatic_cast
in C).
â Ben Steffan
Jan 17 at 16:10
Okay, then the comment was wrong.
â mkrieger1
Jan 17 at 16:18
This is written for Arduino. ItâÂÂs C but the static_cast does work. Therefore I placed it under C and C++
â Sebastiaan Speck
Jan 17 at 16:42
When you're using the arduino development environment, and external libraries you're using C++ e.g.Serial.begin()
...
â Harald Scheirich
Jan 18 at 11:52
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
This is a follow-up from Digital clock with many functions
I used the review mentioned above to optimize the code, but the code can still be made better.
I made a digital clock with the use of an RTC (DS3231) and an LCD (16x2).
Current functions:
- Display time
- Display date (different formats)
- Display temperature (Celsius and Fahrenheit)
- Display day of the week (English and Dutch)
- Display week number
- Display number of day in the year
- Humidity (%)
- Dew point (Celsius and Fahrenheit)
- Change summer -> winter time (this will be done automatically, once set correctly)
Future functions:
- Menu (controlled using the buttons on the LCD shield)
- Alarm (already possible with predefining it at the start)
- Timer
- Stopwatch
- Local time of different locations
I want to implement these future functions as quickly as possible. Please feel free to give feedback and your opinion about what could be better/more efficient.
Github
Clock.ino:
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include <Timezone.h> // https://github.com/JChristensen/Timezone
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
#include <Streaming.h> // http://arduiniana.org/libraries/streaming/
#include <Wire.h> // https://www.arduino.cc/en/Reference/Wire
#include <LiquidCrystal.h> // https://www.arduino.cc/en/Reference/LiquidCrystal
#include <DHT.h> // https://github.com/adafruit/DHT-sensor-library
#include "Date.h"
#define DHTPIN 2 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
/* EXPLANATION DIFFERENT FUNCTIONS FOR CLOCK (WILL ONLY BE USED ON THE HOMEPAGE)
TIME
'h' = hours
'm' = minutes
's' = seconds
'a' = alarm 1 (not atm)
'A' = alarm 2 (not atm)
WEATHER
'T' = temperature
'H' = humidity (no sensor atm)
'P' = dew point (no sensor atm)
DATE
'd' = day of week
'D' = day
'M' = month
'S' = month (short string)
'Y' = year
'w' = weeknumber
'n' = daynumber
MISCELLANEOUS
'l' = current location (need to create a array of enums/strings which can be used in Settings)
DELIMTERS
':' = delimiter
'-' = delimiter
'/' = delimiter
'.' = delimiter
'|' = delimiter
' ' = delimiter
*/
const int kNumLCDCols = 16;
const int kNumLCDRows = 2;
const int kSerialBaud = 9600;
const int kLPin = 13;
const int kNumLCDChars = kNumLCDCols * kNumLCDRows;
char homepage[kNumLCDCols] = "h:m:s", "d D-M-Y", "T H", "w n";
const size_t kNumSupportedLanguages = 2;
const size_t kNumDaysPerWeek = 7;
const size_t kNumMonthsPerYear = 12;
const size_t kNumLabels = 5;
const size_t numberOfPages = (sizeof(homepage) / sizeof(char)) / kNumLCDChars;
const String days[kNumSupportedLanguages][kNumDaysPerWeek] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "zo", "ma", "di", "wo", "do", "vr", "za";
const String months[kNumSupportedLanguages][kNumMonthsPerYear] = "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "jan", "feb", "mrt", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec";
const String labels[kNumLabels] = "T", "RH", "DP", "D", "Wk";
const char degreesSymbol = 223;
enum languages_t EN, NL;
enum degreesFormats_t CELSIUS, FAHRENHEIT;
enum hourFormats_t HourFormat12, HourFormat24;
typedef struct
uint8_t hourFormat; // 12 or 24 hour format (AM/PM is not displayed)
uint8_t language; // The language for several labels
uint8_t degreesFormat; // Celsius or Fahrenheit
boolean labels; // Display temperature, weeknumber and daynumber with label
Settings;
Settings settings = HourFormat24, NL, CELSIUS, true;
unsigned long previousMillis = 0; // will store last time lcd was updated (page 1)
unsigned long oldMillis = 0; // will store last time lcd switched pages
TimeChangeRule myDST = "MDT", Last, Sun, Mar, 2, 2 * 60; //Daylight time/Summertime = UTC + 2 hours
TimeChangeRule mySTD = "MST", Last, Sun, Oct, 2, 1 * 60; //Standard time/Wintertime = UTC + 1 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev
int language_id;
int rowX = 0;
int rowY = 2;
float tem;
float hum;
float dew;
const long refreshRate = 1000;
const long switchPages = 3000;
void setup()
Serial.begin(9600);
lcd.begin(kNumLCDCols, kNumLCDRows);
// setSyncProvider() causes the Time library to synchronize with the
// external RTC by calling RTC.get() every five minutes by default.
setSyncProvider(RTC.get);
if (timeStatus() != timeSet) lcd << ("RTC SYNC FAILED");
pinMode(kLPin, OUTPUT);
digitalWrite(kLPin, LOW);
void loop()
mainLoop();
void mainLoop()
// check to see if it's time to refresh the lcd; that is, if the difference
// between the current time and last time you refreshed the lcd is bigger than
// the interval at which you want to refresh the lcd.
unsigned long currentMillis = millis();
defineLanguageId();
tem = dht.readTemperature();
hum = dht.readHumidity();
if (currentMillis - previousMillis >= refreshRate)
// save the last time you refreshed the lcd
previousMillis = currentMillis;
// display the date and time according to the specificied order with the specified settings
displayPage(rowX, rowY);
if (currentMillis - oldMillis >= switchPages)
oldMillis = currentMillis;
if (rowY == numberOfPages * 2)
rowX = 0;
rowY = 2;
lcd.clear();
else
rowX += 2;
rowY += 2;
lcd.clear();
void displayPage(int rowStart, int rowEnd)
time_t utc, local;
utc = now();
local = myTZ.toLocal(utc, &tcr);
// calculate which day and week of the year it is, according to the current local time
DayWeekNumber(year(local), month(local), day(local), weekday(local));
lcd.setCursor(0, 0);
// for-loop which loops through each row
for (int row = rowStart; row < rowEnd; row++)
// if row == odd, then we are on the second line, so move the cursor of the lcd
if (not(row % 2 == 0)) lcd.setCursor(0, 1);
// for-loop which loops through each char in row
for (int pos = 0; pos < 15; pos++)
displayDesiredFunction(row, pos, local);
void displayDesiredFunction(int row, int pos, time_t l)
switch (homepage[row][pos]) '
break;
case ' ':
displayDelimiter(' '); // display ' '
break;
void displayHours(time_t l)
(settings.hourFormat == HourFormat24) ? printI00(hour(l)) : printI00(hourFormat12(l));
void displayTemperature()
if (settings.labels)
lcd << labels[0] << ": ";
lcdDisplayTempDew(tem);
void displayHumidity()
if (settings.labels)
lcd << labels[1] << ": ";
lcd << int(hum) << "%";
void displayDewPoint()
dew = calculateDewPoint(tem, hum);
if (settings.labels)
lcd << labels[2] << ": ";
lcdDisplayTempDew(dew);
void lcdDisplayTempDew(float val)
(settings.degreesFormat == CELSIUS) ? lcd << int(val) << degreesSymbol << "C" : lcd << celsiusToFahrenheit(val) << (char)223 << "F";
float calculateDewPoint(float t, float h)
float a = 17.271;
float b = 237.7;
float temp = (a * t) / (b + t) + log(h * 0.01);
float Td = (b * temp) / (a - temp);
return Td;
void displayWeekday(int val)
lcd << days[language_id][val - 1];
void displayNumber(char val)
if (val == 'd')
if (settings.labels == true)
lcd << labels[3] << ": ";
printI00(DW[0]);
else
if (settings.labels == true)
lcd << labels[4] << ": ";
printI00(DW[1]);
void displayMonthShortStr(int val)
lcd << months[language_id][val];
void displayLocation()
//lcd << settings.location;
void defineLanguageId()
switch (settings.language)
case EN:
language_id = 0;
break;
case NL:
language_id = 1;
void printI00(int val)
if (val < 10) lcd << '0';
lcd << _DEC(val);
void displayDelimiter(char delim)
lcd << delim;
void setTimeRTC(unsigned int hours, unsigned int minutes, unsigned int seconds, unsigned int d, unsigned int m, unsigned int y)
setTime(hours, minutes, seconds, d, m, y);
RTC.set(now());
int celsiusToFahrenheit(const float celsius)
return static_cast<int>(celsius * 1.8 + 32);
Date.h:
short DW[2];
void DayWeekNumber(unsigned int y, unsigned int m, unsigned int d, unsigned int w)
int ndays = 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334; // Number of days at the beginning of the month in a not leap year.
int numLeapDaysToAdd = 0;
if ((y % 4 == 0 && y % 100 != 0)
c++ datetime arduino
This is a follow-up from Digital clock with many functions
I used the review mentioned above to optimize the code, but the code can still be made better.
I made a digital clock with the use of an RTC (DS3231) and an LCD (16x2).
Current functions:
- Display time
- Display date (different formats)
- Display temperature (Celsius and Fahrenheit)
- Display day of the week (English and Dutch)
- Display week number
- Display number of day in the year
- Humidity (%)
- Dew point (Celsius and Fahrenheit)
- Change summer -> winter time (this will be done automatically, once set correctly)
Future functions:
- Menu (controlled using the buttons on the LCD shield)
- Alarm (already possible with predefining it at the start)
- Timer
- Stopwatch
- Local time of different locations
I want to implement these future functions as quickly as possible. Please feel free to give feedback and your opinion about what could be better/more efficient.
Github
Clock.ino:
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include <Timezone.h> // https://github.com/JChristensen/Timezone
#include <TimeLib.h> // https://github.com/PaulStoffregen/Time
#include <Streaming.h> // http://arduiniana.org/libraries/streaming/
#include <Wire.h> // https://www.arduino.cc/en/Reference/Wire
#include <LiquidCrystal.h> // https://www.arduino.cc/en/Reference/LiquidCrystal
#include <DHT.h> // https://github.com/adafruit/DHT-sensor-library
#include "Date.h"
#define DHTPIN 2 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
/* EXPLANATION DIFFERENT FUNCTIONS FOR CLOCK (WILL ONLY BE USED ON THE HOMEPAGE)
TIME
'h' = hours
'm' = minutes
's' = seconds
'a' = alarm 1 (not atm)
'A' = alarm 2 (not atm)
WEATHER
'T' = temperature
'H' = humidity (no sensor atm)
'P' = dew point (no sensor atm)
DATE
'd' = day of week
'D' = day
'M' = month
'S' = month (short string)
'Y' = year
'w' = weeknumber
'n' = daynumber
MISCELLANEOUS
'l' = current location (need to create a array of enums/strings which can be used in Settings)
DELIMTERS
':' = delimiter
'-' = delimiter
'/' = delimiter
'.' = delimiter
'|' = delimiter
' ' = delimiter
*/
const int kNumLCDCols = 16;
const int kNumLCDRows = 2;
const int kSerialBaud = 9600;
const int kLPin = 13;
const int kNumLCDChars = kNumLCDCols * kNumLCDRows;
char homepage[kNumLCDCols] = "h:m:s", "d D-M-Y", "T H", "w n";
const size_t kNumSupportedLanguages = 2;
const size_t kNumDaysPerWeek = 7;
const size_t kNumMonthsPerYear = 12;
const size_t kNumLabels = 5;
const size_t numberOfPages = (sizeof(homepage) / sizeof(char)) / kNumLCDChars;
const String days[kNumSupportedLanguages][kNumDaysPerWeek] = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "zo", "ma", "di", "wo", "do", "vr", "za";
const String months[kNumSupportedLanguages][kNumMonthsPerYear] = "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "jan", "feb", "mrt", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec";
const String labels[kNumLabels] = "T", "RH", "DP", "D", "Wk";
const char degreesSymbol = 223;
enum languages_t EN, NL;
enum degreesFormats_t CELSIUS, FAHRENHEIT;
enum hourFormats_t HourFormat12, HourFormat24;
typedef struct
uint8_t hourFormat; // 12 or 24 hour format (AM/PM is not displayed)
uint8_t language; // The language for several labels
uint8_t degreesFormat; // Celsius or Fahrenheit
boolean labels; // Display temperature, weeknumber and daynumber with label
Settings;
Settings settings = HourFormat24, NL, CELSIUS, true;
unsigned long previousMillis = 0; // will store last time lcd was updated (page 1)
unsigned long oldMillis = 0; // will store last time lcd switched pages
TimeChangeRule myDST = "MDT", Last, Sun, Mar, 2, 2 * 60; //Daylight time/Summertime = UTC + 2 hours
TimeChangeRule mySTD = "MST", Last, Sun, Oct, 2, 1 * 60; //Standard time/Wintertime = UTC + 1 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev
int language_id;
int rowX = 0;
int rowY = 2;
float tem;
float hum;
float dew;
const long refreshRate = 1000;
const long switchPages = 3000;
void setup()
Serial.begin(9600);
lcd.begin(kNumLCDCols, kNumLCDRows);
// setSyncProvider() causes the Time library to synchronize with the
// external RTC by calling RTC.get() every five minutes by default.
setSyncProvider(RTC.get);
if (timeStatus() != timeSet) lcd << ("RTC SYNC FAILED");
pinMode(kLPin, OUTPUT);
digitalWrite(kLPin, LOW);
void loop()
mainLoop();
void mainLoop()
// check to see if it's time to refresh the lcd; that is, if the difference
// between the current time and last time you refreshed the lcd is bigger than
// the interval at which you want to refresh the lcd.
unsigned long currentMillis = millis();
defineLanguageId();
tem = dht.readTemperature();
hum = dht.readHumidity();
if (currentMillis - previousMillis >= refreshRate)
// save the last time you refreshed the lcd
previousMillis = currentMillis;
// display the date and time according to the specificied order with the specified settings
displayPage(rowX, rowY);
if (currentMillis - oldMillis >= switchPages)
oldMillis = currentMillis;
if (rowY == numberOfPages * 2)
rowX = 0;
rowY = 2;
lcd.clear();
else
rowX += 2;
rowY += 2;
lcd.clear();
void displayPage(int rowStart, int rowEnd)
time_t utc, local;
utc = now();
local = myTZ.toLocal(utc, &tcr);
// calculate which day and week of the year it is, according to the current local time
DayWeekNumber(year(local), month(local), day(local), weekday(local));
lcd.setCursor(0, 0);
// for-loop which loops through each row
for (int row = rowStart; row < rowEnd; row++)
// if row == odd, then we are on the second line, so move the cursor of the lcd
if (not(row % 2 == 0)) lcd.setCursor(0, 1);
// for-loop which loops through each char in row
for (int pos = 0; pos < 15; pos++)
displayDesiredFunction(row, pos, local);
void displayDesiredFunction(int row, int pos, time_t l)
switch (homepage[row][pos]) '
break;
case ' ':
displayDelimiter(' '); // display ' '
break;
void displayHours(time_t l)
(settings.hourFormat == HourFormat24) ? printI00(hour(l)) : printI00(hourFormat12(l));
void displayTemperature()
if (settings.labels)
lcd << labels[0] << ": ";
lcdDisplayTempDew(tem);
void displayHumidity()
if (settings.labels)
lcd << labels[1] << ": ";
lcd << int(hum) << "%";
void displayDewPoint()
dew = calculateDewPoint(tem, hum);
if (settings.labels)
lcd << labels[2] << ": ";
lcdDisplayTempDew(dew);
void lcdDisplayTempDew(float val)
(settings.degreesFormat == CELSIUS) ? lcd << int(val) << degreesSymbol << "C" : lcd << celsiusToFahrenheit(val) << (char)223 << "F";
float calculateDewPoint(float t, float h)
float a = 17.271;
float b = 237.7;
float temp = (a * t) / (b + t) + log(h * 0.01);
float Td = (b * temp) / (a - temp);
return Td;
void displayWeekday(int val)
lcd << days[language_id][val - 1];
void displayNumber(char val)
if (val == 'd')
if (settings.labels == true)
lcd << labels[3] << ": ";
printI00(DW[0]);
else
if (settings.labels == true)
lcd << labels[4] << ": ";
printI00(DW[1]);
void displayMonthShortStr(int val)
lcd << months[language_id][val];
void displayLocation()
//lcd << settings.location;
void defineLanguageId()
switch (settings.language)
case EN:
language_id = 0;
break;
case NL:
language_id = 1;
void printI00(int val)
if (val < 10) lcd << '0';
lcd << _DEC(val);
void displayDelimiter(char delim)
lcd << delim;
void setTimeRTC(unsigned int hours, unsigned int minutes, unsigned int seconds, unsigned int d, unsigned int m, unsigned int y)
setTime(hours, minutes, seconds, d, m, y);
RTC.set(now());
int celsiusToFahrenheit(const float celsius)
return static_cast<int>(celsius * 1.8 + 32);
Date.h:
short DW[2];
void DayWeekNumber(unsigned int y, unsigned int m, unsigned int d, unsigned int w)
int ndays = 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334; // Number of days at the beginning of the month in a not leap year.
int numLeapDaysToAdd = 0;
if ((y % 4 == 0 && y % 100 != 0)
c++ datetime arduino
edited Jan 17 at 16:01
200_success
123k14143401
123k14143401
asked Jan 17 at 14:37
Sebastiaan Speck
462
462
In your previous question you said in a comment that the code was in C. Is it now still in C? Then you should remove the C++ tag.
â mkrieger1
Jan 17 at 15:21
@mkrieger1 This looks like C++ to me, not C (for example, there is nostatic_cast
in C).
â Ben Steffan
Jan 17 at 16:10
Okay, then the comment was wrong.
â mkrieger1
Jan 17 at 16:18
This is written for Arduino. ItâÂÂs C but the static_cast does work. Therefore I placed it under C and C++
â Sebastiaan Speck
Jan 17 at 16:42
When you're using the arduino development environment, and external libraries you're using C++ e.g.Serial.begin()
...
â Harald Scheirich
Jan 18 at 11:52
add a comment |Â
In your previous question you said in a comment that the code was in C. Is it now still in C? Then you should remove the C++ tag.
â mkrieger1
Jan 17 at 15:21
@mkrieger1 This looks like C++ to me, not C (for example, there is nostatic_cast
in C).
â Ben Steffan
Jan 17 at 16:10
Okay, then the comment was wrong.
â mkrieger1
Jan 17 at 16:18
This is written for Arduino. ItâÂÂs C but the static_cast does work. Therefore I placed it under C and C++
â Sebastiaan Speck
Jan 17 at 16:42
When you're using the arduino development environment, and external libraries you're using C++ e.g.Serial.begin()
...
â Harald Scheirich
Jan 18 at 11:52
In your previous question you said in a comment that the code was in C. Is it now still in C? Then you should remove the C++ tag.
â mkrieger1
Jan 17 at 15:21
In your previous question you said in a comment that the code was in C. Is it now still in C? Then you should remove the C++ tag.
â mkrieger1
Jan 17 at 15:21
@mkrieger1 This looks like C++ to me, not C (for example, there is no
static_cast
in C).â Ben Steffan
Jan 17 at 16:10
@mkrieger1 This looks like C++ to me, not C (for example, there is no
static_cast
in C).â Ben Steffan
Jan 17 at 16:10
Okay, then the comment was wrong.
â mkrieger1
Jan 17 at 16:18
Okay, then the comment was wrong.
â mkrieger1
Jan 17 at 16:18
This is written for Arduino. ItâÂÂs C but the static_cast does work. Therefore I placed it under C and C++
â Sebastiaan Speck
Jan 17 at 16:42
This is written for Arduino. ItâÂÂs C but the static_cast does work. Therefore I placed it under C and C++
â Sebastiaan Speck
Jan 17 at 16:42
When you're using the arduino development environment, and external libraries you're using C++ e.g.
Serial.begin()
...â Harald Scheirich
Jan 18 at 11:52
When you're using the arduino development environment, and external libraries you're using C++ e.g.
Serial.begin()
...â Harald Scheirich
Jan 18 at 11:52
add a comment |Â
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185315%2fdigital-clock-with-many-functions-follow-up%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
In your previous question you said in a comment that the code was in C. Is it now still in C? Then you should remove the C++ tag.
â mkrieger1
Jan 17 at 15:21
@mkrieger1 This looks like C++ to me, not C (for example, there is no
static_cast
in C).â Ben Steffan
Jan 17 at 16:10
Okay, then the comment was wrong.
â mkrieger1
Jan 17 at 16:18
This is written for Arduino. ItâÂÂs C but the static_cast does work. Therefore I placed it under C and C++
â Sebastiaan Speck
Jan 17 at 16:42
When you're using the arduino development environment, and external libraries you're using C++ e.g.
Serial.begin()
...â Harald Scheirich
Jan 18 at 11:52