converting total seconds to hours, minutes and seconds...

Status
Not open for further replies.

vfxwolf

Well-known member
I would appreciate some assistance with this seemingly trivial thing.. I'm trying to convert a seconds time variable to corresponding hours, minutes and seconds. Its a countdown timer. Here's the code I found:

Code:
float h = 0;
float m = 0;
float s = 0;
long unsigned int remainingSeconds = 39600;

void loop();{

TimeCalc(remainingSeconds);

Serial.print(h); Serial.print(" ");Serial.print(m); Serial.print(" ");Serial.print(s);
remainingSeconds --
}

void TimeCalc( long unsigned int seconds ) {
  uint32_t t = seconds;

  s = t % 60;

  t = (t - s) / 60;
  m = t % 60;

  t = (t - m) / 60;
  h = t;
}

it seems to work fine starting with anything up to 9 hours 59 mins 59 seconds... counts down smoothly.. but start at 10 hours or more, and things get screwy.

I suspect my problem is some sort of variable mistyping.. but I'm new to arduino coding, and not sure how to track down the issue.

Appreciate the help.
 
you can google convert seconds to hours minutes seconds, maybe

Code:
    uint32_t h,m,s,rem,secs;
    secs = 39867;
    h = secs/3600;
    rem = secs%3600;
    m = rem/60;
    s = rem % 60;

or change your float's to int's

EDIT: The sketch you provided would not compile, so I assumed your function TimeCalc() was also broken. Later I fixed your sample sketch so it would compile, and the TimeCalc() function (even with float's) seems to properly print h,m,s on a T3.2 and UNO
 
Last edited:
Thanks manitou, but using your code snippet, I"m still having the same problem... counting down from 9 hours 6 minutes works fine.. but 9 hours and 7 minutes and above, and printing to the OLED gives me garbage...

BTW.. I'm printing with those same h, m, s variables..


you can google convert seconds to hours minutes seconds, maybe

Code:
    uint32_t h,m,s,rem,secs;
    secs = 39867;
    h = secs/3600;
    rem = secs%3600;
    m = rem/60;
    s = rem % 60;

or change your float's to int's
 
Might help to see your code: hint: 9 hours and 6 minutes is: 32760 seconds which which is fine for in a int16_t where as 9 hours 7 minutes is 32828 which does not fit in int16_t (would go negative)...
Should work with uint16_t which goes up to 65535...
 
Might help to see your code:..

I posted the code in my first post.. I've modified it now with Manitou's suggestion.. but it didnt seem to help. I'm aware that that trouble threshold is at the 32760 point - that was my first clue that it must be a variable typing issue. But now, as Manitou suggested, I've defined them as uint32_t... which should be more than enough, no?
 
Maybe I am missing something, but if I take the program and modify it and make it such that it compiles:
Code:
uint32_t h = 0;
uint32_t m = 0;
uint32_t s = 0;
long unsigned int remainingSeconds = 39600;
void setup(){
  while (!Serial)
  Serial.begin(115200); 
}
void loop() {

  TimeCalc(remainingSeconds);

  Serial.print(h); Serial.print(" "); Serial.print(m); Serial.print(" "); Serial.println(s);
  remainingSeconds --;
  delay(50);
}

void TimeCalc( long unsigned int secs ) {
  uint32_t rem;
  h = secs / 3600;
  rem = secs % 3600;
  m = rem / 60;
  s = rem % 60;
}

I appear to be getting the results:
Code:
11 0 0
10 59 59
10 59 58
10 59 57
10 59 56
10 59 55
10 59 54
10 59 53
10 59 52
10 59 51
10 59 50
10 59 49
10 59 48
10 59 47
10 59 46
10 59 45
10 59 44
10 59 43
10 59 42
10 59 41
10 59 40
10 59 39
10 59 38
10 59 37
10 59 36
10 59 35
10 59 34
10 59 33
10 59 32
10 59 31
10 59 30
10 59 29
10 59 28
10 59 27
10 59 26
10 59 25
...
 
Maybe I am missing something, but if I take the program and modify it and make it such that it compiles:

I appear to be getting the results:

Kurt,

You are correct.. the serial monitor will show the correct values, however, the OLED will not (pictures posted). As stated earlier, uint16 variables seem to have gotten me past the 9 hour 7 minute barrier, where, long unsigned int or uint32 types will not.

Unfortunately, I seem to be overflowing around 19 hours now...

I find this confusing, as 32 is double 16.. why can I not go to higher values with uint32 variables?
 
have you tried specifying uint32_t instead of unsigned long int? you didnt specify your mcu.

Yes... uint32_t errors out above 9hrs 6min. uint16_t is the only thing that got me to 18hrs 12mins. I'm developing on two platforms: Teensy 3.6 will be the target platform. Its currently being used to develop the stepper motor control algorithms, but I'm developing the menu system and front-end framework on a mega.. hoping to migrate over to the teensy next week. The issues I'm having at the moment are with the menu on the mega.
 
The compiler is stupid. It does what you tell it to do. You told it to multiply/divide ints and put that into an unsigned long.
try doing adding UL to your calculations.. example: 3600UL
also replace “unsigned long int” with uint32_t as well, as ints are different size between arduino and teensy, best to specify the type for portability purposes
Tony
 
Try the following:
Code:
static uint16_t days;
static uint8_t hours, minutes, seconds;

static void TimeCalc(uint32_t  secs)
{
    seconds = secs % (uint32_t)60;
    secs /= (uint32_t)60;
    minutes = secs % (uint32_t)60;
    secs /= (uint32_t)60;
    hours = secs % (uint32_t)24;
    days = secs / (uint32_t)32;
}

uint32_t  remainingSeconds = 70000; /* 0d 19h 26m 40s */

void setup(){
  while (!Serial)
      Serial.begin(115200); 
}

void loop() {

  TimeCalc(remainingSeconds);

  Serial.print(days);
  Serial.print("d ");
  Serial.print(hours);
  Serial.print("h ");
  Serial.print(minutes);
  Serial.print("m ");
  Serial.println(seconds);

  remainingSeconds --;
  delay(50);
}

The variable containing the number of seconds remaining, remainingSeconds, also has to be of sufficient size (i.e, uint32_t).

The explicit casts to (uint32_t) should not be necessary for sane C compilers, but they are safe, and are harmless (no slowdown or any other cost).
 
Nominal Animal,

I tried your approach. Here's the code now.. (excerpts from the main code)
Code:
//                                        Countdown variables



uint32_t remainingSeconds = 0;
uint8_t h   = 0;
uint8_t m   = 0;
uint8_t s   = 0;
uint8_t rem = 0;

TimeCalc(remainingSeconds);

    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds

static void TimeCalc(uint32_t  secs)
{
    s = secs % (uint32_t)60;
    secs /= (uint32_t)60;
    m = secs % (uint32_t)60;
    secs /= (uint32_t)60;
    h = secs % (uint32_t)24;
    
}

It runs right up to the same limit as the first iteration, but different - no garbage, just complete inaccuracy:).

If I start the countdown at 9hrs 6min.. I get an accurate countdown... all the way to zero. Start at 9hrs 7min.. and the countdown starts at 21 hours 22 minutes??????

There's obviously some kind of rollover happening... but where?
 
There's obviously some kind of rollover happening... but where?

If you do not give the WHOLE code, how can we find the problem?
Don't say it is the same. Also, code in post #1 is not complete (setup() is missing) .

have you copied Normal Animal's or KurtE's code exactly as presented (cut and past)? Does t work for you? AFAIK, a Mega has a different architecture than a Teensy.

At one post you are saying serial monitor gives correct values but display not. So, it is a problem with display interface, right?

can you give screen shots (pictures) of serial monitor and display values from the same program?

As Paul always says, we cannot see you screen and details matter.
 
WXMZ,

I have posted pictures of the screen in a previous post in this thread. Are they not showing for you?

As for posting the code, I didn’t think it necessary to post the other 400 lines of code when the issue could only involve the variables and functions that are involved in calculating and displaying the time - that code I’ve posted.

I have applied every suggestion posted thus far - and given updates on the results. If I’ve been unclear, please let me know what other information I could provide.

As for the architecture - no doubt there are differences - but I thought both were Arduino compatible - within reason. Understand that the problem I’m having is happening on the Mega - I will be moving the code over to the teensy in a few days. I believe the issue is logic, not hardware related - but I may be wrong.
 
WXMZ,

I have posted pictures of the screen in a previous post in this thread. Are they not showing for you?

As for posting the code, I didn’t think it necessary to post the other 400 lines of code when the issue could only involve the variables and functions that are involved in calculating and displaying the time - that code I’ve posted.

I have applied every suggestion posted thus far - and given updates on the results. If I’ve been unclear, please let me know what other information I could provide.

As for the architecture - no doubt there are differences - but I thought both were Arduino compatible - within reason. Understand that the problem I’m having is happening on the Mega - I will be moving the code over to the teensy in a few days. I believe the issue is logic, not hardware related - but I may be wrong.

clicking on the attachments says "Invalid Attachment specified"

400 lines? that is exactly the problem. somewhere in there is an error.

So,
the standard procedures in these cases are
- start from working example, here serial.printf and augment functionality, here add display.printf
or if you want help finding you problem
- remove all non problem relevant code to a bare minimum.
doing this, you will in most cases find you problem yourself, otherwise, someone else can
a) reproduce the issue (Forum rule)
b) find a solution.

as fo architecture:
Paul did a great job to make teensy compatible to Arduino-avr, but it cannot be said that Arduino avr is maintaining or even aiming for compatibility to 32 bit arm. (I'm not worried about the sketch SW but the display lbrary)
 
if serial monitor reports fine, and display rolls over, your display library must be processing the 32bit ints as 16bits, or chunking on 8bit data instead, who knows.... lack of display info, lack of library, all we have here are working time snippets for serial monitor :)
 
WMXZ and tonton81, points taken.

tonton81, I suspect you may be on to something there.. the display library may be the culprit. Here is the complete code for the GUI, currently being compiled on the Mega. As stated earlier, I'm also developing motor control on the Teensy, and the plan is to merge the GUI onto the Teensy later this week.

The functions of interest are: TimeCalc() and LapseModeRun() which gets its variables set in LapseModeSet().
Code:
/*


  List of fonts: https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts






  If you have the 128x64 version, you need to edit the file called Adafruit_SSD1306.h that is on the
  Adafruit_SSD1306-master folder. The library comes by default set to use the 128x32 display.
  For this reason you need to define the correct resolution like this:
  Quote:
   #define SSD1306_128_64
  //   #define SSD1306_128_32
  //   #define SSD1306_96_16
  Unquote.
  Notes the "//" before each line to comment the other resolutions that we are not going to use.




*/






#include <Adafruit_GFX.h>  // Include core graphics library for the display
#include <Adafruit_SSD1306.h>  // Include Adafruit_SSD1306 library to drive the display
#include <Metro.h>
#include <Encoder.h>
#include <Bounce2.h>
#include <Fonts/FreeSans9pt7b.h>  // Add a custom font


Adafruit_SSD1306 display;  // Create display




int Variable1;  // Create a variable to have something dynamic to show on the display


//                                        Countdown variables


long unsigned int TotalSeconds = 0;
uint16_t remainingSeconds = 0;
uint16_t h   = 0;
uint16_t m   = 0;
uint16_t s   = 0;
uint16_t rem = 0;


//                                          Menu Variables
boolean hlight = 0;
int menuMax = 5;
int menuMode = 0;
int menuDelay = 500;
Metro blinkon = Metro(1000);
Metro blinkoff = Metro(1000);
Metro debounce = Metro(10);


//                                          Keyframe Variables


char StartingKey;
char EndingKey;


//                                          Encoder Variables


Encoder myEnc(2, 3);
int encState;
int encRead;                              //current encoder read
int encOld;                               //previous encoder read


const int EncButton = 4;                  //Pin # to which SW line is connected
byte oldButtonState = HIGH;               // set previous buttonestate to HIGH because of pull-up resistor
const unsigned long debounceTime = 10;    // milliseconds
unsigned long buttonPressTime;            // when the switch last changed state
boolean buttonPressed = 0;                // a flag variable




//                                          Graphic variables
int progress = 0;


//                                          Mode variables


// timelapse
int TL_hours = 0;
int TL_mins = 0;




#define SMLFONT FreeSans9pt7b




Metro nextfunc = Metro(4000);


class FlashBox
{
    int OnTime;
    int OffTime;
    int x;
    int y;
    int w;
    int h;
    int highlight;
    unsigned long previousMillis;


    // constructor
  public:
    FlashBox(int xx, int yy, int width, int height, int on, int off)
    {
      x = xx;
      y = yy;
      w = width;
      h = height;
      OnTime = on;
      OffTime = off;
      highlight = 0;
      previousMillis = 0;
      blinkon.interval(OnTime);
      blinkon.reset();
      blinkoff.interval(OffTime);
      blinkoff.reset();
    }


    void Flasher()
    {
      unsigned long currentMillis = millis();


      //        if ((blinkon.check())  && (highlight == 0))
      if ((currentMillis - previousMillis >= OnTime)  && (highlight == 0))
      {


        display.drawRect(x, y, w, h, WHITE);
        display.display();
        highlight = 1;
        previousMillis = currentMillis;


        //delay (1000);
      }
      //          else if ((blinkoff.check()) && (highlight == 1))
      else if ((currentMillis - previousMillis >= OffTime) && (highlight == 1))
      {


        display.drawRect(x, y, w, h, BLACK);
        display.display();
        highlight = 0;
        previousMillis = currentMillis;
        //delay(1000);
      }


    }
};




void setup()  // Start of setup
{
  // Encoder setup
  pinMode(EncButton, INPUT);
  digitalWrite(EncButton, HIGH); // Pull-Up resistor for switch


  // Display Setup
  delay(100);  // This delay is needed to let the display to initialize
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Initialize display with the I2C address of 0x3C
  display.clearDisplay();  // Clear the buffer
  display.setTextColor(WHITE);  // Set color of the text
  display.setRotation(0);  // Set orientation. Goes from 0, 1, 2 or 3
  display.setTextWrap(false);  // By default, long lines of text are set to automatically “wrap” back to the leftmost column.
  // To override this behavior (so text will run off the right side of the display - useful for
  // scrolling marquee effects), use setTextWrap(false). The normal wrapping behavior is restored
  // with setTextWrap(true).


  display.dim(0);  //Set brightness (0 is maximun and 1 is a little dim)


}  // End of setup




void loop()  // Start of loop
{


  getMenuMode();   // 0: Run Mode A 1: Run Mode B 2: Live Mode




}  // End of loop


void getMenuMode() {
  int mode = 1;
  display.clearDisplay();  // Clear the display so we can refresh
  display.setFont(&SMLFONT);  // Set a custom font
  display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
  display.setTextColor(WHITE);


  do {
    encRead = myEnc.read() >> 2; // bitwise divide by 4


    if (encRead < encOld)
    {
      mode--;
      if (mode < 1) mode = 1;
      encOld = encRead;
    }




    if (encRead > encOld)
    {
      mode++;
      if (mode > menuMax) mode = menuMax;
      encOld = encRead;
    }






    switch (mode) {
      case 1:
        display.clearDisplay();  // Clear the display so we can refresh
        //drawgrid();
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(10, 50);  // (x,y)
        display.println("Run Mode A");
        display.display();
        //            RunMode('A','B');
        break;


      case 2:
        display.clearDisplay();  //            RecordMode()
        //drawgrid();
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(10, 50);  // (x,y)
        display.println("Record Mode");
        display.display();


        break;


      case 3:
        display.clearDisplay();  // Clear the display so we can refresh
        //drawgrid();
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(20, 50);  // (x,y)
        display.println("Live Mode");
        display.display();
        //            LiveMode();
        break;


      case 4:
        display.clearDisplay();  //           SET TimeLapse  menuMode = 4
        //drawgrid();
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(48, 38);  // (x,y)
        display.println("SET");
        display.setCursor(22, 55);  // (x,y)
        display.println("Timelapse");
        display.display();
        checkSwitch();
        if (buttonPressed) {
          buttonPressed = 0;
          display.drawRect(0, 0, 128, 64, WHITE);
          display.display();
          delay(menuDelay);
          menuMode = 4;
          LapseModeSet();
        }
        break;


      case 5:
        display.clearDisplay();  //            RUN Timelapse  MenuMode = 5
        //drawgrid();
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(46, 38);  // (x,y)
        display.println("RUN");
        display.setCursor(22, 55);  // (x,y)
        display.println("Timelapse");
        display.display();
        checkSwitch();
        if (buttonPressed) {
          buttonPressed = 0;
          display.drawRect(0, 0, 128, 64, WHITE);
          display.display();
          delay(menuDelay);
          menuMode = 5;
          LapseModeRun();
        }
        break;


    }
  } while (menuMode == 0);
}


void TimeCalc( uint32_t seconds ) {
  uint32_t t = seconds;


  h = t / 3600;
  rem = t % 3600;
  m = rem / 60;
  s = rem % 60;
}


void RunMode ( char startKF, char endKF ) {
  nextfunc.reset();
  TotalSeconds = 740;
  do {
    Variable1++;  // Increase variable by 1
    if (Variable1 > 150) // If Variable1 is greater than 150
    {
      Variable1 = 0;  // Set Variable1 to 0
    }


    display.clearDisplay();  // Clear the display so we can refresh




    display.setFont(&SMLFONT);  // Set a custom font
    display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
    display.setTextColor(WHITE);




    // Print text:
    display.setCursor(0, 12);  // (x,y)
    display.print("Running "); display.print(startKF); display.print("<->"); display.print(endKF);  // print start and end keyframes
    display.setFont();
    display.setCursor(0, 30);  // (x,y)
    //        display.println("TIME REMAINING");  // Text or value to print
    display.setCursor(0, 29);
    display.println(" HOURS   MIN.    SEC.");
    display.drawLine(0, 43, 128, 43, WHITE);  // Draw Horizontal line
    display.drawLine(42, 43, 42, 64, WHITE);  // Draw Vertictal line
    display.drawLine(84, 43, 84, 64, WHITE);  // Draw Vertictal line
    display.setFont(&SMLFONT);
    TimeCalc(TotalSeconds);
    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds
    --TotalSeconds;




    // Draw Progress Bar rectangle:
    display.drawRect(0, 22, 128, 1, WHITE);  // Draw rectangle (x,y,width,height,color)
    display.fillRect(0, 21, progress, 3, WHITE);  // It draws from the location to down-right
    progress++;
    if (progress > 127) {
      progress = 0;
    }


    //display.setFont(&FreeMonoBold12pt7b);  // Set a custom font


    // Print variable with left alignment:
    display.setFont();




    display.display();  // Print everything we set previously
    checkSwitch();      // check encoder switch
    if (buttonPressed) {
      Variable1 = 0;
      progress = 0;
      display.clearDisplay();
      display.display();
      return;
    }
  } while (Variable1 < 128);




}


void LiveMode() {
  // display.fillRect(0, 0, 128, 64, WHITE);
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.setCursor(10, 20);  // (x,y)
  display.setTextColor(WHITE);
  while (!buttonPressed) {
    display.println("Live Mode");
    display.display();
  }
  return;
}


void RecordMode() {
  // display.fillRect(0, 0, 128, 64, WHITE);
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.setCursor(10, 20);  // (x,y)
  display.setTextColor(WHITE);
  while (!buttonPressed) {
    display.println("Recording..");
    display.display();
  }
  return;
}


void LapseModeSet() {


  screen_Lapse();


  FlashBox hours(1, 36, 63, 27, 200, 200); // Construct flashing box (Hours)
  FlashBox mins(65, 36, 62, 27, 200, 200); // Construct flashing box (Minutes)
  FlashBox TL_set(0, 0, 128, 64, 300, 300); // Construct TL Done flashing box
  int mode = 0;  // 0 = hours selected   1 = minutes selected
  int valuechange = 0;


  encOld = 0;
  buttonPressed = 0;
  myEnc.write(0);
  do {




    do {


      encRead = myEnc.read() >> 2; // bitwise divide by 4
      if (encRead < encOld)
      {
        mode--;
        if (mode < 0) mode = 0;
        encOld = encRead;
        screen_Lapse();
      }
      if (encRead > encOld)
      {
        mode++;
        if (mode > 2) mode = 2;
        encOld = encRead;
        screen_Lapse();
      }




      switch (mode)
      {
        case 0:
          hours.Flasher();    // flash Hours Box
          break;
        case 1:
          mins.Flasher();     // flash Minutes Box
          break;
        case 2:
          TL_set.Flasher();   // flash whole screen Box
          break;
      }


      checkSwitch();
      if (buttonPressed)
      {
        buttonPressed = 0;
        valuechange = 1;
        if (mode == 0) myEnc.write(TL_hours);
        if (mode == 1) myEnc.write(TL_mins);
        screen_Lapse();
      }


    } while (!valuechange);






    do {
      if (mode == 0)   // Adjust Hours
      {
        display.drawRect(1, 36, 63, 27, WHITE);
        encRead = myEnc.read() >> 2; // bitwise divide by 4
        TL_hours = constrain(encRead, 0, 100);
        screen_Lapse();
        checkSwitch();
        if (buttonPressed)
        {
          valuechange = 0;
          buttonPressed = 0;
        }
      }


      if (mode == 1)   // Adjust Minutes
      {
        display.drawRect(65, 36, 62, 27, WHITE);
        encRead = myEnc.read() >> 2; // bitwise divide by 4
        TL_mins = constrain(encRead, 0, 59);
        screen_Lapse();
        checkSwitch();
        if (buttonPressed)
        {
          valuechange = 0;
          buttonPressed = 0;
        }
      }


      if (mode == 2)   // Quit to Main Menu
      {


        valuechange = 0;
        buttonPressed = 0;
        menuMode = 0;
        remainingSeconds = ((TL_hours * 60) * 60) + (TL_mins * 60);


      }


    } while (valuechange);










  } while (menuMode == 4);


}


void LapseModeRun() {
  //  Serial.begin(9600);
  TotalSeconds = remainingSeconds;
  int percent = 0;


  do {






    display.clearDisplay();  // Clear the display so we can refresh
    display.setFont(&SMLFONT);  // Set a custom font
    display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
    display.setTextColor(WHITE);
    display.setCursor(0, 12);  // (x,y)
    display.print("Running ");
    display.setFont();
    display.setCursor(0, 30);  // (x,y)
    //        display.println("TIME REMAINING");  // Text or value to print
    display.setCursor(0, 29);
    display.println(" HOURS   MIN.    SEC.");
    display.drawLine(0, 43, 128, 43, WHITE);  // Draw Horizontal line
    display.drawLine(42, 43, 42, 64, WHITE);  // Draw Vertictal line
    display.drawLine(84, 43, 84, 64, WHITE);  // Draw Vertictal line
    display.setFont(&SMLFONT);
    TimeCalc(remainingSeconds);
    //Serial.print(h); Serial.print(" ");Serial.print(m); Serial.print(" ");Serial.println(s);
    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds




    // Draw Progress Bar rectangle:
    progress = abs((((float)remainingSeconds / (float)TotalSeconds) * 128) - 128);
    percent = ((float)progress / 128) * 100;
    display.drawRect(0, 22, 128, 1, WHITE);  // Draw rectangle (x,y,width,height,color)
    display.fillRect(0, 21, progress, 3, WHITE);  // It draws from the location to down-right




    //display.setFont(&FreeMonoBold12pt7b);  // Set a custom font


    // Print variable with left alignment:
    display.setFont();
    display.setCursor(100, 5);
    display.print(percent);
    display.println("%");
    //    display.setCursor(80, 5);
    //    display.print(remainingSeconds);


    display.display();  // Print everything we set previously


    if (remainingSeconds == 0)
    {
      //display.getTextBounds("Running ",0,12,int x, int y, int ww, int hh);
      display.fillRect(0, 0, 70, 20, BLACK);
      display.setFont(&SMLFONT);
      display.setCursor(0, 12);  // (x,y)
      display.print("DONE ");
      display.display();
      delay(50000);
      menuMode = 0;
    }




    remainingSeconds--;             //          TICK!










    checkSwitch();      // check encoder switch
    if (buttonPressed) {
      buttonPressed = 0;
      menuMode = 0;
      display.clearDisplay();
      display.display();
      return;
    }
  } while (menuMode == 5);




}


void checkSwitch() {
  // Check Encoder Switch


  byte buttonState = digitalRead(EncButton);
  if (buttonState != oldButtonState)
  {
    if (millis () - buttonPressTime >= debounceTime)
    { // debounce
      buttonPressTime = millis ();                      // when we closed the switch
      oldButtonState =  buttonState;                    // remember for next time
      if (buttonState == LOW)
      {
        //        Serial.println ("Button pressed");               // DEBUGGING: print that button has been closed
        buttonPressed = 1;
      }
      else
      {
        //        Serial.println ("Button released");               // DEBUGGING: print that button has been opened
        buttonPressed = 0;
      }
    }  // end if debounce time up
  } // end of state change
}


void screen_Lapse() {
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.drawRect(0, 0, 128, 64, WHITE);  // Draw Border
  display.setCursor(4, 15);  // (x,y)
  display.setTextColor(WHITE);
  display.println("Set Timelapse");
  display.setFont();
  display.setCursor(0, 25);
  display.println("   HOURS     MINUTES");
  display.drawLine(0, 35, 128, 35, WHITE);  // Draw Horizontal line
  display.drawLine(64, 35, 64, 64, WHITE);  // Draw Vertictal line
  display.setFont(&SMLFONT);
  display.setCursor(17, 55);
  display.println(TL_hours);
  display.setCursor(85, 55);
  display.println(TL_mins);
  display.display();


}


void drawgrid() {
  display.drawRect(0, 0, 128, 64, WHITE);
  display.drawLine(64, 0, 64, 128, WHITE);
  display.drawLine(0, 32, 128, 32, WHITE);
}




// Adafruit Graphic library code references




// Draw triangle:
// display.drawTriangle(40,40,   50,20,   60,40, WHITE);  // Draw triangle. X, Y coordinates for three corner points defining the triangle, followed by a color


// Draw filled triangle:
//display.fillTriangle(0,35,   15,45,   30,63, WHITE);  // Draw filled triangle. X, Y coordinates for three corner points defining the triangle, followed by a color


// Draw line:
//  display.drawLine(0, 18, 128, 18, WHITE);  // Draw line (x0,y0,x1,y1,color)


// Draw circle:
// display.drawCircle(47, 36, 20, WHITE);  //  Draw circle (x,y,radius,color). X and Y are the coordinates for the center point


// Draw a filled circle:
// display.fillCircle(12, 27, 10, WHITE);  // Draw filled circle (x,y,radius,color). X and Y are the coordinates for the center point


// Draw rectangle:
// display.drawRect(58, 0, 18, 18, WHITE);  // Draw rectangle (x,y,width,height,color)
// It draws from the location to down-right


// Draw rounded rectangle and fill:
// display.fillRoundRect(58, 0, 18, 18, 5, WHITE);  // Draw filled rounded rectangle (x,y,width,height,color)
// It draws from the location to down-right
// Draw rounded rectangle:
//display.drawRoundRect(79, 37, 49, 27, 8, WHITE);  // Draw rounded rectangle (x,y,width,height,radius,color)
// It draws from the location to down-right


// Print variable with right alignment:
//  display.setCursor(83, 60);  // (x,y)
//  display.println(string);  // Text or value to print




//
//
//  // Convert Variable1 into a string, so we can change the text alignment to the right:
//  // It can be also used to add or remove decimal numbers.
//  char string[10];  // Create a character array of 10 characters
//  // Convert float to a string:
//  dtostrf(Variable1, 3, 0, string);  // (<variable>,<amount of digits we are going to use>,<amount of decimal digits>,<string name>)

I'm also reattaching images of the OLED SSD 1306 module running the sketch. Please let me know if they cant be viewed. Standard JPG.
IMG_5925.jpgIMG_7986.jpg

Again, the problem is the OLED will not display proper countdown starting higher than 18 hrs. 12 minutes.
 
Last edited:
Again simple problem here... Example: your 18 hours and 12 minutes comes out to 65520 seconds... Which is just about as big a number you can fit int uint16_t

Code:
void TimeCalc( uint32_t seconds ) {
  uint32_t t = seconds;


  h = t / 3600;
  rem = t % 3600;
  m = rem / 60;
  s = rem % 60;
}

Yes you are using some uint32_t values which should work, but your intermediate calculations may be done in 16 bits... What happens if you start casting things and use large constants?

Like:
Code:
void TimeCalc( uint32_t seconds ) {
  uint32_t t = seconds;


  h =  (uint32_t)t / (uint32_t)3600L;
  rem =  (uint32_t)t %  (uint32_t)3600L;
  m = rem / 60;
  s = rem % 60;
}
 
Again simple problem here...... What happens if you start casting things and use large constants?

Like:
Code:
void TimeCalc( uint32_t seconds ) {
  uint32_t t = seconds;


  h =  (uint32_t)t / (uint32_t)3600L;
  rem =  (uint32_t)t %  (uint32_t)3600L;
  m = rem / 60;
  s = rem % 60;
}

Kurt, tried your idea... I get the same result. Setting countdown to 18:13 results in a 1 minute countdown..

Code:
/*


  List of fonts: https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts






  If you have the 128x64 version, you need to edit the file called Adafruit_SSD1306.h that is on the
  Adafruit_SSD1306-master folder. The library comes by default set to use the 128x32 display.
  For this reason you need to define the correct resolution like this:
  Quote:
   #define SSD1306_128_64
  //   #define SSD1306_128_32
  //   #define SSD1306_96_16
  Unquote.
  Notes the "//" before each line to comment the other resolutions that we are not going to use.




*/






#include <Adafruit_GFX.h>  // Include core graphics library for the display
#include <Adafruit_SSD1306.h>  // Include Adafruit_SSD1306 library to drive the display
#include <Metro.h>
#include <Encoder.h>
#include <Bounce2.h>
#include <Fonts/FreeSans9pt7b.h>  // Add a custom font


Adafruit_SSD1306 display;  // Create display




int Variable1;  // Create a variable to have something dynamic to show on the display


//                                        Countdown variables


long unsigned int TotalSeconds = 0;
uint16_t remainingSeconds = 0;
uint16_t h   = 0;
uint16_t m   = 0;
uint16_t s   = 0;
uint16_t rem = 0;


//                                          Menu Variables
boolean hlight = 0;
int menuMax = 5;
int menuMode = 0;
int menuDelay = 500;
Metro blinkon = Metro(1000);
Metro blinkoff = Metro(1000);
Metro debounce = Metro(10);


//                                          Keyframe Variables


char StartingKey;
char EndingKey;


//                                          Encoder Variables


Encoder myEnc(2, 3);
int encState;
int encRead;                              //current encoder read
int encOld;                               //previous encoder read


const int EncButton = 4;                  //Pin # to which SW line is connected
byte oldButtonState = HIGH;               // set previous buttonestate to HIGH because of pull-up resistor
const unsigned long debounceTime = 10;    // milliseconds
unsigned long buttonPressTime;            // when the switch last changed state
boolean buttonPressed = 0;                // a flag variable




//                                          Graphic variables
int progress = 0;


//                                          Mode variables


// timelapse
int TL_hours = 0;
int TL_mins = 0;




#define SMLFONT FreeSans9pt7b




Metro nextfunc = Metro(4000);


class FlashBox
{
    int OnTime;
    int OffTime;
    int x;
    int y;
    int w;
    int h;
    int highlight;
    unsigned long previousMillis;


    // constructor
  public:
    FlashBox(int xx, int yy, int width, int height, int on, int off)
    {
      x = xx;
      y = yy;
      w = width;
      h = height;
      OnTime = on;
      OffTime = off;
      highlight = 0;
      previousMillis = 0;
      blinkon.interval(OnTime);
      blinkon.reset();
      blinkoff.interval(OffTime);
      blinkoff.reset();
    }


    void Flasher()
    {
      unsigned long currentMillis = millis();


      //        if ((blinkon.check())  && (highlight == 0))
      if ((currentMillis - previousMillis >= OnTime)  && (highlight == 0))
      {


        display.drawRect(x, y, w, h, WHITE);
        display.display();
        highlight = 1;
        previousMillis = currentMillis;


        //delay (1000);
      }
      //          else if ((blinkoff.check()) && (highlight == 1))
      else if ((currentMillis - previousMillis >= OffTime) && (highlight == 1))
      {


        display.drawRect(x, y, w, h, BLACK);
        display.display();
        highlight = 0;
        previousMillis = currentMillis;
        //delay(1000);
      }


    }
};




void setup()  // Start of setup
{
  // Encoder setup
  pinMode(EncButton, INPUT);
  digitalWrite(EncButton, HIGH); // Pull-Up resistor for switch


  // Display Setup
  delay(100);  // This delay is needed to let the display to initialize
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Initialize display with the I2C address of 0x3C
  display.clearDisplay();  // Clear the buffer
  display.setTextColor(WHITE);  // Set color of the text
  display.setRotation(0);  // Set orientation. Goes from 0, 1, 2 or 3
  display.setTextWrap(false);  // By default, long lines of text are set to automatically “wrap” back to the leftmost column.
  // To override this behavior (so text will run off the right side of the display - useful for
  // scrolling marquee effects), use setTextWrap(false). The normal wrapping behavior is restored
  // with setTextWrap(true).


  display.dim(0);  //Set brightness (0 is maximun and 1 is a little dim)


}  // End of setup




void loop()  // Start of loop
{


  getMenuMode();   // 0: Run Mode A 1: Run Mode B 2: Live Mode




}  // End of loop


void getMenuMode() {
  int mode = 1;
  display.clearDisplay();  // Clear the display so we can refresh
  display.setFont(&SMLFONT);  // Set a custom font
  display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
  display.setTextColor(WHITE);


  do {
    encRead = myEnc.read() >> 2; // bitwise divide by 4


    if (encRead < encOld)
    {
      mode--;
      if (mode < 1) mode = 1;
      encOld = encRead;
    }




    if (encRead > encOld)
    {
      mode++;
      if (mode > menuMax) mode = menuMax;
      encOld = encRead;
    }






    switch (mode) {
      case 1:
        display.clearDisplay();  // Clear the display so we can refresh
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(20, 38);  // (x,y)
        display.println("REALTIME");
        display.setCursor(44, 55);  // (x,y)
        display.println("Mode");
        display.display();
        //            RunMode('A','B');
        break;


      case 2:
        display.clearDisplay();  //            RecordMode()
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(27, 38);  // (x,y)
        display.println("RECORD");
        display.setCursor(44, 55);  // (x,y)
        display.println("Mode");
        display.display();


        break;


      case 3:
        display.clearDisplay();  // Clear the display so we can refresh
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(47, 38);  // (x,y)
        display.println("LIVE");
        display.setCursor(44, 55);  // (x,y)
        display.println("Mode");
        display.display();
        //            LiveMode();
        break;


      case 4:
        display.clearDisplay();  //           SET TimeLapse  menuMode = 4
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(48, 38);  // (x,y)
        display.println("SET");
        display.setCursor(22, 55);  // (x,y)
        display.println("Timelapse");
        display.display();
        checkSwitch();
        if (buttonPressed) {
          buttonPressed = 0;
          display.drawRect(0, 0, 128, 64, WHITE);
          display.display();
          delay(menuDelay);
          menuMode = 4;
          LapseModeSet();
        }
        break;


      case 5:
        display.clearDisplay();  //            RUN Timelapse  MenuMode = 5
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(46, 38);  // (x,y)
        display.println("RUN");
        display.setCursor(22, 55);  // (x,y)
        display.println("Timelapse");
        display.display();
        checkSwitch();
        if (buttonPressed) {
          buttonPressed = 0;
          display.drawRect(0, 0, 128, 64, WHITE);
          display.display();
          delay(menuDelay);
          menuMode = 5;
          LapseModeRun();
        }
        break;


    }
  } while (menuMode == 0);
}


void TimeCalc( uint32_t seconds ) {
  uint32_t t = seconds;


  h =  (uint32_t)t / (uint32_t)3600L;
  rem =  (uint32_t)t %  (uint32_t)3600L;
  m = rem / 60;
  s = rem % 60;




//  h = t / 3600;
//  rem = t % 3600;
//  m = rem / 60;
//  s = rem % 60;
}


void RunMode ( char startKF, char endKF ) {
  nextfunc.reset();
  TotalSeconds = 740;
  do {
    Variable1++;  // Increase variable by 1
    if (Variable1 > 150) // If Variable1 is greater than 150
    {
      Variable1 = 0;  // Set Variable1 to 0
    }


    display.clearDisplay();  // Clear the display so we can refresh




    display.setFont(&SMLFONT);  // Set a custom font
    display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
    display.setTextColor(WHITE);




    // Print text:
    display.setCursor(0, 12);  // (x,y)
    display.print("Running "); display.print(startKF); display.print("<->"); display.print(endKF);  // print start and end keyframes
    display.setFont();
    display.setCursor(0, 30);  // (x,y)
    //        display.println("TIME REMAINING");  // Text or value to print
    display.setCursor(0, 29);
    display.println(" HOURS   MIN.    SEC.");
    display.drawLine(0, 43, 128, 43, WHITE);  // Draw Horizontal line
    display.drawLine(42, 43, 42, 64, WHITE);  // Draw Vertictal line
    display.drawLine(84, 43, 84, 64, WHITE);  // Draw Vertictal line
    display.setFont(&SMLFONT);
    TimeCalc(TotalSeconds);
    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds
    --TotalSeconds;




    // Draw Progress Bar rectangle:
    display.drawRect(0, 22, 128, 1, WHITE);  // Draw rectangle (x,y,width,height,color)
    display.fillRect(0, 21, progress, 3, WHITE);  // It draws from the location to down-right
    progress++;
    if (progress > 127) {
      progress = 0;
    }


    //display.setFont(&FreeMonoBold12pt7b);  // Set a custom font


    // Print variable with left alignment:
    display.setFont();




    display.display();  // Print everything we set previously
    checkSwitch();      // check encoder switch
    if (buttonPressed) {
      Variable1 = 0;
      progress = 0;
      display.clearDisplay();
      display.display();
      return;
    }
  } while (Variable1 < 128);




}


void LiveMode() {
  // display.fillRect(0, 0, 128, 64, WHITE);
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.setCursor(10, 20);  // (x,y)
  display.setTextColor(WHITE);
  while (!buttonPressed) {
    display.println("Live Mode");
    display.display();
  }
  return;
}


void RecordMode() {
  // display.fillRect(0, 0, 128, 64, WHITE);
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.setCursor(10, 20);  // (x,y)
  display.setTextColor(WHITE);
  while (!buttonPressed) {
    display.println("Recording..");
    display.display();
  }
  return;
}


void LapseModeSet() {


  screen_Lapse();


  FlashBox hours(1, 36, 63, 27, 200, 200); // Construct flashing box (Hours)
  FlashBox mins(65, 36, 62, 27, 200, 200); // Construct flashing box (Minutes)
  FlashBox TL_set(0, 0, 128, 64, 300, 300); // Construct TL Done flashing box
  int mode = 0;  // 0 = hours selected   1 = minutes selected
  int valuechange = 0;


  encOld = 0;
  buttonPressed = 0;
  myEnc.write(0);
  do {




    do {


      encRead = myEnc.read() >> 2; // bitwise divide by 4
      if (encRead < encOld)
      {
        mode--;
        if (mode < 0) mode = 0;
        encOld = encRead;
        screen_Lapse();
      }
      if (encRead > encOld)
      {
        mode++;
        if (mode > 2) mode = 2;
        encOld = encRead;
        screen_Lapse();
      }




      switch (mode)
      {
        case 0:
          hours.Flasher();    // flash Hours Box
          break;
        case 1:
          mins.Flasher();     // flash Minutes Box
          break;
        case 2:
          TL_set.Flasher();   // flash whole screen Box
          break;
      }


      checkSwitch();
      if (buttonPressed)
      {
        buttonPressed = 0;
        valuechange = 1;
        if (mode == 0) myEnc.write(TL_hours);
        if (mode == 1) myEnc.write(TL_mins);
        screen_Lapse();
      }


    } while (!valuechange);






    do {
      if (mode == 0)   // Adjust Hours
      {
        display.drawRect(1, 36, 63, 27, WHITE);
        encRead = myEnc.read() >> 2; // bitwise divide by 4
        TL_hours = constrain(encRead, 0, 100);
        screen_Lapse();
        checkSwitch();
        if (buttonPressed)
        {
          valuechange = 0;
          buttonPressed = 0;
        }
      }


      if (mode == 1)   // Adjust Minutes
      {
        display.drawRect(65, 36, 62, 27, WHITE);
        encRead = myEnc.read() >> 2; // bitwise divide by 4
        TL_mins = constrain(encRead, 0, 59);
        screen_Lapse();
        checkSwitch();
        if (buttonPressed)
        {
          valuechange = 0;
          buttonPressed = 0;
        }
      }


      if (mode == 2)   // Quit to Main Menu
      {


        valuechange = 0;
        buttonPressed = 0;
        menuMode = 0;
        remainingSeconds = ((TL_hours * 60) * 60) + (TL_mins * 60);


      }


    } while (valuechange);










  } while (menuMode == 4);


}


void LapseModeRun() {
  //  Serial.begin(9600);
  TotalSeconds = remainingSeconds;
  int percent = 0;


  do {






    display.clearDisplay();  // Clear the display so we can refresh
    display.setFont(&SMLFONT);  // Set a custom font
    display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
    display.setTextColor(WHITE);
    display.setCursor(0, 12);  // (x,y)
    display.print("Running ");
    display.setFont();
    display.setCursor(0, 30);  // (x,y)
    //        display.println("TIME REMAINING");  // Text or value to print
    display.setCursor(0, 29);
    display.println(" HOURS   MIN.    SEC.");
    display.drawLine(0, 43, 128, 43, WHITE);  // Draw Horizontal line
    display.drawLine(42, 43, 42, 64, WHITE);  // Draw Vertictal line
    display.drawLine(84, 43, 84, 64, WHITE);  // Draw Vertictal line
    display.setFont(&SMLFONT);
    TimeCalc(remainingSeconds);
    //Serial.print(h); Serial.print(" ");Serial.print(m); Serial.print(" ");Serial.println(s);
    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds




    // Draw Progress Bar rectangle:
    progress = abs((((float)remainingSeconds / (float)TotalSeconds) * 128) - 128);
    percent = ((float)progress / 128) * 100;
    display.drawRect(0, 22, 128, 1, WHITE);  // Draw rectangle (x,y,width,height,color)
    display.fillRect(0, 21, progress, 3, WHITE);  // It draws from the location to down-right




    //display.setFont(&FreeMonoBold12pt7b);  // Set a custom font


    // Print variable with left alignment:
    display.setFont();
    display.setCursor(100, 5);
    display.print(percent);
    display.println("%");
    //    display.setCursor(80, 5);
    //    display.print(remainingSeconds);


    display.display();  // Print everything we set previously


    if (remainingSeconds == 0)
    {
      //display.getTextBounds("Running ",0,12,int x, int y, int ww, int hh);
      display.fillRect(0, 0, 70, 20, BLACK);
      display.setFont(&SMLFONT);
      display.setCursor(0, 12);  // (x,y)
      display.print("DONE ");
      display.display();
      delay(50000);
      menuMode = 0;
    }




    remainingSeconds--;             //          TICK!










    checkSwitch();      // check encoder switch
    if (buttonPressed) {
      buttonPressed = 0;
      menuMode = 0;
      display.clearDisplay();
      display.display();
      return;
    }
  } while (menuMode == 5);




}


void checkSwitch() {
  // Check Encoder Switch


  byte buttonState = digitalRead(EncButton);
  if (buttonState != oldButtonState)
  {
    if (millis () - buttonPressTime >= debounceTime)
    { // debounce
      buttonPressTime = millis ();                      // when we closed the switch
      oldButtonState =  buttonState;                    // remember for next time
      if (buttonState == LOW)
      {
        //        Serial.println ("Button pressed");               // DEBUGGING: print that button has been closed
        buttonPressed = 1;
      }
      else
      {
        //        Serial.println ("Button released");               // DEBUGGING: print that button has been opened
        buttonPressed = 0;
      }
    }  // end if debounce time up
  } // end of state change
}


void screen_Lapse() {
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.drawRect(0, 0, 128, 64, WHITE);  // Draw Border
  display.setCursor(4, 15);  // (x,y)
  display.setTextColor(WHITE);
  display.println("Set Timelapse");
  display.setFont();
  display.setCursor(0, 25);
  display.println("   HOURS     MINUTES");
  display.drawLine(0, 35, 128, 35, WHITE);  // Draw Horizontal line
  display.drawLine(64, 35, 64, 64, WHITE);  // Draw Vertictal line
  display.setFont(&SMLFONT);
  display.setCursor(17, 55);
  display.println(TL_hours);
  display.setCursor(85, 55);
  display.println(TL_mins);
  display.display();


}


void drawgrid() {
  display.drawRect(0, 0, 128, 64, WHITE);
  display.drawLine(64, 0, 64, 128, WHITE);
  display.drawLine(0, 32, 128, 32, WHITE);
}




// Adafruit Graphic library code references




// Draw triangle:
// display.drawTriangle(40,40,   50,20,   60,40, WHITE);  // Draw triangle. X, Y coordinates for three corner points defining the triangle, followed by a color


// Draw filled triangle:
//display.fillTriangle(0,35,   15,45,   30,63, WHITE);  // Draw filled triangle. X, Y coordinates for three corner points defining the triangle, followed by a color


// Draw line:
//  display.drawLine(0, 18, 128, 18, WHITE);  // Draw line (x0,y0,x1,y1,color)


// Draw circle:
// display.drawCircle(47, 36, 20, WHITE);  //  Draw circle (x,y,radius,color). X and Y are the coordinates for the center point


// Draw a filled circle:
// display.fillCircle(12, 27, 10, WHITE);  // Draw filled circle (x,y,radius,color). X and Y are the coordinates for the center point


// Draw rectangle:
// display.drawRect(58, 0, 18, 18, WHITE);  // Draw rectangle (x,y,width,height,color)
// It draws from the location to down-right


// Draw rounded rectangle and fill:
// display.fillRoundRect(58, 0, 18, 18, 5, WHITE);  // Draw filled rounded rectangle (x,y,width,height,color)
// It draws from the location to down-right
// Draw rounded rectangle:
//display.drawRoundRect(79, 37, 49, 27, 8, WHITE);  // Draw rounded rectangle (x,y,width,height,radius,color)
// It draws from the location to down-right


// Print variable with right alignment:
//  display.setCursor(83, 60);  // (x,y)
//  display.println(string);  // Text or value to print




//


//  // Convert Variable1 into a string, so we can change the text alignment to the right:
//  // It can be also used to add or remove decimal numbers.
//  char string[10];  // Create a character array of 10 characters
//  // Convert float to a string:
//  dtostrf(Variable1, 3, 0, string);  // (<variable>,<amount of digits we are going to use>,<amount of decimal digits>,<string name>)
 
you have delcared h,m,s,rem as uint16_t, and remainingseconds. remainingseconds should be uint32_t. is there a reason why h,m,s,rem can not be declared uint32_t? try it
 
Manitou,

Tried it. Seems to make matters worse.. now setting countdown to 10 hours gives garbage on the OLED. Only setting all relevant variables to uint16_t allows me to get to 18hrs 12mins cleanly..

Code:
/*


  List of fonts: https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts






  If you have the 128x64 version, you need to edit the file called Adafruit_SSD1306.h that is on the
  Adafruit_SSD1306-master folder. The library comes by default set to use the 128x32 display.
  For this reason you need to define the correct resolution like this:
  Quote:
   #define SSD1306_128_64
  //   #define SSD1306_128_32
  //   #define SSD1306_96_16
  Unquote.
  Notes the "//" before each line to comment the other resolutions that we are not going to use.




*/






#include <Adafruit_GFX.h>  // Include core graphics library for the display
#include <Adafruit_SSD1306.h>  // Include Adafruit_SSD1306 library to drive the display
#include <Metro.h>
#include <Encoder.h>
#include <Bounce2.h>
#include <Fonts/FreeSans9pt7b.h>  // Add a custom font


Adafruit_SSD1306 display;  // Create display




int Variable1;  // Create a variable to have something dynamic to show on the display


//                                        Countdown variables


long unsigned int TotalSeconds = 0;
uint32_t remainingSeconds = 0;
uint32_t h   = 0;
uint32_t m   = 0;
uint32_t s   = 0;
uint32_t rem = 0;


//                                          Menu Variables
boolean hlight = 0;
int menuMax = 5;
int menuMode = 0;
int menuDelay = 500;
Metro blinkon = Metro(1000);
Metro blinkoff = Metro(1000);
Metro debounce = Metro(10);


//                                          Keyframe Variables


char StartingKey;
char EndingKey;


//                                          Encoder Variables


Encoder myEnc(2, 3);
int encState;
int encRead;                              //current encoder read
int encOld;                               //previous encoder read


const int EncButton = 4;                  //Pin # to which SW line is connected
byte oldButtonState = HIGH;               // set previous buttonestate to HIGH because of pull-up resistor
const unsigned long debounceTime = 10;    // milliseconds
unsigned long buttonPressTime;            // when the switch last changed state
boolean buttonPressed = 0;                // a flag variable




//                                          Graphic variables
int progress = 0;


//                                          Mode variables


// timelapse
int TL_hours = 0;
int TL_mins = 0;




#define SMLFONT FreeSans9pt7b




Metro nextfunc = Metro(4000);


class FlashBox
{
    int OnTime;
    int OffTime;
    int x;
    int y;
    int w;
    int h;
    int highlight;
    unsigned long previousMillis;


    // constructor
  public:
    FlashBox(int xx, int yy, int width, int height, int on, int off)
    {
      x = xx;
      y = yy;
      w = width;
      h = height;
      OnTime = on;
      OffTime = off;
      highlight = 0;
      previousMillis = 0;
      blinkon.interval(OnTime);
      blinkon.reset();
      blinkoff.interval(OffTime);
      blinkoff.reset();
    }


    void Flasher()
    {
      unsigned long currentMillis = millis();


      //        if ((blinkon.check())  && (highlight == 0))
      if ((currentMillis - previousMillis >= OnTime)  && (highlight == 0))
      {


        display.drawRect(x, y, w, h, WHITE);
        display.display();
        highlight = 1;
        previousMillis = currentMillis;


        //delay (1000);
      }
      //          else if ((blinkoff.check()) && (highlight == 1))
      else if ((currentMillis - previousMillis >= OffTime) && (highlight == 1))
      {


        display.drawRect(x, y, w, h, BLACK);
        display.display();
        highlight = 0;
        previousMillis = currentMillis;
        //delay(1000);
      }


    }
};




void setup()  // Start of setup
{
  // Encoder setup
  pinMode(EncButton, INPUT);
  digitalWrite(EncButton, HIGH); // Pull-Up resistor for switch


  // Display Setup
  delay(100);  // This delay is needed to let the display to initialize
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Initialize display with the I2C address of 0x3C
  display.clearDisplay();  // Clear the buffer
  display.setTextColor(WHITE);  // Set color of the text
  display.setRotation(0);  // Set orientation. Goes from 0, 1, 2 or 3
  display.setTextWrap(false);  // By default, long lines of text are set to automatically “wrap” back to the leftmost column.
  // To override this behavior (so text will run off the right side of the display - useful for
  // scrolling marquee effects), use setTextWrap(false). The normal wrapping behavior is restored
  // with setTextWrap(true).


  display.dim(0);  //Set brightness (0 is maximun and 1 is a little dim)


}  // End of setup




void loop()  // Start of loop
{


  getMenuMode();   // 0: Run Mode A 1: Run Mode B 2: Live Mode




}  // End of loop


void getMenuMode() {
  int mode = 1;
  display.clearDisplay();  // Clear the display so we can refresh
  display.setFont(&SMLFONT);  // Set a custom font
  display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
  display.setTextColor(WHITE);


  do {
    encRead = myEnc.read() >> 2; // bitwise divide by 4


    if (encRead < encOld)
    {
      mode--;
      if (mode < 1) mode = 1;
      encOld = encRead;
    }




    if (encRead > encOld)
    {
      mode++;
      if (mode > menuMax) mode = menuMax;
      encOld = encRead;
    }






    switch (mode) {
      case 1:
        display.clearDisplay();  // Clear the display so we can refresh
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(20, 38);  // (x,y)
        display.println("REALTIME");
        display.setCursor(44, 55);  // (x,y)
        display.println("Mode");
        display.display();
        //            RunMode('A','B');
        break;


      case 2:
        display.clearDisplay();  //            RecordMode()
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(27, 38);  // (x,y)
        display.println("RECORD");
        display.setCursor(44, 55);  // (x,y)
        display.println("Mode");
        display.display();


        break;


      case 3:
        display.clearDisplay();  // Clear the display so we can refresh
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(47, 38);  // (x,y)
        display.println("LIVE");
        display.setCursor(44, 55);  // (x,y)
        display.println("Mode");
        display.display();
        //            LiveMode();
        break;


      case 4:
        display.clearDisplay();  //           SET TimeLapse  menuMode = 4
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(48, 38);  // (x,y)
        display.println("SET");
        display.setCursor(22, 55);  // (x,y)
        display.println("Timelapse");
        display.display();
        checkSwitch();
        if (buttonPressed) {
          buttonPressed = 0;
          display.drawRect(0, 0, 128, 64, WHITE);
          display.display();
          delay(menuDelay);
          menuMode = 4;
          LapseModeSet();
        }
        break;


      case 5:
        display.clearDisplay();  //            RUN Timelapse  MenuMode = 5
        //drawgrid();
        display.drawRoundRect(0, 0, 128, 64, 8, WHITE);
        display.setCursor(48, 12);  // (x,y)
        display.setFont();
        display.print("SELECT");
        //display.print(mode);
        display.setFont(&SMLFONT);
        display.setCursor(46, 38);  // (x,y)
        display.println("RUN");
        display.setCursor(22, 55);  // (x,y)
        display.println("Timelapse");
        display.display();
        checkSwitch();
        if (buttonPressed) {
          buttonPressed = 0;
          display.drawRect(0, 0, 128, 64, WHITE);
          display.display();
          delay(menuDelay);
          menuMode = 5;
          LapseModeRun();
        }
        break;


    }
  } while (menuMode == 0);
}


void TimeCalc( uint32_t seconds ) {
  uint32_t t = seconds;


//  h =  (uint32_t)t / (uint32_t)3600L;
//  rem =  (uint32_t)t %  (uint32_t)3600L;
//  m = rem / 60;
//  s = rem % 60;




  h = t / 3600;
  rem = t % 3600;
  m = rem / 60;
  s = rem % 60;
}


void RunMode ( char startKF, char endKF ) {
  nextfunc.reset();
  TotalSeconds = 740;
  do {
    Variable1++;  // Increase variable by 1
    if (Variable1 > 150) // If Variable1 is greater than 150
    {
      Variable1 = 0;  // Set Variable1 to 0
    }


    display.clearDisplay();  // Clear the display so we can refresh




    display.setFont(&SMLFONT);  // Set a custom font
    display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
    display.setTextColor(WHITE);




    // Print text:
    display.setCursor(0, 12);  // (x,y)
    display.print("Running "); display.print(startKF); display.print("<->"); display.print(endKF);  // print start and end keyframes
    display.setFont();
    display.setCursor(0, 30);  // (x,y)
    //        display.println("TIME REMAINING");  // Text or value to print
    display.setCursor(0, 29);
    display.println(" HOURS   MIN.    SEC.");
    display.drawLine(0, 43, 128, 43, WHITE);  // Draw Horizontal line
    display.drawLine(42, 43, 42, 64, WHITE);  // Draw Vertictal line
    display.drawLine(84, 43, 84, 64, WHITE);  // Draw Vertictal line
    display.setFont(&SMLFONT);
    TimeCalc(TotalSeconds);
    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds
    --TotalSeconds;




    // Draw Progress Bar rectangle:
    display.drawRect(0, 22, 128, 1, WHITE);  // Draw rectangle (x,y,width,height,color)
    display.fillRect(0, 21, progress, 3, WHITE);  // It draws from the location to down-right
    progress++;
    if (progress > 127) {
      progress = 0;
    }


    //display.setFont(&FreeMonoBold12pt7b);  // Set a custom font


    // Print variable with left alignment:
    display.setFont();




    display.display();  // Print everything we set previously
    checkSwitch();      // check encoder switch
    if (buttonPressed) {
      Variable1 = 0;
      progress = 0;
      display.clearDisplay();
      display.display();
      return;
    }
  } while (Variable1 < 128);




}


void LiveMode() {
  // display.fillRect(0, 0, 128, 64, WHITE);
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.setCursor(10, 20);  // (x,y)
  display.setTextColor(WHITE);
  while (!buttonPressed) {
    display.println("Live Mode");
    display.display();
  }
  return;
}


void RecordMode() {
  // display.fillRect(0, 0, 128, 64, WHITE);
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.setCursor(10, 20);  // (x,y)
  display.setTextColor(WHITE);
  while (!buttonPressed) {
    display.println("Recording..");
    display.display();
  }
  return;
}


void LapseModeSet() {


  screen_Lapse();


  FlashBox hours(1, 36, 63, 27, 200, 200); // Construct flashing box (Hours)
  FlashBox mins(65, 36, 62, 27, 200, 200); // Construct flashing box (Minutes)
  FlashBox TL_set(0, 0, 128, 64, 300, 300); // Construct TL Done flashing box
  int mode = 0;  // 0 = hours selected   1 = minutes selected
  int valuechange = 0;


  encOld = 0;
  buttonPressed = 0;
  myEnc.write(0);
  do {




    do {


      encRead = myEnc.read() >> 2; // bitwise divide by 4
      if (encRead < encOld)
      {
        mode--;
        if (mode < 0) mode = 0;
        encOld = encRead;
        screen_Lapse();
      }
      if (encRead > encOld)
      {
        mode++;
        if (mode > 2) mode = 2;
        encOld = encRead;
        screen_Lapse();
      }




      switch (mode)
      {
        case 0:
          hours.Flasher();    // flash Hours Box
          break;
        case 1:
          mins.Flasher();     // flash Minutes Box
          break;
        case 2:
          TL_set.Flasher();   // flash whole screen Box
          break;
      }


      checkSwitch();
      if (buttonPressed)
      {
        buttonPressed = 0;
        valuechange = 1;
        if (mode == 0) myEnc.write(TL_hours);
        if (mode == 1) myEnc.write(TL_mins);
        screen_Lapse();
      }


    } while (!valuechange);






    do {
      if (mode == 0)   // Adjust Hours
      {
        display.drawRect(1, 36, 63, 27, WHITE);
        encRead = myEnc.read() >> 2; // bitwise divide by 4
        TL_hours = constrain(encRead, 0, 100);
        screen_Lapse();
        checkSwitch();
        if (buttonPressed)
        {
          valuechange = 0;
          buttonPressed = 0;
        }
      }


      if (mode == 1)   // Adjust Minutes
      {
        display.drawRect(65, 36, 62, 27, WHITE);
        encRead = myEnc.read() >> 2; // bitwise divide by 4
        TL_mins = constrain(encRead, 0, 59);
        screen_Lapse();
        checkSwitch();
        if (buttonPressed)
        {
          valuechange = 0;
          buttonPressed = 0;
        }
      }


      if (mode == 2)   // Quit to Main Menu
      {


        valuechange = 0;
        buttonPressed = 0;
        menuMode = 0;
        remainingSeconds = ((TL_hours * 60) * 60) + (TL_mins * 60);


      }


    } while (valuechange);










  } while (menuMode == 4);


}


void LapseModeRun() {
  //  Serial.begin(9600);
  TotalSeconds = remainingSeconds;
  int percent = 0;


  do {






    display.clearDisplay();  // Clear the display so we can refresh
    display.setFont(&SMLFONT);  // Set a custom font
    display.setTextSize(1);  // Set text size. We are using a custom font so you should always use the text size of 0
    display.setTextColor(WHITE);
    display.setCursor(0, 12);  // (x,y)
    display.print("Running ");
    display.setFont();
    display.setCursor(0, 30);  // (x,y)
    //        display.println("TIME REMAINING");  // Text or value to print
    display.setCursor(0, 29);
    display.println(" HOURS   MIN.    SEC.");
    display.drawLine(0, 43, 128, 43, WHITE);  // Draw Horizontal line
    display.drawLine(42, 43, 42, 64, WHITE);  // Draw Vertictal line
    display.drawLine(84, 43, 84, 64, WHITE);  // Draw Vertictal line
    display.setFont(&SMLFONT);
    TimeCalc(remainingSeconds);
    //Serial.print(h); Serial.print(" ");Serial.print(m); Serial.print(" ");Serial.println(s);
    display.setCursor(5, 62);
    display.println(h);    // Hours
    display.setCursor(54, 62);
    display.println(m);      // Minutes
    display.setCursor(97, 62);
    display.println(s);      // Seconds




    // Draw Progress Bar rectangle:
    progress = abs((((float)remainingSeconds / (float)TotalSeconds) * 128) - 128);
    percent = ((float)progress / 128) * 100;
    display.drawRect(0, 22, 128, 1, WHITE);  // Draw rectangle (x,y,width,height,color)
    display.fillRect(0, 21, progress, 3, WHITE);  // It draws from the location to down-right




    //display.setFont(&FreeMonoBold12pt7b);  // Set a custom font


    // Print variable with left alignment:
    display.setFont();
    display.setCursor(100, 5);
    display.print(percent);
    display.println("%");
    //    display.setCursor(80, 5);
    //    display.print(remainingSeconds);


    display.display();  // Print everything we set previously


    if (remainingSeconds == 0)
    {
      //display.getTextBounds("Running ",0,12,int x, int y, int ww, int hh);
      display.fillRect(0, 0, 70, 20, BLACK);
      display.setFont(&SMLFONT);
      display.setCursor(0, 12);  // (x,y)
      display.print("DONE ");
      display.display();
      delay(50000);
      menuMode = 0;
    }




    remainingSeconds--;             //          TICK!










    checkSwitch();      // check encoder switch
    if (buttonPressed) {
      buttonPressed = 0;
      menuMode = 0;
      display.clearDisplay();
      display.display();
      return;
    }
  } while (menuMode == 5);




}


void checkSwitch() {
  // Check Encoder Switch


  byte buttonState = digitalRead(EncButton);
  if (buttonState != oldButtonState)
  {
    if (millis () - buttonPressTime >= debounceTime)
    { // debounce
      buttonPressTime = millis ();                      // when we closed the switch
      oldButtonState =  buttonState;                    // remember for next time
      if (buttonState == LOW)
      {
        //        Serial.println ("Button pressed");               // DEBUGGING: print that button has been closed
        buttonPressed = 1;
      }
      else
      {
        //        Serial.println ("Button released");               // DEBUGGING: print that button has been opened
        buttonPressed = 0;
      }
    }  // end if debounce time up
  } // end of state change
}


void screen_Lapse() {
  display.setFont(&SMLFONT);
  display.setTextSize(0);
  display.clearDisplay();
  display.drawRect(0, 0, 128, 64, WHITE);  // Draw Border
  display.setCursor(4, 15);  // (x,y)
  display.setTextColor(WHITE);
  display.println("Set Timelapse");
  display.setFont();
  display.setCursor(0, 25);
  display.println("   HOURS     MINUTES");
  display.drawLine(0, 35, 128, 35, WHITE);  // Draw Horizontal line
  display.drawLine(64, 35, 64, 64, WHITE);  // Draw Vertictal line
  display.setFont(&SMLFONT);
  display.setCursor(17, 55);
  display.println(TL_hours);
  display.setCursor(85, 55);
  display.println(TL_mins);
  display.display();


}


void drawgrid() {
  display.drawRect(0, 0, 128, 64, WHITE);
  display.drawLine(64, 0, 64, 128, WHITE);
  display.drawLine(0, 32, 128, 32, WHITE);
}




// Adafruit Graphic library code references




// Draw triangle:
// display.drawTriangle(40,40,   50,20,   60,40, WHITE);  // Draw triangle. X, Y coordinates for three corner points defining the triangle, followed by a color


// Draw filled triangle:
//display.fillTriangle(0,35,   15,45,   30,63, WHITE);  // Draw filled triangle. X, Y coordinates for three corner points defining the triangle, followed by a color


// Draw line:
//  display.drawLine(0, 18, 128, 18, WHITE);  // Draw line (x0,y0,x1,y1,color)


// Draw circle:
// display.drawCircle(47, 36, 20, WHITE);  //  Draw circle (x,y,radius,color). X and Y are the coordinates for the center point


// Draw a filled circle:
// display.fillCircle(12, 27, 10, WHITE);  // Draw filled circle (x,y,radius,color). X and Y are the coordinates for the center point


// Draw rectangle:
// display.drawRect(58, 0, 18, 18, WHITE);  // Draw rectangle (x,y,width,height,color)
// It draws from the location to down-right


// Draw rounded rectangle and fill:
// display.fillRoundRect(58, 0, 18, 18, 5, WHITE);  // Draw filled rounded rectangle (x,y,width,height,color)
// It draws from the location to down-right
// Draw rounded rectangle:
//display.drawRoundRect(79, 37, 49, 27, 8, WHITE);  // Draw rounded rectangle (x,y,width,height,radius,color)
// It draws from the location to down-right


// Print variable with right alignment:
//  display.setCursor(83, 60);  // (x,y)
//  display.println(string);  // Text or value to print




//


//  // Convert Variable1 into a string, so we can change the text alignment to the right:
//  // It can be also used to add or remove decimal numbers.
//  char string[10];  // Create a character array of 10 characters
//  // Convert float to a string:
//  dtostrf(Variable1, 3, 0, string);  // (<variable>,<amount of digits we are going to use>,<amount of decimal digits>,<string name>)
 
Where in the code did you set 18:13? Is there a contant? If so does it have an L at the end to say it is a long value? Did you try to cast it there?

My guess it has to do with the line:
Code:
       remainingSeconds = ((TL_hours * 60) * 60) + (TL_mins * 60);

Which I believe remainingSeconds is defined: uint16_t remainingSeconds = 0;
So it will overflow with your 18:13...
 
Kurt,

Correct. The time is set in the LapseModeSet() function. It has to be a variable I can dial in. I tried setting remaingSeconds to uint32_t, but that causes problems much earlier.. at 9hrs 6minutes
 
Status
Not open for further replies.
Back
Top