Clock Timer not converting to minutes correctly

I am currently using a 3 pin rotary encoder to set a time in a clock format (MM:SS). The rotary encoder works well both up and down, but when I go to convert the counter to a time it messes up when crossing a minute. When the counter gets 60 the clock should be 01:00, but I get 00:60, then going up one more I get 01:00 (should be 1:01), then it corrects itself and correctly reads 1:02 when you go up another. Also when going back down from 2:00 to 1:59 it will read 2:-1 instead of 1:59. I have this all connected to a screen right now displaying the actual count and the clock.

I think the error is in my timing code but I am honestly not sure. I am still new to Arduino and coding in general so I may be missing something obvious.

Code I have is below.

//Install "Adafruit_LiquidCrystal" Library
// To install go to tools in the ribbon > Manage Libraries > Search for "LiquidCrystal_PCF8574" in the box. Select the latest version and then install

// include the library code:
#include <LiquidCrystal_PCF8574.h>
#include <Wire.h>

LiquidCrystal_PCF8574 lcd(0x27);
//  Connect the backpack on back of the screen to the Arduino
// * 5V to Arduino 5V pin
// * GND to Arduino GND pin
// * SCL to Analog #5 (Or SCL)
// * SDA to Analog #4 (Or SDA)
// Connect via i2c, default address #0 (A0-A2 not jumpered)

//Setup for rotary encoder
// Rotary Encoder Inputs
#define inputCLK 4
#define inputDT 5
 int currentStateCLK;
 int previousStateCLK; 

// Steup the timer 
 float counter = 0; 
 int dispcount;
 int min1 = 0;
 int sec1 = 0;
 char buffer[6];
 
void setup() {


//Setup Rotary Encoder
   pinMode (inputCLK,INPUT);
   pinMode (inputDT,INPUT);
   digitalWrite(inputCLK, HIGH);
   digitalWrite(inputDT, HIGH);
   // Read the initial state of inputCLK
   // Assign to previousStateCLK variable
   previousStateCLK = digitalRead(inputCLK);

//   Setup Screen
// set up the LCD's number of columns and rows. Big Screen is (20,4), little screen is (16,2).
  lcd.begin(20, 4); // Put the columns and rows of the screen here
// Print a message to the LCD.
  lcd.setCursor(0,0); // First row is always 0
  lcd.print("Clock Count: ");
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0,2); 
  lcd.print("Actual Count: ");

}

void loop() {

    lcd.setBacklight(255); // Set backlight for screen
    
// Read the current state of inputCLK for encoder
   currentStateCLK = digitalRead(inputCLK); // Reads Encoder value

// Code for encoder 
              // If the previous and the current state of the inputCLK are different then a pulse has occured
              if (currentStateCLK != previousStateCLK){ 
      
                    if (digitalRead(inputDT) != currentStateCLK) { // If the inputDT state is different than the inputCLK state then the encoder is rotating counterclockwise
                     counter = counter - 1; // Increment by half to account for slop
           }
                    
                    else {// Encoder is rotating clockwise
                    counter = counter + 1; // Increment by half to account for slop
                          }  
                          dispcount = abs(counter);
                                                                                  // Begin Code for timing
                                                       if (sec1 == 60 && min1 >= 0) { // Resets seconds to 0 and increases minute when hitting 60s
                                                       min1 = min1 +1;
                                                       sec1 = 0; }
                                                       else if (sec1 < 0 && min1 >= 1){ // Resets seconds to 59 and decreses minute when hitting 0s
                                                       min1 = min1 -1;
                                                       sec1 = 59; }
                                                       else if (dispcount < 60){
                                                       sec1 = dispcount;
                                                       min1 = 0;}
                                                       else if (dispcount > 59){
                                                       sec1 = dispcount - (60*min1);} 
                                                       else if (dispcount == 60){
                                                        sec1 = dispcount - (60*min1);} 
                                                       else if (min1 > 10){
                                                       sec1 = 0;
                                                       min1 = 0;
                                                       dispcount = 0;
                                                       counter = 0; }
                                                       // End Code for Timing      
              }                   
                    previousStateCLK = currentStateCLK;  //Update previousStateCLK with the current state
                     

           sprintf(buffer, "%02d:%02d", min1, sec1);
           lcd.setCursor(0, 1); // Set Cursor to correct place           
           lcd.print(buffer); // Print Cycle ON time to screen
           lcd.setCursor(0, 3); // Set Cursor to correct place
           lcd.print(dispcount); // Print Cycle OFF time to screen
}

you only have one big if/else if / else if / else
The first part deals with sec & minutes and if you enter one of those, you'll ignore the part dealing with the counter

I changed them to if statements and cleaned it up a little and it works when counting up but not down. It goes from 2:00 to 2:-1 to 1:58.

Updated Code below:

                                                                                  // Begin Code for timing
                                                       if (sec1 == 59 && min1 >= 0) { // Resets seconds to 0 and increases minute when hitting 60s
                                                       min1 = min1 +1;
                                                       sec1 = 0; 
                                                       }
                                                       if (sec1 < 0 && min1 >= 1){ // Resets seconds to 59 and decreses minute when hitting 0s                                                
                                                       sec1 = 59;        
                                                       min1 = min1 - 1;                                        
                                                       }
                                                       if (dispcount <= 59){
                                                       sec1 = dispcount;
                                                       min1 = 0;                                                     
                                                       }
                                                       else {
                                                       sec1 = dispcount - (60*min1);} 

                                                       // End Code for Timing     

Put the code aside for a bit and explain what you want to do In plain English

If the rotary encoder value has changed then …

See if it works on a few manual examples, then write code that does this.


Alternatively
Hint for a change: it’s easier to work in seconds and calculate the minutes and seconds when needed

If the rotary encoder value changes I want the value to change on a clock timer. So every time the the encoder goes up by 1 or down by 1 the clock does the same. So when rotary encoder value goes from 119 to 120 the clock value goes 01:59 to 02:00. And also if the rotary encoder value goes from from 120 to 119 the clock value goes 2:00 to 1:59. The latter is the part that is not working for me.

I am using the rotary encoder value to convert it time. So every 60 increments of the rotary encoder is 1:00 minute. The clock time is just for a display value. The actual rotary encoder value is what I will be using to control the time.

Could You please use the autoformat in the IDE before copying? Parts of the code prints outside my screen....

Can the rotary change by more than 1 in a given loop?

Why not just increment and decrement seconds and then convert the result

++seconds;
....
       sprintf(buffer, "%02d:%02d", seconds/60, seconds%60);
1 Like

Brilliant! Count seconds only, nothing else...

That was the hint in #4 but before OP needs to get it right….

A teachers psychological approach....

There are 60 seconds in a minute, not 59.

That makes it way easier thank you. I did not know I could divide integers like that, or increment with ++ for that matter. What does the %60 after seconds do? seconds%60

I am new to C++ and Arduino so I do not know many functions or commands.

Check out the reference and tutorials section on this site.

1 Like

this is the modulo operator. it gives you the remainder of a division

for example 10 / 3 = 3 and remainder is 1

so when you do integer math 10 / 3 = 3 and 10 % 3 = 1

➜ by taking the modulo by 60, you get the seconds (as the remainder will always be between 0 and 59)

1 Like

as explained here
https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/remainder/

1 Like