Hi all. I am fairly new to the coding scene and am working on a sketch to display run time of a compressor motor. I have created the sketch and it works ok. I am using the millis function to count the time, i can convert the milliseconds to hours no problem but the issue is im using hours as a int (id like to stay away from floats) and i want the hours to display with one place after the decimal. So basically every 6 minutes (360seconds) i want the counter to increase by 0.1. The best i can get the code to work is to have it display 1 hour every 3600 seconds.
Is there anyway i can do this? or do i have to use float type?
you can scale up your hours by factor 10
so 3 hours would be 30 and then displaying 3.0
1451.8 hours would be 14518 and a display-function could create the charactersequence "1451.8"
best regards Stefan
Thank you for your reply. Thats actually how i wanted to do it. So how would i go about displaying 30 as 3.0? i try to divide by ten but that dont work?
@OP
The following codes may be helpful to you.
const long interval = 200L;//200UL;//11250UL;//45000;//90000UL;//180000UL;//360000UL; (test value)
unsigned long previousMillis;
byte hour; //hour = 00
byte myHr;
byte hrArray[3];
void setup()
{
Serial.begin(9600);
previousMillis = millis();
}
void loop()
{
if (millis() - previousMillis >= interval) //for 6 min chane interval to 3600000UL
{
previousMillis = millis();
hour = hour + 1; //6 minute is added as 0.1
myHr = hour;
for (int i = 0; i < 3; i++)//getting BCD values for the digits x, y, z of xy.z
{
hrArray[i] = myHr % 10;
myHr = myHr / 10;
}
if (((hrArray[2] << 4) + hrArray[1]) == 0x24)//checking 24.0 hrs before print time and reset
{
hrArray[2] = 0x00;
hrArray[1] = 0x00;
hrArray[0] = 0x00;
hour = 0x00;
}
//----------------------------------------
if (hrArray[2] != 0)
{
Serial.print(hrArray[2], HEX);
Serial.print(hrArray[1], HEX);
Serial.print('.');
Serial.println(hrArray[0], HEX);
}
else //suppressing one leading 0
{
Serial.print(hrArray[1], HEX);
Serial.print('.');
Serial.println(hrArray[0], HEX);
}
}
}


unsigned deciHours = 112; // 11.2 hours (holds up to 6553.5 hours. Use 'unsigned long' for longer times.)
Serial.print(deciHours / 10u); // Print the full hours part
Serial.print('.'); // Print the decimal point
Serial.println(deciHours % 10); // Print the tenths digit
@johnwasser
Cannot follow exactly!
If full codes could be made available, then an effort could be employed to understand the program logic.
GolamMostafa:
@johnwasser
Cannot follow exactly!
If full codes could be made available, then an effort could be employed to understand the program logic.
OK:
unsigned deciHours = 112; // 11.2 hours (holds up to 6553.5 hours. Use 'unsigned long' for longer times.)
void setup()
{
Serial.begin(115200);
Serial.print(deciHours / 10u); // Print the full hours part
Serial.print('.'); // Print the decimal point
Serial.println(deciHours % 10); // Print the tenths digit
}
void loop() {}
[edit]While making this reply my PC decided to be stubborn. So I already made a MCVE of johnwasser's code before he did...[/edit]
The logic of @johnwasser is a heck easier to understand than all the HEX nonsense.... Although your method is basically fine, the implementation is wayyyy overcomplicated.
Stripped down version:
const unsigned long interval = 200;//11250UL;//45000;//90000UL;//180000UL;//360000UL; (test value)
unsigned long previousMillis;
byte hour; //hour = 00
void setup()
{
Serial.begin(115200);
previousMillis = millis();
}
void loop()
{
if (millis() - previousMillis >= interval) //for 6 min change interval to 3600000UL
{
previousMillis = millis();
hour = hour + 1; //6 minute is added as 0.1
//checking 24.00 hrs and reset
if(hour == 240){
hour = 0;
}
byte myHr = hour;
byte hrArray[3];
for (int i = 0; i < 3; i++)//getting BCD values for the digits x, y, z of xy.z
{
hrArray[i] = myHr % 10;
myHr = myHr / 10;
}
if (hrArray[2] != 0)
{
Serial.print(hrArray[2]);
}
Serial.print(hrArray[1]);
Serial.print('.');
Serial.println(hrArray[0]);
}
}
MVCE of johnwasser's version
const unsigned long interval = 200;//11250UL;//45000;//90000UL;//180000UL;//360000UL; (test value)
unsigned long previousMillis;
unsigned deciHours = 112; // 11.2 hours (holds up to 6553.5 hours. Use 'unsigned long' for longer times.)
void setup()
{
Serial.begin(115200);
previousMillis = millis();
}
void loop()
{
if (millis() - previousMillis >= interval) //for 6 min change interval to 3600000UL
{
previousMillis = millis();
deciHours++; //6 minute is added as 0.1
Serial.print(deciHours / 10u); // Print the full hours part
Serial.print('.'); // Print the decimal point
Serial.println(deciHours % 10); // Print the tenths digit
}
}
And my implementation (which makes adding more decimals easy):
const unsigned long interval = 200;//11250UL;//45000;//90000UL;//180000UL;//360000UL; (test value)
unsigned long previousMillis;
unsigned deciHour = 112; // 11.2 hours (holds up to 6553.5 hours. Use 'unsigned long' for longer times.)
void setup()
{
Serial.begin(115200);
previousMillis = millis();
}
void loop()
{
if (millis() - previousMillis >= interval) //for 6 min change interval to 3600000UL
{
previousMillis = millis();
deciHour++; //6 minute is added as 0.1
char hourStr[8];
itoa(deciHour, hourStr, 10);
byte n = strlen(hourStr) + 1;
for(byte i = 0; i <= 1; i++){
n--;
hourStr[n + 1] = hourStr[n];
}
hourStr[n] = '.';
Serial.println(hourStr);
}
}
So multiple ways to fix it
@septillion
The logic of @johnwasser is a heck easier to understand than all the HEX nonsense.... Although your method is basically fine, the implementation is wayyyy overcomplicated.
This is the output for the codes of @johnwasser that you have supplied (Is it working!?).

This is the output for the codes of @septillion that you have supplied (Is it working!?)



const long interval = 200UL;
What's the 'U' for?
@GolamMostafa I see perfectly working code 
Hint, it was you who made the implicit requirement for reset @ 24h
Something you probably don't want if we talk run time of a compressor. And if you want a reset, that's the easy part as I showed in the simplified version of your method.
septillion:
@GolamMostafa I see perfectly working code 
Hint, it was you who made the implicit requirement for reset @ 24h
Something you probably don't want if we talk run time of a compressor. And if you want a reset, that's the easy part as I showed in the simplified version of your method.
Fine! If the @OP wants to keep registering the accumulated run time, then codes both of @septillion and @johnwasser are working alright.
TheMemberFormerlyKnownAsAWOL:
const long interval = 200UL;
What's the 'U' for?
Either U (for unsigned) should be removed or the modifier "unsigned" should go before the data type long. I recognize my mistake. I have edited my post.
Thank you very much.
Thanks all. I have come up with the following code
/* This code will need to run oncce an input is detected
for now it will be a button. The sketch will use the mills
fuction once it reaches 6000 it will need to add 1 to the counter. The mills will then need to reset.
*/#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27,16,2); //lcd address
const int swtch = 2;
unsigned long runTime = 0;
int eeAddress = 0;
unsigned long aHours ;
unsigned hours;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(swtch, INPUT);
lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("Hours");
aHours = EEPROM.get(eeAddress, hours);
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long currentTime= millis();
static unsigned long pressStartTime = 0;
int buttonState = digitalRead(swtch);
static int lastButtonState = LOW;
if (buttonState != lastButtonState){
// The button state has changed
if (buttonState == HIGH){
//button freshly pressed
pressStartTime = currentTime;
}
else // button freshly released
{runTime += (currentTime-pressStartTime);
}
lastButtonState = buttonState;
Serial.println(runTime);
}
unsigned long elapsedTime = runTime;
if (buttonState == HIGH) //counting
{
elapsedTime += (currentTime - pressStartTime);
}
// display run time
hours = (elapsedTime/1000) + aHours;
Serial.println(hours);
lcd.setCursor(7,0);
lcd.print(hours);
//display elapsed time in hours
EEPROM.put(eeAddress,hours);
}
In line 72 "hours = (elapsedTime/1000) + aHours" the hours value increments by 1 for one second. ( i am just using one second now to make testing the code faster this will eventually be 360000 for the hour value to increase every six minutes). What i want to happen is the hour value to increase by 0.1 each time instead of increasing by 1. I also want the hour value to write to the EEPROM every time the hour value changes. Do i have this done correctly in the code or do the way i have it done update the EEPROM each time through the loop?
Thanks for all the help
@ryan_brown17 As @StefanL38 suggested in reply #1 and we (the rest) all agreed upon is that it's easier to keep track of deci-hours (aka, 1/10th of an hour) and just insert a decimal point when needed.
Is it with a reason you keep 'elapsedTime' and 'runTime'? Aka, do you want to display both total runtime and current runtime?
And yeah, by using EEPROM.put() the value is only written when it changed.
Just scanned your code and cleaned it up a bit. Made no real changes, just a couple of small once but mainly made it more readable.
/* This code will need to run oncce an input is detected
for now it will be a button. The sketch will use the mills
fuction once it reaches 6000 it will need to add 1 to the counter. The mills will then need to reset.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27,16,2); //lcd address
const byte SwitchPin = 2;
const int EeAddress = 0;
unsigned long runTime = 0;
unsigned long aHours ;
unsigned long hours;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(SwitchPin, INPUT);
lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("Hours");
aHours = EEPROM.get(EeAddress, hours);
}
void loop() {
static bool lastButtonState = LOW;
static unsigned long pressStartTime = 0;
const unsigned long CurrentTime = millis();
const bool ButtonState = digitalRead(SwitchPin);
// The button state has changed
if (ButtonState != lastButtonState) {
//button freshly pressed
if (ButtonState == HIGH){
pressStartTime = CurrentTime;
}
// button freshly released
else {
runTime += (CurrentTime - pressStartTime);
}
lastButtonState = ButtonState;
Serial.println(runTime);
}
unsigned long elapsedTime = runTime;
//counting
if (ButtonState == HIGH) {
elapsedTime += (CurrentTime - pressStartTime);
}
// display run time in hours
hours = (elapsedTime/1000) + aHours;
Serial.println(hours);
lcd.setCursor(7,0);
lcd.print(hours);
EEPROM.put(EeAddress, hours);
}
My quick go at it:
/* This code will need to run oncce an input is detected
for now it will be a button. The sketch will use the mills
fuction once it reaches 6000 it will need to add 1 to the counter. The mills will then need to reset.
*/
//#include <Wire.h>
//#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#define lcd_setCursor(x,y) Serial.print("Cursor: ");Serial.print(x);Serial.print(", ");Serial.println(y)
#define lcd_print(x) Serial.print("Print: ");Serial.println(x)
#define lcd_init() Serial.println("lcd Init")
#define lcd_backlight() Serial.println("Backlight")
//LiquidCrystal_I2C lcd(0x27,16,2); //lcd address
const byte SwitchPin = 2;
const int EeAddress = 0;
const unsigned long DeciHourInterval = 1000; //360000 for 6 minutes
unsigned long totalRunTime; //in deciHour
unsigned long currentRunTime; //in deciHour
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(SwitchPin, INPUT_PULLUP);
lcd_init();
lcd_backlight();
lcd_setCursor(0,0);
lcd_print("Total");
lcd_setCursor(0,0);
lcd_print("Current");
EEPROM.get(EeAddress, totalRunTime);
//reset if EEPROM is fresh or we are at our limits
if(totalRunTime >= 42949672){
totalRunTime = 0;
}
//make it deciHoud
totalRunTime *= 10;
printStates(false);
}
void loop() {
static bool lastSwitchState = LOW;
static unsigned long switchMillis = 0;
const unsigned long CurrentMillis = millis();
const bool SwitchState = digitalRead(SwitchPin);
// The switch state has changed
if (SwitchState != lastSwitchState) {
//switch freshly turned on
if (SwitchState == HIGH){
switchMillis = CurrentMillis;
currentRunTime = 0;
}
else{
printStates(false);
}
lastSwitchState = SwitchState;
}
if ((SwitchState == HIGH) && (CurrentMillis - switchMillis >= DeciHourInterval)) {
switchMillis = CurrentMillis;
//increment timers
totalRunTime++;
currentRunTime++;
//and print it
printStates(true);
//update EEPROM is needed
EEPROM.put(EeAddress, totalRunTime / 10);
Serial.println();
}
}
/*
char* getHourStr2(unsigned long h){
static char hourStr[12];
itoa(h, hourStr, 10);
byte n = strlen(h) + 1;
for(byte i = 0; i <= 1; i++){
n--;
hourStr[n + 1] = hourStr[n];
}
hourStr[n] = 'h';
return hourStr;
}*/
char* getHourStr(unsigned long h){
static char hourStr[12];
itoa(h / 10, hourStr, 10);
byte n = strlen(hourStr);
hourStr[n] = 'h';
itoa(h % 10, hourStr + n + 1, 10);
return hourStr;
}
void printStates(bool on){
lcd_setCursor(8,0);
lcd_print(getHourStr(totalRunTime));
lcd_setCursor(8,1);
lcd_print(" "); //be sure it's clear
lcd_setCursor(8,1);
if(on){
lcd_print(getHourStr(currentRunTime));
}
else{
lcd_print("Off");
}
}
Did test it with Serial only, so hope stuff is set right for lcd now 
Thanks for your help. I will try this code in the morning and let you know if it works with the lcd.
@Septillion. With regards to the following line of code
if ((SwitchState == HIGH) && (CurrentMillis - switchMillis >= DeciHourInterval)) {[color=#222222][/color]
switchMillis = CurrentMillis;
The issue im having is that when i press the button and the counters are counting up everything works as it should, but when i release the button for a period of time and press the button again it immediately counts up, im assuming that is because as soon as i press the button again the difference between the current millis and switchmillis is greater then 6000.