Setup Menu with encoder

I am working on a project and I am struggling with a starting point. If someone could help with an example that would be great. I am trying to set an INT "speed" with user inputs from a rotary encoder only once in the setup menu. When it is done I would like the program to run this way until the unit dies.

rotation speed is what I am trying to control.
I am using an LCD and a ky-404 with push button.
I want to display "Movement speed?"
speed = 4
as the encoder turns it will -.1or +.1 until it reaches 0 or 8.
after the user pushes the button I would like it to ask is speed 5.2 correct. Then allow for a yes/no from the encoder + number for yes -number for no. If yes then move on if no go back to the previous menu.
If someone has an example of something like this that I could learn from that would be great. I was thinking it would need to be in a while loop but I'm not sure. Thank you for your time.

If you have not yet tried, search "arduino rotary encoder motor speed" for many examples.

In programing courses they tell the way to describe program/code flow. It's not like Shakespeare did his work.
Such diagram is a greate help when coding.
Expect the code You want to be none existent. You need to make it.
Start by exploring rotary encoder examples.
Explore how to read buttons.

I do not have code yet. I have been searching to find an example. I have read a few but I have been stuck the past few days. Everything I have been finding is in the void loop. menus and so on. I just need to ask one question at the start followed by a confirmation.

Write a minimal sketch to read your input devices and make an output depending on your selection.

Where will you display the menu? What if you "blink" LED_BUILTIN, one blink for speed one, two blinks for speed two, three, four.

Try to describe your idea like no one has seen it before, like "Step one, power on. Step two look at menu (whatever that is). Step three adjust rotary switch for x through y"...

Any code in the loop() function can be moved to the setup() function. Or it can be moved into its own function and called from setup() and/or loop().

In the setup loop There is a forced choice. Call it RPM speed setting
I am thinking I would need to put this in While loop but i am not sure.
"What Speed?"
Speed = 4
user uses the dial and changes the setting to 5.2
display now reads
What Speed?
Speed = 5.2
pushbutton for accept
"Is 5.2 correct?
Roll CW "yes"
Rolls CCW "no"
push button.
If yes set new value
if no go back to x line in the code and repeat.
I can use the encoder I can use the LCD. I am not sure how to keep it from skipping over and waiting for a user input. I think a While loop but I'm not sure. Also I don't know how to send it back. This is what has me pulling my hair out. My issue is I am not sure how to look it up because I am struggling with what to look for.

What type of display are you using?

I2C IIC 1602 LCD Display Module 16x02

Put all your devices in a wiring diagram and post it here. You can pencil/paper draw it, but it must be legible.

bool done = false;
while ( !done ) {
  set_speed();  // function returns when user pushes button
  done = confirm();  // function returns true if user accepts, false otherwise
}
...

writing set_speed() and confirm() are left as an exercise for the reader :slight_smile:

I cant Draw...

1 Like

: )

It looks like you use Wokwi. Click on the encoder, then click the question-mark "?" beside the encoder, and you will be directed to the following page... with a good explanation of the device, and a few example programs.

I found a great example. I have been playing with the code for a bit and I cant get it to increment by (.1). if i put counter -= .1 it wont display anything. I changed the starting counter to 4.1 and it wont display the (.1).

/* KY-040 Rotary Encoder Counter

   Rotate clockwise to count up, counterclockwise to counter done.

   Press to reset the counter.

   Copyright (C) 2021, Uri Shaked
*/

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define ENCODER_CLK 2
#define ENCODER_DT  3
#define ENCODER_SW  4

int counter = 4.1;


void setup() {
  // Initialize LCD
  lcd.init();
  lcd.backlight();

  // Initialize encoder pins
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
}

void readEncoder() {
  int dtValue = digitalRead(ENCODER_DT);
  if (dtValue == HIGH) {
    counter ++; // Clockwise
  }
  if (dtValue == LOW) {
    counter -- ; // Counterclockwise
  }
}

// Get the counter value, disabling interrupts.
// This make sure readEncoder() doesn't change the value
// while we're reading it.
int getCounter() {
  int result;
  noInterrupts();
  result = counter;
  interrupts();
  return result;
}

void resetCounter() {
  noInterrupts();
  counter = 0;
  interrupts();
}

void loop() {
  lcd.setCursor(3, 0);
  lcd.print("Counter:");
  lcd.setCursor(7, 1);
  lcd.print(getCounter());
 

  if (digitalRead(ENCODER_SW) == LOW) {
    resetCounter();
  }
}

I am certain that Uri Shaked did not present a non-working sketch Check your copy/pasting, and wiring.

I see what you meant... these are not "int" rather "float"

int counter = 4.1;
int result;
int getCounter() {

Change to float... and change your counter++ and counter-- to counter+=.1 and counter-=.1

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define ENCODER_CLK 2
#define ENCODER_DT  3
#define ENCODER_SW  4

float counter = 4.1;


void setup() {
  // Initialize LCD
  lcd.init();
  lcd.backlight();

  // Initialize encoder pins
  pinMode(ENCODER_CLK, INPUT);
  pinMode(ENCODER_DT, INPUT);
  pinMode(ENCODER_SW, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
}

void readEncoder() {
  int dtValue = digitalRead(ENCODER_DT);
  if (dtValue == HIGH) {
    counter+=.1; // Clockwise
  }
  if (dtValue == LOW) {
    counter -=.1 ; // Counterclockwise
  }
}

// Get the counter value, disabling interrupts.
// This make sure readEncoder() doesn't change the value
// while we're reading it.
float getCounter() {
  float result;
  noInterrupts();
  result = counter;
  interrupts();
  return result;
}

void resetCounter() {
  noInterrupts();
  counter = 0;
  interrupts();
}

void loop() {
  lcd.setCursor(3, 0);
  lcd.print("Counter:");
  lcd.setCursor(7, 1);
  lcd.print(getCounter());
 

  if (digitalRead(ENCODER_SW) == LOW) {
    resetCounter();
  }
}

Is changing it to float all you had to do?

The two variables AND the return type of one function... change to float.

I want you to understand why changing the function return type to float was important... would you describe it so we know that you know?

a float can hold a decimal number. I changed the counter to a float once but I didn't catch the other 2. Thank you

1 Like

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