20x4 LCD i2c menu with rotary encoder

I need help with the code, I've asked chatgpt, it still doesn't work.
So I'm making a temp based watering system using max6675 and rotary encoder
This is the code I'm using rn for encoder and LCD

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

LiquidCrystal_I2C lcd(0x27, 20, 4);  // Set the I2C address to 0x27 and specify the columns and rows

#define PINA A0
#define PINB A1
#define PUSHB A2

Rotary r = Rotary(PINA, PINB, PUSHB);

int cursorLine = 1;
int displayFirstLine = 1;

#define MainMenu 0

const int maxItemSize = 11;

char startMenu[][maxItemSize] = {"Volume", "Reset"};

int Summary[] = {0, 0};

int menuItems;
char *menuSelected = NULL;
bool volumeHandler = false;
int volume = 0;
int menuOption = 0;

int backlightPin = 10;
int brightness = 255;
int fadeAmount = 5;

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 10000;

void setup()
{
  pinMode(PINA, INPUT);
  pinMode(PINB, INPUT);
  pinMode(PUSHB, INPUT);
  digitalWrite(PINA, HIGH);
  digitalWrite(PINB, HIGH);
  digitalWrite(PUSHB, HIGH);

  pinMode(backlightPin, OUTPUT);
  digitalWrite(backlightPin, HIGH);

  Wire.begin();
  lcd.begin(20, 4);
  welcome();
  lcd.clear();

  menuItems = sizeof(startMenu) / sizeof(startMenu[0]);
  menuSelected = &startMenu[0][0];
  menuOption = MainMenu;

  startMillis = millis();
  display_menu();
}

void loop()
{
  volatile unsigned char result = r.process();

  currentMillis = millis();
  lcd.setCursor(18, 0);
  lcd.print((currentMillis - startMillis) / 1000);
  if (currentMillis - startMillis >= period)
  {
    LCDfadeOut();
  }

  if (result)
  {
    init_backlight();
    if (result == DIR_CCW)
    {
      if (volumeHandler == true)
      {
        volume--;
        lcd.setCursor(0, 1);
        lcd.print("Volume: ");
        lcd.print(volume);
      }
    }
    else
    {
      if (volumeHandler == true)
      {
        volume++;
        lcd.setCursor(0, 1);
        lcd.print("Volume: ");
        lcd.print(volume);
      }
    }
  }

  if (r.buttonPressedReleased(25))
  {
    init_backlight();
    if (menuOption == MainMenu)
    {
      if (cursorLine == 1)
      {
        volumeHandler = !volumeHandler;
        lcd.clear();
        if (volumeHandler)
        {
          lcd.setCursor(0, 1);
          lcd.print("Volume: ");
          lcd.print(volume);
        }
        else
        {
          display_menu();
        }
      }
      else if (cursorLine == 2)
      {
        Reset();
        display_menu(); // added to display the menu after Reset
      }
    }
  }
}

void welcome()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Demo Menu  ");
  lcd.setCursor(0, 2);
  lcd.print("   Carlos Siles  ");
  lcd.setCursor(0, 3);
  lcd.print("   Version 1.0  ");
  delay(2000);
}

void display_menu()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Menu  ");

  for (int i = 0; i < menuItems; ++i)
  {
    lcd.setCursor(1, i + 1);
    lcd.print(startMenu[i]);

    if (i + 1 == cursorLine)
    {
      lcd.setCursor(0, i + 1);
      lcd.print("<");
    }
  }
}

void Reset()
{
  volume = 0;
  lcd.setCursor(0, 1);
  lcd.print("Volume: ");
  lcd.print(volume);
  menuOption = MainMenu; // set menuOption to MainMenu after Reset
}

void LCDfadeOut()
{
  while (brightness > 0)
  {
    lcd.setBacklight(brightness);
    brightness -= fadeAmount;
    delay(20);
  }
  lcd.noBacklight();
  lcd.clear();
}

void init_backlight()
{
  lcd.setBacklight(255);
  startMillis = millis();
  brightness = 255;
}

My plan is that there would be temp showing at the top after the menu then options named Threshold, duration, and interval, so I tried a sketch by someone named Carlos siles and only retained the volume option. Also other options like reset and summary are options I want to add. If you can, could you also add the rest of the code like the temp and relay mod and small water pump. Another prob I want to say is that the encoder increases the value by random like 1-2 or even more.
This is due tomorrow and I would be sad if I don't finish, this actually for research subject

so in a nutshell, this is a school project, you did not write anything yourself, you found a sketch online that does not work, you waited for the last minute and hoped chatGPT would solve it for you but it did not ?

did I get that right?

Ive actually finished this without the rotary encoder but they said I had to add buttons to change the temp thresholds and stuff, so that they didn't have to change the code. I've been trying for almost a month now and still not working. I have group mates but they don't know about code stuff so I was the one doing it

I would suggest you throw away that code if you copied it from someone so that you build something that you fully understand and are ready to explain to your teacher.

use the encoder library for the rotary
use Toggle for the button
use hd44780 for the LCD screen

here is a basic sketch showing how to put those together and update the screen when the rotary encoder is used or the button pressed

you might also benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

I'll try this out. Thanks

ok so I tried the code and whenever i try to move or press the encoder, it doesn't do anything, connections are accurate.

show a picture (in focus, clear) of your project
did you use the exact same code I gave you and the same wiring?


Is this good enough?

is there any issue with it?

ok so kept unplugging and plugging it back in and it finally worked. But I wanted to ask if you could help me with my project

so the LCD does turn on correctly - that's already a good sign

can you make sure the power reaches your rotary encoder?

try to move the rotary power pins next to the others
image

yes it works now

good :slight_smile:

Could you maybe help with setting up a menu in the lcd?

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

LiquidCrystal_I2C lcd(0x27, 20, 4);  // Set the I2C address to 0x27 and specify the columns and rows

#define PINA 3
#define PINB 2
#define PUSHB 4

Rotary r = Rotary(PINA, PINB, PUSHB);

int cursorLine = 1;
int displayFirstLine = 1;

#define MainMenu 0

const int maxItemSize = 11;

char startMenu[][maxItemSize] = {"Volume", "Reset"};

int Summary[] = {0, 0};

int menuItems;
char *menuSelected = NULL;
bool volumeHandler = false;
int volume = 0;
int menuOption = 0;

int backlightPin = 10;
int brightness = 255;
int fadeAmount = 5;

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 10000;

void setup()
{
  pinMode(PINA, INPUT);
  pinMode(PINB, INPUT);
  pinMode(PUSHB, INPUT);
  digitalWrite(PINA, HIGH);
  digitalWrite(PINB, HIGH);
  digitalWrite(PUSHB, HIGH);

  pinMode(backlightPin, OUTPUT);
  digitalWrite(backlightPin, HIGH);

  Wire.begin();
  lcd.begin(20, 4);
  welcome();
  lcd.clear();

  menuItems = sizeof(startMenu) / sizeof(startMenu[0]);
  menuSelected = &startMenu[0][0];
  menuOption = MainMenu;

  startMillis = millis();
  display_menu();
}

void loop()
{
  volatile unsigned char result = r.process();

  currentMillis = millis();
  lcd.setCursor(18, 0);
  lcd.print((currentMillis - startMillis) / 1000);
  if (currentMillis - startMillis >= period)
  {
    LCDfadeOut();
  }

  if (result)
  {
    init_backlight();
    if (result == DIR_CCW)
    {
      if (volumeHandler == true)
      {
        volume--;
        lcd.setCursor(0, 1);
        lcd.print("Volume: ");
        lcd.print(volume);
      }
      else // Update cursorLine for menu navigation
      {
        cursorLine--;
        if (cursorLine < 1) {
          cursorLine = menuItems;
        }
        display_menu();
      }
    }
    else
    {
      if (volumeHandler == true)
      {
        volume++;
        lcd.setCursor(0, 1);
        lcd.print("Volume: ");
        lcd.print(volume);
      }
      else // Update cursorLine for menu navigation
      {
        cursorLine++;
        if (cursorLine > menuItems) {
          cursorLine = 1;
        }
        display_menu();
      }
    }
  }

  if (r.buttonPressedReleased(25))
  {
    init_backlight();
    if (menuOption == MainMenu)
    {
      if (cursorLine == 1)
      {
        volumeHandler = !volumeHandler;
        lcd.clear();
        if (volumeHandler)
        {
          lcd.setCursor(0, 1);
          lcd.print("Volume: ");
          lcd.print(volume);
        }
        else
        {
          display_menu();
        }
      }
      else if (cursorLine == 2)
      {
        Reset();
        display_menu(); // added to display the menu after Reset
      }
    }
  }
}

void welcome()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Demo Menu  ");
  lcd.setCursor(0, 2);
  lcd.print("   Carlos Siles  ");
  lcd.setCursor(0, 3);
  lcd.print("   Version 1.0  ");
  delay(2000);
}

void display_menu()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Menu  ");

  for (int i = 0; i < menuItems; ++i)
  {
    lcd.setCursor(1, i + 1);
    lcd.print(startMenu[i]);

    if (i + 1 == cursorLine)
    {
      lcd.setCursor(0, i + 1);
      lcd.print("<");
    }
  }
}

void Reset()
{
  volume = 0;
  lcd.setCursor(0, 1);
  lcd.print("Volume: ");
  lcd.print(volume);
  menuOption = MainMenu; // set menuOption to MainMenu after Reset
}

void LCDfadeOut()
{
  while (brightness > 0)
  {
    lcd.setBacklight(brightness);
    brightness -= fadeAmount;
    delay(20);
  }
  lcd.noBacklight();
  lcd.clear();
}

void init_backlight()
{
  lcd.setBacklight(255);
  startMillis = millis();
  brightness = 255;
}

I tried this and it worked, now I'm thinking on how to add 2 more options that function like Volume, but don't know how to do it

you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

ok, um what is a good max6675 library? and is this code needed or can it be replaced?
thermocouple.begin();
because the library made by adafruit doesn't have it

I found another example that I had shared on wokwi with a menu

part of the code is in French but I'm sure your chatGPT friend can translate the variable names and comments in English

look at their examples

Ask ChatGPT for the schematic it used. How long did you wait until starting the project? I believe the answers to most of your questions were in the class lecture but you missed them. Hint: You can spend an hour on ChatGPT and get your code. You then spend about 6 to 8 days debugging it if you are lucky. If you start from scratch and write it yourself you have it running in less then 3 days and know why it works.