Oled menu buttons interference on a retro watch

Hi all.

I'm new to Arduino programming and i am trying to make a simple menu for a retro watch using an oled , 3 push buttons and an esp32 c6 board. For now, I was able to make a digital and analog clock faces and a stop watch as a menu item. I have included a feature to edit time and date in place. For some reason the buttons meant for the menu are interfering with the time and date edit feature and iam not able to edit the time, I'm not sure how to fix this. All i was looking for is a simple watch logic like in Casio f91w. Attaching the code here.

#include <ESP32Time.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Initialize ESP32Time instance
ESP32Time rtc;

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int second, minute, hour;
int xcenter = 30, ycenter = 32; // Move analog clock 2 pixels left
float pi = 3.14159265359;
float angle = 0;
int x, y;

unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;

const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char* daysOfWeek[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// Time and date variables
//int hours = 12;
//int minutes = 0;
//int day = 1;
//int month = 1;  // Month range: 1-12
//int year = 2023;  // Starting year

// Menu navigation variables
int selectedField = 0;  // 0: Hours, 1: Minutes, 2: Day, 3: Month, 4: Year
bool editing = false;

// Function prototypes
void drawMenu();

// Button pins
#define MODE_BUTTON_PIN D2   // Mode button
#define SELECT_BUTTON_PIN D0 // Select button
#define SET_BUTTON_PIN D1    // Set button

// Menu states
enum MenuState {
  MENU_TIME_DATE,
  MENU_EDIT_TIME_DATE,
  MENU_STOPWATCH,
  MENU_12_24_HOUR,
  MENU_BRIGHTNESS,
  MENU_TEMPERATURE_HUMIDITY,
  MENU_COUNT
};
MenuState currentMenu = MENU_TIME_DATE;

// Brightness levels
int brightnessLevels[] = {10, 50, 100, 200};
int currentBrightnessIndex = 2;

// Internal RTC variables
unsigned long previousMillis = 0;
int seconds = 0, minutes = 0, hours = 15, day = 26, month = 12, year = 2024;
bool is24HourFormat = true;
bool settingTime = false;
int settingField = 0; // 0: Hours, 1: Minutes, 2: Day, 3: Month, 4: Year

// Stopwatch variables
bool stopwatchRunning = false;
unsigned long stopwatchStartTime = 0;
unsigned long stopwatchElapsedTime = 0;

void setup() {
  Serial.begin(115200);

  // Initialize display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.display();
  delay(2000);
  display.clearDisplay();

  // Initialize buttons
  pinMode(MODE_BUTTON_PIN, INPUT_PULLUP);
  pinMode(SELECT_BUTTON_PIN, INPUT_PULLUP);
  pinMode(SET_BUTTON_PIN, INPUT_PULLUP);

  // Initialize ESP32Time with a specific date and time (if needed)
  rtc.setTime(0, 16, 9, 29, 12, 2024); // Set to 12:00:00 on 1st Jan 2023
}

void loop() {

  // Check mode button to cycle through menu
  if (digitalRead(MODE_BUTTON_PIN) == LOW && (millis() - lastDebounceTime > debounceDelay)) {
    lastDebounceTime = millis();
    cycleMenu();
    delay(300); // Debounce delay
  }

  // Check select button to select the current menu option
  if (digitalRead(SELECT_BUTTON_PIN) == LOW && (millis() - lastDebounceTime > debounceDelay)) {
    lastDebounceTime = millis();
    selectMenuOption();
    delay(300); // Debounce delay
  }

  // Check set button to adjust settings in the current menu option
  if (digitalRead(SET_BUTTON_PIN) == LOW && (millis() - lastDebounceTime > debounceDelay)) {
    lastDebounceTime = millis();
    setMenuOption();
    delay(300); // Debounce delay
  }


  // Default display for clock
  if (currentMenu == MENU_TIME_DATE) {
    // Get current time from ESP32Time
    GetDateTime();

    // Display current time on OLED
    displayTime();

    // Draw analog clock
    drawAnalogClock();
    //delay(1000);
  }

  // Display stopwatch if in stopwatch menu
  if (currentMenu == MENU_STOPWATCH) {
    displayStopwatch();
  }

  if (currentMenu == MENU_EDIT_TIME_DATE) {
    // Update internal RTC time
    drawMenu();
    settingTime = !settingTime;
    if (!settingTime) {
      updateTime();
      rtc.setTime(seconds, minutes, hours, day, month, year); // Set to 12:00:00 on 1st Jan 2023
      display.println("Time/Date Set!");
      delay(1000);
    }
  }

}

void updateTime() {

// Button pins
//MODE_BUTTON_PIN D2   // Mode button
//SELECT_BUTTON_PIN D0 // Select button
//SET_BUTTON_PIN D1    // Set button

  // Handle button presses
  if (digitalRead(SELECT_BUTTON_PIN) == LOW && (millis() - lastDebounceTime > debounceDelay)) {
    lastDebounceTime = millis();
    if (editing) {
      selectedField = (selectedField + 1) % 5;  // Cycle through fields
    } else {
      editing = true;  // Enter editing mode
    }
    //drawMenu();
    delay(200);  // Debounce
  }

  if (digitalRead(SET_BUTTON_PIN) == LOW && (millis() - lastDebounceTime > debounceDelay)) {
    lastDebounceTime = millis();
    if (editing) {
      // Increment the selected field
      switch (selectedField) {
        case 0: hours = (hours + 1) % 24; break;
        case 1: minutes = (minutes + 1) % 60; break;
        case 2: day = (day % 31) + 1; break;
        case 3: month = (month % 12) + 1; break;
        case 4: year++; break;
      }
      //drawMenu();
      delay(200);  // Debounce
    }
  }

  if (digitalRead(MODE_BUTTON_PIN) == LOW && (millis() - lastDebounceTime > debounceDelay)) {
    lastDebounceTime = millis();
    if (editing) {
      editing = false;  // Exit editing mode
      displayTime();
      // Draw analog clock
      drawAnalogClock();
    }
    delay(200);  // Debounce
  }
}


void cycleMenu() {
  if (settingTime) {
    settingField = (settingField + 1) % 5; // Cycle through fields
  } else {
    currentMenu = static_cast<MenuState>((currentMenu + 1) % MENU_COUNT);
    displayMenu();
  }
}

void selectMenuOption() {
  display.clearDisplay();
  display.setCursor(0, 0);
  switch (currentMenu) {
    case MENU_TEMPERATURE_HUMIDITY:
      display.println("Show Temp/Humidity");
      displayTemperatureAndHumidity();
      return;
    case MENU_STOPWATCH:
      stopwatchRunning = !stopwatchRunning;
      if (stopwatchRunning) {
        stopwatchStartTime = millis() - stopwatchElapsedTime;
      } else {
        stopwatchElapsedTime = millis() - stopwatchStartTime;
      }
      break;
    case MENU_TIME_DATE:
      break;
    case MENU_EDIT_TIME_DATE:
      break;
    case MENU_12_24_HOUR:
      is24HourFormat = !is24HourFormat;
      display.println(is24HourFormat ? "24 Hour Mode" : "12 Hour Mode");
      break;
    case MENU_BRIGHTNESS:
      display.println("Adjust Brightness");
      display.println("Use Set button");
      break;
  }
  display.display();
}

void setMenuOption() {
  if (settingTime) {
    switch (settingField) {
      case 0: // Hours
        hours = (hours + 1) % 24;
        break;
      case 1: // Minutes
        minutes = (minutes + 1) % 60;
        break;
      case 2: // Day
        day = (day % 31) + 1;
        break;
      case 3: // Month
        month = (month % 12) + 1;
        break;
      case 4: // Year
        year++;
        break;
    }
  } else {
    display.clearDisplay();
    display.setCursor(0, 0);
    switch (currentMenu) {
      case MENU_STOPWATCH:
        if (!stopwatchRunning) stopwatchElapsedTime = 0;
        break;
      case MENU_BRIGHTNESS:
        currentBrightnessIndex = (currentBrightnessIndex + 1) % 4;
        analogWrite(OLED_RESET, brightnessLevels[currentBrightnessIndex]); // Simulate brightness adjustment
        display.println("Brightness:");
        display.print(brightnessLevels[currentBrightnessIndex]);
        display.println(" %");
        break;
      case MENU_TIME_DATE:
        break;
      case MENU_EDIT_TIME_DATE:
      /*settingTime = !settingTime;
        if (!settingTime) {
          //editing = true;
          updateTime();
          rtc.setTime(seconds, minutes, hours, day, month, year); // Set to 12:00:00 on 1st Jan 2023
          display.println("Time/Date Set!");
          delay(1000);
        }*/
        break;
      case MENU_12_24_HOUR:
        break;
      case MENU_TEMPERATURE_HUMIDITY:
        display.println("Adjustments not implemented");
        break;
    }
    display.display();
  }
}

void displayMenu() {
  display.clearDisplay();
  display.setCursor(0, 0);
  switch (currentMenu) {
    case MENU_TIME_DATE:
      display.println("Menu: Time/Date");
      break;
    case MENU_EDIT_TIME_DATE:
      display.println("Menu: Edit Time/Date");
      break;
    case MENU_STOPWATCH:
      display.println("Menu: Stopwatch");
      break;
    case MENU_12_24_HOUR:
      display.println("Menu: 12/24 Hour");
      break;
    case MENU_BRIGHTNESS:
      display.println("Menu: Brightness");
      break;
    case MENU_TEMPERATURE_HUMIDITY:
      display.println("Menu: Temp/Humidity");
      break;
  }
  display.display();
}

void GetDateTime() {
  second = rtc.getSecond();
  minute = rtc.getMinute();
  hour = rtc.getHour();
}

void displayTime() {
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(65, 0); // Adjusted to make space for the analog clock on the left

  display.printf("%02d:%02d:%02d", hour, minute, second);

  display.setCursor(65, 25);
  display.printf("%s", daysOfWeek[rtc.getDayofWeek()]);


  display.setTextSize(1);
  display.setCursor(65, 40);
  display.printf("%s %02d", months[rtc.getMonth()], rtc.getDay());

  display.setTextSize(1);
  display.setCursor(65, 50);
  display.printf("%04d", rtc.getYear());


  display.display();
}

void drawAnalogClock() {
  display.drawCircle(xcenter, ycenter, 30, SSD1306_WHITE);
  display.drawCircle(xcenter, ycenter, 2, SSD1306_WHITE);

  // Draw hour hand
  angle = ((hour % 12) + minute / 60.0) * 30;
  angle = angle * pi / 180;
  x = xcenter + 15 * sin(angle);
  y = ycenter - 15 * cos(angle);
  display.drawLine(xcenter, ycenter, x, y, SSD1306_WHITE);

  // Draw minute hand
  angle = (minute + second / 60.0) * 6;
  angle = angle * pi / 180;
  x = xcenter + 20 * sin(angle);
  y = ycenter - 20 * cos(angle);
  display.drawLine(xcenter, ycenter, x, y, SSD1306_WHITE);

  // Draw second hand
  angle = second * 6;
  angle = angle * pi / 180;
  x = xcenter + 25 * sin(angle);
  y = ycenter - 25 * cos(angle);
  display.drawLine(xcenter, ycenter, x, y, SSD1306_WHITE);

  // Draw clock markers
  for (int i = 0; i < 12; i++) {
    angle = i * 30 * pi / 180;
    x = xcenter + 28 * sin(angle);
    y = ycenter - 28 * cos(angle);
    int x2 = xcenter + 30 * sin(angle);
    int y2 = ycenter - 30 * cos(angle);
    display.drawLine(x, y, x2, y2, SSD1306_WHITE);
  }

  display.display();
}

void displayStopwatch() {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.setTextSize(2);

  unsigned long elapsed = stopwatchRunning ? millis() - stopwatchStartTime : stopwatchElapsedTime;
  int stopwatchSeconds = (elapsed / 1000) % 60;
  int stopwatchMinutes = (elapsed / (1000 * 60)) % 60;
  int stopwatchHours = (elapsed / (1000 * 60 * 60));
  int stopwatchmilliseconds = elapsed % 1000;
  display.print(stopwatchHours);
  display.print(":");
  if (stopwatchMinutes < 10) display.print("0");
  display.print(stopwatchMinutes);
  display.print(":");
  if (stopwatchSeconds < 10) display.print("0");
  display.print(stopwatchSeconds);
  display.print(":");
  if (stopwatchSeconds < 10) display.print("0");
  display.print(stopwatchmilliseconds);

  display.setTextSize(1);
  display.setCursor(0, 50);
  display.print(stopwatchRunning ? "Running" : "Stopped");

  display.display();
}


void displayTemperatureAndHumidity() {
  // float temp = dht.readTemperature();
  // float hum = dht.readHumidity();

  // if (isnan(temp) || isnan(hum)) {
  //   display.println("Failed to read sensor!");
  // } else {
  //   display.println("Temperature:");
  //   display.print(temp);
  //   display.println(" C");
  //   display.println("Humidity:");
  //   display.print(hum);
  //   display.println(" %");
  // }
  display.println("Temp/Humidity Disabled");
  display.display();
}

// Function to draw the menu on the OLED
void drawMenu() {
  display.clearDisplay();

  // Display current field being edited with highlight
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);  // Highlight selected field
  switch (selectedField) {
    case 0: display.setCursor(0, 0); display.print("Editing: Hour"); break;
    case 1: display.setCursor(0, 0); display.print("Editing: Minute"); break;
    case 2: display.setCursor(0, 0); display.print("Editing: Day"); break;
    case 3: display.setCursor(0, 0); display.print("Editing: Month"); break;
    case 4: display.setCursor(0, 0); display.print("Editing: Year"); break;
  }

  display.setTextSize(2);  // Larger size for values
  display.setCursor(0, 20);

  // Highlight the selected field
  if (selectedField == 0) {
    display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);  // Invert color
    display.printf("%02d", hours);
  } else {
    display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    display.printf("%02d", hours);
  }
  display.print(":");

  if (selectedField == 1) {
    display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
    display.printf("%02d", minutes);
  } else {
    display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    display.printf("%02d", minutes);
  }

  display.setTextSize(1);
  display.setCursor(0, 50);

  if (selectedField == 2) {
    display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
    display.printf("%02d", day);
  } else {
    display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    display.printf("%02d", day);
  }
  display.print("/");

  if (selectedField == 3) {
    display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
    display.printf("%02d", month);
  } else {
    display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    display.printf("%02d", month);
  }
  display.print("/");

  if (selectedField == 4) {
    display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
    display.printf("%04d", year);
  } else {
    display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
    display.printf("%04d", year);
  }

  display.display();
}

Describe "interfering"

When trying to edit time/date the select button will show strings of other menu items. The buttons were not configured correctly, i switched them and the issue is gone but now the time/date edit doesn't work, when i try to increment minutes, it will also increment hours at the same time. I have updated the code in the question.

Return the code in post #1 to its original form.

Post updates to the original code. Do not edit the original.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.