Formatting Millis to display dd:hh:mm:ss

Hi,

Noob in the noob-class here, and I’ve researched and tried different code for about a week now.

I’m trying to get a I2C 20x4 LCD display (PCF8574T) to display a count up timer using an UNO, in the 00:00:00:00 format, rather than 0:0:0:0. I’m doing a biltong box (drying box) (and will add 12V fan and 12V bulbs later on and some if statements to control them) and need a timer to know how long the meat has been in.

I found code that does what I want it to do, without any issues such as the second counter moving one place to the left, leaving the digit on the right (in the ‘one’s’ place) and doing silly things like displaying 19,29,39,49,59,69,79 etc). Dealing with the problem by using lcd.print(" ") and lcd.clear caused issues such as bad flickering and the digits to disappear.

Only problem with the code is that it doesn’t include ‘days’. Only hh:mm:ss, so I’ve adapted it to what I think it should be. Testing it involves waiting at least 24 hours for every test.

So I’m basically just asking if I’m doing over flow from the hours to days right. Sorry for being long-winded.

#include <dht11.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>



/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
dht11 DHT11;

/*-----( Declare Constants, Pin Numbers )-----*/
#define DHT11PIN 2

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600); //(Remove all 'Serial' commands if not needed)
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.backlight();
  lcd.print("Biltong Box");

}/*--(end setup )---*/

void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{


  int chk = DHT11.read(DHT11PIN);

  Serial.print("Read sensor: ");
  switch (chk)
  {
    case 0: Serial.println("OK"); break;
    case -1: Serial.println("Checksum error"); break;
    case -2: Serial.println("Time out error"); break;
    default: Serial.println("Unknown error"); break;
  }


//TEMPERATURE  
  lcd.setCursor(0, 1);

  lcd.print((char)223);
  lcd.print("C:");
  lcd.print((float)DHT11.temperature, 0);
  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);

  lcd.print("  H=");
  lcd.print((float)DHT11.humidity, 0);
  lcd.print("%");
  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);  

  Serial.print("Temperature (K): ");
  Serial.println(Kelvin(DHT11.temperature), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(dewPoint(DHT11.temperature, DHT11.humidity));

  Serial.print("Dew PointFast (oC): ");
  Serial.println(dewPointFast(DHT11.temperature, DHT11.humidity));

  delay(2000);

//TIMER

 char *s;
 s = TimeToString(millis()/1000);
 lcd.setCursor(0,4);
 lcd.print(s);
 delay(456);

  
}/* --(end main loop )-- */

/*-----( Declare User-written Functions )-----*/

// t is time in seconds = millis()/1000;
char * TimeToString(unsigned long t)
{
 static char str[12];
 
 long h = t / 3600;
 long d = h / 24;
 t = t % 3600;
 int m = t / 60;
 int s = t % 60;
 sprintf(str, "%02ld:%02ld:%02d:%02d", d, h, m, s);
 return str;
}


//
//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
        return 1.8 * celsius + 32;
}

//Celsius to Kelvin conversion
double Kelvin(double celsius)
{
        return celsius + 273.15;
}

// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm 
double dewPoint(double celsius, double humidity)
{
        double A0= 373.15/(273.15 + celsius);
        double SUM = -7.90298 * (A0-1);
        SUM += 5.02808 * log10(A0);
        SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;
        SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ;
        SUM += log10(1013.246);
        double VP = pow(10, SUM-3) * humidity;
        double T = log(VP/0.61078);   // temp var
        return (241.88 * T) / (17.558-T);
}

// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

/* ( THE END ) */

The serial.print is just so I can collect data to analyse later.

::
  sprintf(str, "%2ld:%2ld:%2d:%2d", d, h, m, s);
  replace(str, ' ', '0');
  return str;
::

You can also save a tiny bit of performance and RAM - get rid of the longs - as d,h,m,s won't exceed char values.

lastchancename:

::

sprintf(str, "%2ld:%2ld:%2d:%2d", d, h, m, s);
  replace(str, ' ', '0');
  return str;
::



**You can also save a tiny bit of performance and RAM - get rid of the longs - as d,h,m,s won't exceed char values.**

Thanks.

If this was my project I would have 4 variables for the date, hour, minutes and seconds. Whenever millis() increases by 1000 I would increase the seconds value by 1. When the seconds value gets to 60 I would increase the minutes value by 1 and set the seconds value back to 0. etc,

For display purposes I would just do

Serial.print(data);
Serial.print(:);
Serial.print(hour);
etc

...R

Robin2:
If this was my project I would have 4 variables for the date, hour, minutes and seconds. Whenever millis() increases by 1000 I would increase the seconds value by 1. When the seconds value gets to 60 I would increase the minutes value by 1 and set the seconds value back to 0. etc,

For display purposes I would just do

Serial.print(data);

Serial.print(:);
Serial.print(hour);
etc




...R

You mean with if statements and ++? Sorry, I’m not kidding when I say I’m a noob’s noob.

kriekit:
You mean with if statements and ++? Sorry, I'm not kidding when I say I'm a noob's noob.

Yes. Have a go at it and if you can't get it to work then post your code.

You can get the seconds from millis() like this

if (millis() - prevSecond >= 1000) {
   prevSecond += 1000;
   seconds ++;
   if (seconds >= 60) {
      minutes ++;
      seconds = 0;
   }
   if (minutes > = 60 .....

}

All the variables, such as prevSecond connected with millis() should be defined as unsigned long.

A byte variable will be sufficient for your seconds, minutes, hour and day-of-month

...R

Robin2:
Yes. Have a go at it and if you can't get it to work then post your code.

You can get the seconds from millis() like this

if (millis() - prevSecond >= 1000) {

prevSecond += 1000;
  seconds ++;
  if (seconds >= 60) {
      minutes ++;
      seconds = 0;
  }
  if (minutes > = 60 .....

}




All the variables, such as prevSecond connected with millis() should be defined as unsigned long.

A byte variable will be sufficient for your seconds, minutes, hour and day-of-month


...R

Will try, thanx!

I would do it like:

void loop(){
  unsigned long time = millis();
  
  printLeading(Serial, time / (24 * 60 * 60 * 1000UL));
  Serial.print(':');
  printLeading(Serial, time / (60 * 60 * 1000UL) % 24);
  Serial.print(':');
  printLeading(Serial, time / (60 * 1000UL) % 60);
  Serial.print(':');
  printLeading(Serial, time / 1000UL % 60);
}


void printLeading(Stream &out, unsigned int in){
  if(in < 10){
    out.print('0');
  }
  out.print(in);
}

septillion:
I would do it like:

void loop(){

unsigned long time = millis();
 
  printLeading(Serial, time / (24 * 60 * 60 * 1000UL));
  Serial.print(’:’);
  printLeading(Serial, time / (60 * 60 * 1000UL) % 24);
  Serial.print(’:’);
  printLeading(Serial, time / (60 * 1000UL) % 60);
  Serial.print(’:’);
  printLeading(Serial, time / 1000UL % 60);
}

void printLeading(Stream &out, unsigned int in){
  if(in < 10){
    out.print(‘0’);
  }
  out.print(in);
}

Will check it out, thank you.

septillion:
I would do it like:

That seems to calculate all the values every time they are printed. But most of the values will be the same as the last time

…R

Buy a little RTC and use EEPROM to 'remember' what state you are in.

Use the time library, worry not about power loss.

The code above is cute but you should be displaying the start time, current time and elapsed time. Easily managed with an RTC.

BulldogLowell:
Buy a little RTC and use EEPROM to 'remember' what state you are in.

Use the time library, worry not about power loss.

The code above is cute but you should be displaying the start time, current time and elapsed time. Easily managed with an RTC.

Thanks for the response, Bull. I've considered it, but that's really going overboard. I really just need to hang the meat for 3-4 days. This is basically just a fun project to get back into coding (I had one module of C programming during a CCNA + Networking course that ended last year). But I will definitely do that on any project that requires more accurate time-keeping.

The code I posted finally rolled over to 1 day successfully, but it left the hours as 24. Can anyone tell me how to fix that.

(I realized too late that I could have changed the calc for millis to 100 instead of 1000, to speed the testing process up.

kriekit:
The code I posted

Where did you post it?

...R

The original post, but here it is again.

#include <dht11.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>



/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
dht11 DHT11;

/*-----( Declare Constants, Pin Numbers )-----*/
#define DHT11PIN 2

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600); //(Remove all 'Serial' commands if not needed)
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.backlight();
  lcd.print("Biltong Box");

}/*--(end setup )---*/

void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{


  int chk = DHT11.read(DHT11PIN);

  Serial.print("Read sensor: ");
  switch (chk)
  {
    case 0: Serial.println("OK"); break;
    case -1: Serial.println("Checksum error"); break;
    case -2: Serial.println("Time out error"); break;
    default: Serial.println("Unknown error"); break;
  }


//TEMPERATURE 
  lcd.setCursor(0, 1);

  lcd.print((char)223);
  lcd.print("C:");
  lcd.print((float)DHT11.temperature, 0);
  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);

  lcd.print("  H=");
  lcd.print((float)DHT11.humidity, 0);
  lcd.print("%");
  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2); 

  Serial.print("Temperature (K): ");
  Serial.println(Kelvin(DHT11.temperature), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(dewPoint(DHT11.temperature, DHT11.humidity));

  Serial.print("Dew PointFast (oC): ");
  Serial.println(dewPointFast(DHT11.temperature, DHT11.humidity));

  delay(2000);

//TIMER

 char *s;
 s = TimeToString(millis()/1000);
 lcd.setCursor(0,4);
 lcd.print(s);
 delay(456);

 
}/* --(end main loop )-- */

/*-----( Declare User-written Functions )-----*/

// t is time in seconds = millis()/1000;
char * TimeToString(unsigned long t)
{
 static char str[12];
 
 long h = t / 3600;
 long d = h / 24;
 t = t % 3600;
 int m = t / 60;
 int s = t % 60;
 sprintf(str, "%02ld:%02ld:%02d:%02d", d, h, m, s);
 return str;
}


//
//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
        return 1.8 * celsius + 32;
}

//Celsius to Kelvin conversion
double Kelvin(double celsius)
{
        return celsius + 273.15;
}

// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm
double dewPoint(double celsius, double humidity)
{
        double A0= 373.15/(273.15 + celsius);
        double SUM = -7.90298 * (A0-1);
        SUM += 5.02808 * log10(A0);
        SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;
        SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ;
        SUM += log10(1013.246);
        double VP = pow(10, SUM-3) * humidity;
        double T = log(VP/0.61078);   // temp var
        return (241.88 * T) / (17.558-T);
}

// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
        double a = 17.271;
        double b = 237.7;
        double temp = (a * celsius) / (b + celsius) + log(humidity/100);
        double Td = (b * temp) / (a - temp);
        return Td;
}

/* ( THE END ) */

kriekit:
The original post, but here it is again.

Please restore the Original Post to its orginal code so that readers can make sense of the Thread.

...R

I believe the suggestion I made in Reply #3 and Reply #5 would not have had the problem you mentioned in Reply #12

…R

add

h %= 24;

Robin2:
Please restore the Original Post to its orginal code so that readers can make sense of the Thread.

...R

It displays with code tags in my post - I don't understand why it's showing incorrectly?

Robin2:
I believe the suggestion I made in Reply #3 and Reply #5 would not have had the problem you mentioned in Reply #12

...R

I'm still trying to incorporate suggestions into my code - very much noob.

septillion:
add

h %= 24;

I will try that, thank you.

kriekit:
It displays with code tags in my post - I don't understand why it's showing incorrectly?

What he means is that you should never ever change a post to add information or "update" the code. Edit is for when you made a typo etc. Updates and extra info go into a new post.