Go Down

Topic: LCD Encoder Menu (Read 937 times) previous topic - next topic

dizzwold

Hi,

 Something else I've noticed is from the serial print.

 Can someone advise me a better way to read the reading's of the encoder, so the serial monitor will print the direction or the switch and then the reading "xxxx", for example;

CW xxxx
CCW xxxx
SW xx

 What I've noticed with the current serial print "I know, not the best", it starts with "1111", on a CW rotation of 1 detent I get "0011", on a CCW rotation of 1 detent I get "0011" and on the push of the switch I get "01"
 So I'm getting 4 reading's with each rotation, but only 2 reading's with a push of the switch. So I've tried the skatch by removing the divide by 4;
Code: [Select]
long newP = myEnc.read() / 4;
To;
Code: [Select]
long newP = myEnc.read();

 This seem's to still work correctly for the rotation of the encoder and the switch to toggle the LED, allthough with rotating the encoder a speed still sometimes changes the LED state.

 I think a better serial print would help.

 I've also commented-out the button pin 53 and it's pin mode as this may also be causing conflicts;
Code: [Select]
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <Encoder.h>
Encoder myEnc(20, 21);

//Input & Button Logic
const int numOfInputs = 3;
const int inputPins[numOfInputs] = {20, 21, 53};
int inputState[numOfInputs];
int lastInputState[numOfInputs] = {LOW, LOW, LOW};
bool inputFlags[numOfInputs] = {LOW, LOW, LOW};
long lastDebounceTime[numOfInputs] = {0, 0, 0};
long debounceDelay = 10;
int backlight_pin10 = 10;

//LCD Menu Logic
const int numOfScreens = 10;
int currentScreen = 0;
const char* screens[numOfScreens][2] = {{"1Motor Voltage", "Volts"}, {"2Motor Current", "Amps"},
  {"3Motor Rated HP", "HP"}, {"4Overload Temp.", "degC"}, {"5Accel Time", "Secs"}, {"6Restart Time", "Mins"},
  {"7Analog Out. Curr.", "mA"}, {"8Input Temp.", "degC"}, {"9Run Time", "Hours"}, {"10Start Times", "times"}
};
//int button = 53;
int led = 13;
int dizzwold = false;
int parameters[numOfScreens];

void setup() {
  pinMode(backlight_pin10, OUTPUT);
  analogWrite(10, 200);
  for (int i = 0; i < numOfInputs; i++) {
    pinMode(inputPins[i], INPUT);
    digitalWrite(inputPins[i], HIGH); // pull-up 20k
  }
  pinMode(led, OUTPUT);
  //pinMode(button, INPUT_PULLUP); // set the internal pull up resistor, unpressed button is HIGH
  Serial.begin(9600);
  lcd.begin(20, 4);
}

long old = 0;

void loop() {
  setInputFlags();
  resolveInputFlags();

}

void setInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    int reading = digitalRead(inputPins[i]);
    if (reading != lastInputState[i]) {
      lastDebounceTime[i] = millis();
      Serial.println(reading);
    }
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
      if (reading != inputState[i]) {
        inputState[i] = reading;
        if (inputState[i] == HIGH) {
          inputFlags[i] = HIGH;
        }
      }
    }
    lastInputState[i] = reading;
  }
}

void resolveInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    if (inputFlags[i] == HIGH) {
      inputAction(i);
      inputFlags[i] = LOW;
      printScreen();
    }
  }
}

void inputAction(int input)
{
  long newP = myEnc.read();
  {
    if (input == 0)
    {
      if (newP < old)
      {
        old = newP;
        if (currentScreen == 0 && 1)
        {
          currentScreen = numOfScreens - 1;
        }
        else
        {
          currentScreen--;
        }
      }
    }
    else if (input == 1)
    {
      if (newP > old)
      {
        old = newP;
        if (currentScreen == numOfScreens - 1)
        {
          currentScreen = 0;
        }
        else
        {
          currentScreen++;
        }
      }
    }

    else if (input == 2);
    {
      dizzwold = ! dizzwold;
      digitalWrite(led, dizzwold);
      if (newP < old)
        old = newP;
      {
        parameterChange(1);
      }
      if (newP > old)
        old = newP;
      {
        parameterChange(0);
      }
    }
  }
}




void parameterChange(int key) {
  if (key == 0) {
    parameters[currentScreen]++;
  } else if (key == 1) {
    parameters[currentScreen]--;
  }
}

void printScreen() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(screens[currentScreen][0]);
  lcd.setCursor(0, 1);
  lcd.print(parameters[currentScreen]);
  lcd.print(" ");
  lcd.print(screens[currentScreen][1]);
}


 Also once I'm in the input 2, I think I may need another "if or while statement for input 0 then check and input 1 then check?

 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dougp

Before moving on to being able to change the values or parameters, one thing I have noticed is when loading the sketch /start  /boot, the LED is high and on, push the encoder switch and the change of state works fine, on, off, on, off etc, but if I rotate the encoder really fast this also sometimes changes the state of the LED. Is this just because these are cheap encoders?
That's a new one!  I suppose it's possible that the vibration set up by turning the knob very fast could cause the switch contacts to bounce without the button actually being pressed.  Maybe it's a harmonic thing?

I used this one and have not seen that behavior.  'Course I wasn't testing for high RPM!

dougp

Also once I'm in the input 2, I think I may need another "if or while statement for input 0 then check and input 1 then check?
To what end?

dizzwold

#18
Dec 08, 2017, 02:44 am Last Edit: Dec 08, 2017, 02:14 pm by dizzwold
Hi dougp,

This is the unit I have;
http://www.everbuying.net/product695285.html
* Edited Link

Quote
Also once I'm in the input 2, I think I may need another "if or while statement for input 0 then check and input 1 then check?
Quote
To what end?
I thought this may be needed once in the input 2 to state now expect an iput from 0 or 1 that would be an up or down.

 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dougp

#19
Dec 08, 2017, 05:12 am Last Edit: Dec 08, 2017, 05:13 am by dougp
Third time,

the only activity in if(input == 2) should be toggling the menu select variable.
p.s. link above goes to a sign in screen

dizzwold

Hi,

 Sorry about the link, now edited.

 Regarding the RPM, this was not my intention either, but was something I did by accident and noticed that it somehow had changed the stat of the LED.

 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dougp

Encoder: is there a real knob mounted or, are you turning the bare shaft?

dizzwold

Hi,

 I have a knob fitted to the encoder.

 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dizzwold

#23
Dec 08, 2017, 03:31 pm Last Edit: Dec 08, 2017, 03:56 pm by dizzwold
Hi,

 One thought I have had regarding the encoder being rotated fast and effecting the LED state;

 Allthough I have a software debounce I don't have any caps fitted to the circuit for a hardware debounce, such as a .47uf cap on both DT and CLK to ground.

 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dizzwold

Hi,

 This all seem's to be working.

 When I press the encoder switch "input 2", I can change the state of the LED on and off, but I still can't get into changing the value or parameters.

 What am I missing?
Code: [Select]
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <Encoder.h>
Encoder myEnc(20, 21);

//Input & Button Logic
const int numOfInputs = 3;
const int inputPins[numOfInputs] = {20, 21, 53};
int inputState[numOfInputs];
int lastInputState[numOfInputs] = {LOW, LOW, LOW};
bool inputFlags[numOfInputs] = {LOW, LOW, LOW};
long lastDebounceTime[numOfInputs] = {0, 0, 0};
long debounceDelay = 10;
int backlight_pin10 = 10;

//LCD Menu Logic
const int numOfScreens = 10;
int currentScreen = 0;
const char* screens[numOfScreens][2] = {{"1Motor Voltage", "Volts"}, {"2Motor Current", "Amps"},
  {"3Motor Rated HP", "HP"}, {"4Overload Temp.", "degC"}, {"5Accel Time", "Secs"}, {"6Restart Time", "Mins"},
  {"7Analog Out. Curr.", "mA"}, {"8Input Temp.", "degC"}, {"9Run Time", "Hours"}, {"10Start Times", "times"}
};
//int button = 53;
int led = 13;
int dizzwold = false;
int parameters[numOfScreens];

void setup() {
  pinMode(backlight_pin10, OUTPUT);
  analogWrite(10, 200);
  for (int i = 0; i < numOfInputs; i++) {
    pinMode(inputPins[i], INPUT);
    digitalWrite(inputPins[i], HIGH); // pull-up 20k
  }
  pinMode(led, OUTPUT);
  //pinMode(button, INPUT_PULLUP); // set the internal pull up resistor, unpressed button is HIGH
  Serial.begin(9600);
  lcd.begin(20, 4);
}

long old = 0;

void loop() {
  setInputFlags();
  resolveInputFlags();

}

void setInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    int reading = digitalRead(inputPins[i]);
    if (reading != lastInputState[i]) {
      lastDebounceTime[i] = millis();
      Serial.println(reading);
    }
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
      if (reading != inputState[i]) {
        inputState[i] = reading;
        if (inputState[i] == HIGH) {
          inputFlags[i] = HIGH;
        }
      }
    }
    lastInputState[i] = reading;
  }
}

void resolveInputFlags() {
  for (int i = 0; i < numOfInputs; i++) {
    if (inputFlags[i] == HIGH) {
      inputAction(i);
      inputFlags[i] = LOW;
      printScreen();
    }
  }
}

void inputAction(int input)
{
  long newP = myEnc.read();
  {
    if (input == 0)
    {
      if (newP < old)
      {
        old = newP;
        if (currentScreen == 0 && 1)
        {
          currentScreen = numOfScreens - 1;
        }
        else
        {
          currentScreen--;
        }
      }
    }
    else if (input == 1)
    {
      if (newP > old)
      {
        old = newP;
        if (currentScreen == numOfScreens - 1)
        {
          currentScreen = 0;
        }
        else
        {
          currentScreen++;
        }
      }
    }

    else if (input == 2);
    {
      dizzwold = ! dizzwold;
      digitalWrite(led, dizzwold);
      if (newP < old)
        old = newP;
      {
        parameterChange(1);
      }
      if (newP > old)
        old = newP;
      {
        parameterChange(0);
      }
    }
  }
}




void parameterChange(int key) {
  if (key == 0) {
    parameters[currentScreen]++;
  } else if (key == 1) {
    parameters[currentScreen]--;
  }
}

void printScreen() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(screens[currentScreen][0]);
  lcd.setCursor(0, 1);
  lcd.print(parameters[currentScreen]);
  lcd.print(" ");
  lcd.print(screens[currentScreen][1]);
}


 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dizzwold

Hi dougp,
Quote
the only activity in if(input == 2) should be toggling the menu select variable.
So I only do this in input 2;
Code: [Select]
else if (input == 2);
    {
      dizzwold = ! dizzwold;
      digitalWrite(led, dizzwold);
}


 Where do I put what I want it to do;
Code: [Select]
if (newP < old)
        old = newP;
      {
        parameterChange(1);
      }
      if (newP > old)
        old = newP;
      {
        parameterChange(0);
      }


 Do I put that in a seperate void?

 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dougp

When the encoder changes , you look at dizzwold.  If dizzwold indicates that menu items are to be changed then call a function which uses the encoder value, CW or CCW, to update the screen with new cursor position/titles displayed, whatever.  Keep track of which menu is active.  Triggering on the change, which is only active for one pass through loop(), lets you make one call to update whichever mode is active then that code is inactive 'til encoder moves again.

If dizzwold indicates that parameter values  are to be changed then you cycle/scroll through the options for the currently active menu.

You can have separate functions for these operations or a single function which does both.  I used a single function with switch/case to select which is to be done but if() statements will work too.


dougp

Where do I put what I want it to do;
Code: [Select]
if (newP < old)
        old = newP;
      {
        parameterChange(1);
      }
      if (newP > old)
        old = newP;
      {
        parameterChange(0);
      }


 Do I put that in a seperate void?

 Dizzwold.
Let's establish some common ground.  Can you create an int called encCount and increment/decrement it by rotating the encoder?

dizzwold

Hi dougp,

 Do you mean something like this;
Code: [Select]
#include <LiquidCrystal.h>
#include <Encoder.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
Encoder myEnc(20, 21);
int backlight_pin10 = 10;

void setup()
{
  pinMode(backlight_pin10, OUTPUT);
  analogWrite(10, 200);
  lcd.begin(20, 4);
  Serial.begin(9600);
}

int old  = 0;

void loop()
{
  int encCount = myEnc.read();
  if (encCount != old)
  {
    old = encCount;
    lcd.setCursor(2, 0);
    lcd.print(encCount / 4);
    Serial.println(encCount / 4);
  }
}


 A simpler version without LCD, serial print only;
Code: [Select]

#include <Encoder.h>
Encoder myEnc(20, 21);

void setup()
{
  Serial.begin(9600);
}

int old  = 0;

void loop()
{
  int encCount = myEnc.read();
  if (encCount != old)
  {
    old = encCount;
    Serial.println(encCount / 4);
  }
}


 Dizzwold.
I'm not a student or a lecturer. I'm a hobbyist.

dougp

No.  Doesn't the encoder library return some information telling which way the encoder was turned?

For example, my encoder ISR (interrupt service routine) returns a value thusly:
Code: [Select]
/* Interrupt Service Routine for rotary encoder:
   An interrupt is generated any time either of
   the rotary inputs change state.
*/
void rotate() {
  byte result = rotary.process();
  if (result == DIR_CW) {
    IRQcounter++;
  } else if (result == DIR_CCW) {
    IRQcounter--;
  }
}


IRQcounter (a volatile) conditions the variable the main code uses to detect a . encoder movement and, b . which direction

Code: [Select]
/*
      After clearing any previous encoderTurned value, check
      the count value returned from the ISR to see if the
      rotary encoder has moved. If it has, then a new IRQ has
      been recognized and encoderTurned will be loaded with
      and hold the direction value for one scan only.
  */
  encoderTurned = 0;  // Reset previous turned value.
  if (IRQActivity != IRQcounter) {
    if (IRQcounter > IRQActivity) encoderTurned = DIR_CW;
    if (IRQcounter < IRQActivity) encoderTurned = DIR_CCW;
    IRQActivity = IRQcounter; // reset one-shot value to be ready for next IRQ
  }

encoderTurned != zero initiates a call of the menu navigation function which uses encoderTurned to move through the active selection - menu items or parameters.

Go Up