Digital clock with many functions - follow-up

The name of the pictureThe name of the pictureThe name of the pictureClash 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)






share|improve this question





















  • 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
















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)






share|improve this question





















  • 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












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)






share|improve this question













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)








share|improve this question












share|improve this question




share|improve this question








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 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
















  • 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















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















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















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



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














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













































































Popular posts from this blog

Chat program with C++ and SFML

Function to Return a JSON Like Objects Using VBA Collections and Arrays

Will my employers contract hold up in court?