Problem replacing encoder code with push button

I had found a pieces of code for st7735 display Menu item. In this code the an rotatory encoder was using.

But I don't have this encoder. So I want to do this using three push button. So I needed some modification of this code. How can I do this ? Here is the code:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include "RREFont.h"
#include "rre_fjg_8x16.h"
#include "rre_5x8.h"

#define TFT_CS   8
#define TFT_RST  7
#define TFT_DC   6

#define SCR_WD   128
#define SCR_HT   160

// use 3 debouncing capacitors (100nF seems to be enough)
#define encoderPinA    4
#define encoderPinB    3
#define encoderButton  2
#include <Arduino_ST7735_Fast.h>

Arduino_ST7735 lcd = Arduino_ST7735(TFT_DC, TFT_RST, TFT_CS);

RREFont font;
// needed for RREFont library initialization, define your fillRect
void customRect(int x, int y, int w, int h, int c) {
  return lcd.fillRect(x, y, w, h, c);
}

#include <EEPROM.h>

// -------------------------
volatile int encoderPos = 0, encoderPosOld = 0, encoderStep = 2;

void initEncoder()
{
  encoderPos = 0;
  pinMode(encoderPinA,   INPUT_PULLUP);
  pinMode(encoderPinB,   INPUT_PULLUP);
  pinMode(encoderButton, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(encoderPinA), readEncoderInt, CHANGE);  // encoder pin on interrupt 0 = pin 2
  attachInterrupt(digitalPinToInterrupt(encoderButton), buttonInt, CHANGE);  // encoder pin on interrupt 1 = pin 3
}

void buttonInt() {}

void readEncoderInt()
{
  //(digitalRead(encoderPinA) == digitalRead(encoderPinB)) ? encoderPos++ : encoderPos--;
  uint8_t pd = PIND & B10100; // inputs #2 and #4 direct reading
  ((pd == B10100) || (pd == B00000)) ? encoderPos++ : encoderPos--;
}

int readButton()
{
  const long btDebounce = 30;
  static long btTime = 0;
  static int lastState = HIGH;
  int val = 0, state = digitalRead(encoderButton);
  if (state == LOW && lastState == HIGH) {
    btTime = millis();
    val = 0;
  }
  if (state == HIGH && lastState == LOW && millis() - btTime >= btDebounce) {
    val = 1;
  }
  lastState = state;
  return val;
}

// -------------------------
long readVcc()
{
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA, ADSC));
  result = ADCL;
  result |= ADCH << 8;
  result = 1125300L / result; // Back-calculate AVcc in mV
  return result;
}

float readIntTemp()
{
  long result;
  // Read temperature sensor against 1.1V reference
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
  delay(5); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA, ADSC));
  result = ADCL;
  result |= ADCH << 8;
  result = (result - 125) * 1075;
  return result / 10000.0;
}

// -------------------------
#define MAXSIN 255
const uint8_t sinTab[91] PROGMEM = {
  0, 4, 8, 13, 17, 22, 26, 31, 35, 39, 44, 48, 53, 57, 61, 65, 70, 74, 78, 83, 87, 91, 95, 99, 103, 107, 111, 115, 119, 123,
  127, 131, 135, 138, 142, 146, 149, 153, 156, 160, 163, 167, 170, 173, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, 208, 211, 213, 216, 218,
  220, 223, 225, 227, 229, 231, 232, 234, 236, 238, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251, 251, 252, 253, 253, 254, 254, 254, 254, 254,
  255
};

int fastSin(int i)
{
  while (i < 0) i += 360;
  while (i >= 360) i -= 360;
  if (i < 90)  return (pgm_read_byte(&sinTab[i])); else if (i < 180) return (pgm_read_byte(&sinTab[180 - i])); else if (i < 270) return (-pgm_read_byte(&sinTab[i - 180])); else
    return (-pgm_read_byte(&sinTab[360 - i]));
}

int fastCos(int i)
{
  return fastSin(i + 90);
}

char buf[100];

void drawGauge1(int level)
{
  int sx, sy, xs0, ys0, xe0, ye0, xs1, ys1, xe1, ye1;
  int cx = SCR_WD / 2;
  int cy = SCR_HT / 2;
  int rx0 = 40, ry0 = 40;
  int rx1 = 63, ry1 = 63;
  int mina = -60;
  int maxa = 180 + 60;
  for (int i = mina; i < maxa; i += 15) { // 22 pieces
    sx = fastCos(i - 180);
    sy = fastSin(i - 180);
    xs0 = cx + sx * rx0 / MAXSIN;
    ys0 = cy + sy * ry0 / MAXSIN;
    xe0 = cx + sx * rx1 / MAXSIN;
    ye0 = cy + sy * ry1 / MAXSIN;
    sx = fastCos(i - 180 + 10);
    sy = fastSin(i - 180 + 10);
    xs1 = cx + sx * rx0 / MAXSIN;
    ys1 = cy + sy * ry0 / MAXSIN;
    xe1 = cx + sx * rx1 / MAXSIN;
    ye1 = cy + sy * ry1 / MAXSIN;
    int l = 20 * (i - mina) / (maxa - mina);
    uint16_t c = (l < level) ? lcd.rgbWheel(512L * l / 20) : RGBto565(60, 60, 60);
    lcd.fillTriangle(xs0, ys0, xe0, ye0, xe1, ye1, c);
    lcd.fillTriangle(xs1, ys1, xe1, ye1, xs0, ys0, c);
  }
  snprintf(buf, 10, "%02d", level);
  font.setColor(WHITE, BLACK);
  font.printStr(ALIGN_CENTER, SCR_HT / 2 - 7, buf);
}

// -------------------------

char *menuTxt[] = {
  "Set value",     // 0
  "Help",          // 1
  "MCU Temp",      // 2
  "VCC/Battery",   // 3
  "EEPROM dump",   // 4
  "Graph",         // 5
  "Bckgrnd color", // 6
  "Item color",    // 7
  "Frame color",   // 8
  "Slider color",  // 9
  "About",         // 10
  "Reboot"         // 11
};

const int itemHt = 20;
const int numMenus = sizeof(menuTxt) / sizeof(char*);
const int numScrLines = SCR_HT / itemHt; // 160/20=8
int menuSel = 0, menuSelOld = 0;
int menuStart = 0;
int menuMode = -1; // -1 -> menu of options, 0..n -> option
int storedPos = 0;

uint16_t bgCol     = RGBto565(30, 30, 140);
uint16_t frameCol  = RGBto565(255, 255, 40);
uint16_t itemCol   = RGBto565(220, 220, 220);
uint16_t sliderCol = RGBto565(20, 180, 180);

void showHelp()
{
  lcd.fillScreen(RGBto565(150, 0, 0));
  font.setColor(WHITE);
  font.printStr(ALIGN_CENTER, 4, "Help");
  font.setColor(YELLOW);
  font.setCR(1);
  font.setCharMinWd(0);
  font.printStr(5, 24, "Use encoder to select menu item.\nPress button to exit.");
  font.setCR(0);
}

void showSelected(char *txt)
{
  lcd.fillScreen(RGBto565(150, 0, 150));
  font.setColor(WHITE);  
  font.printStr(10, 10, "Selected:");
  font.setColor(YELLOW);  
  font.printStr(10, 30, txt);
}

void printMenuItem(int y, char *item)
{
  font.setColor(itemCol);
  font.printStr(3, 2 + y * itemHt, item);
}

void printMenu(int full = 0)
{
  int n = numMenus < numScrLines ? numMenus : numScrLines;
  for (int i = 0; i < n; i++) {
    formatMenu(menuTxt[i + menuStart], buf, 14);
    full ? lcd.fillRect(0, i * itemHt, SCR_WD, itemHt, bgCol) : lcd.fillRect(3, 2 + i * itemHt, 120 - 4, 16, bgCol);
    printMenuItem(i, buf);
  }
}

void setMenu(int m)
{
  menuMode = m;
  storedPos = encoderPos;
  encoderPos = 0;
}

void endMenu(int butt)
{
  if (!butt) return;
  menuMode = -1;
  initMenu();
  encoderPos = storedPos;
}

void formatMenu(char *in, char *out, int num)
{
  int j = strlen(in);
  strncpy(out, in, j);
  for (; j < num; j++) out[j] = ' ';
  out[j] = 0;
}

void drawMenuSlider()
{
  //int ht = 10;
  int ht = (SCR_HT - 4) / numMenus;
  int n = (SCR_HT - 4 - ht) * menuSel / (numMenus - 1);
  lcd.drawRect(SCR_WD - 6, 0, 6, SCR_HT, sliderCol);
  lcd.fillRect(SCR_WD - 6 + 2, 2, 2, SCR_HT - 4, bgCol);
  lcd.fillRect(SCR_WD - 6 + 2, n + 2, 2, ht, sliderCol);
}

void drawFrame(int sel, int stat)
{
  lcd.drawRect(0, (sel - menuStart)*itemHt, 120, itemHt - 1, stat ? frameCol : bgCol);
}

void initMenu()
{
  font.setFont(&rre_fjg_8x16);
  font.setCharMinWd(8);
  font.setSpacing(1);
  font.setColor(WHITE);
  printMenu(1);
  drawMenuSlider();
  drawFrame(menuSel, 1);
}

void setValue()
{
  if (encoderPos < 0) encoderPos = 0;
  if (encoderPos > 40) encoderPos = 40;
  drawGauge1(encoderPos / encoderStep);
}

// -------------
int colR, colG, colB;
int colRold, colGold, colBold;
int setRGBMode = 0;
int colBarWd = 96;
int colBarY0 = 5;
int colBarY = 40;
int colBarHt = 30;
int encoderMin = 0;
int encoderMax = 255;

void setColorInit(uint16_t *c)
{
  colR = (*c & 0xf800) >> 8;
  colG = (*c & 0x7e0) >> 3;
  colB = (*c & 0x1f) << 3;
  colRold = colGold = colBold = 0;
  lcd.fillScreen(BLACK);
  for (int i = 0; i < 32; i++) { // 96 pixels wide, 32 shades
    lcd.fillRect(2 + i * 3, colBarY0 + colBarY * 0, 3, colBarHt, RGBto565(i * 8, 0, 0));
    lcd.fillRect(2 + i * 3, colBarY0 + colBarY * 1, 3, colBarHt, RGBto565(0, i * 8, 0));
    lcd.fillRect(2 + i * 3, colBarY0 + colBarY * 2, 3, colBarHt, RGBto565(0, 0, i * 8));
  }
  lcd.drawRect(1, colBarY0 + colBarY * 0 - 1, colBarWd + 2, colBarHt + 2, RGBto565(128, 0, 0));
  lcd.drawRect(1, colBarY0 + colBarY * 1 - 1, colBarWd + 2, colBarHt + 2, RGBto565(0, 128, 0));
  lcd.drawRect(1, colBarY0 + colBarY * 2 - 1, colBarWd + 2, colBarHt + 2, RGBto565(0, 0, 128));
  lcd.fillRect(128 - 50 - 2, 160 - 25 - 2, 50, 25, *c); // cancel
  encoderMax = 4;
}

void setColorAction(uint16_t *col, int butt)
{
  if (encoderPos < encoderMin * encoderStep) encoderPos = encoderMin * encoderStep;
  if (encoderPos > encoderMax * encoderStep) encoderPos = encoderMax * encoderStep;
  int pos = encoderPos / encoderStep;
  int frw = 2 + 96 + 2;
  if (butt) {
    if (setRGBMode > 0) {
      encoderStep = 2;
      encoderPos = (setRGBMode - 1) * encoderStep;
      setRGBMode = 0;
      encoderMax = 4;
    } else {
      if (pos == 3 || pos == 4) {
        if (pos == 3) *col = RGBto565(colR, colG, colB);
        menuMode = -1;
        initMenu();
        encoderPos = storedPos;
        setRGBMode = 0;
        encoderStep = 2;
        return;
      }
      setRGBMode = pos + 1;
      encoderMax = 255;
      encoderStep = 1;
      if (setRGBMode == 1) {
        encoderPos = colR;
        lcd.drawRect(0, colBarY0 + colBarY * 0 - 2, frw, colBarHt + 4, RGBto565(255, 80, 80));
      } else if (setRGBMode == 2) {
        encoderPos = colG;
        lcd.drawRect(0, colBarY0 + colBarY * 1 - 2, frw, colBarHt + 4, RGBto565(80, 255, 80));
      } else if (setRGBMode == 3) {
        encoderPos = colB;
        lcd.drawRect(0, colBarY0 + colBarY * 2 - 2, frw, colBarHt + 4, RGBto565(80, 80, 255));
      }
      return;
    }
  }
  if (setRGBMode == 1) colR = pos; else if (setRGBMode == 2) colG = pos; else if (setRGBMode == 3) colB = pos;

  font.setColor(WHITE, BLACK);
  int xcol = 128 - 9 * 3 + 1;
  if (setRGBMode == 0 || setRGBMode == 1) {
    dtostrf(colR, 3, 0, buf);
    font.printStr(xcol, colBarY0 + colBarY * 0 + 8, buf);
  }
  if (setRGBMode == 0 || setRGBMode == 2) {
    dtostrf(colG, 3, 0, buf);
    font.printStr(xcol, colBarY0 + colBarY * 1 + 8, buf);
  }
  if (setRGBMode == 0 || setRGBMode == 3) {
    dtostrf(colB, 3, 0, buf);
    font.printStr(xcol, colBarY0 + colBarY * 2 + 8, buf);
  }
  font.setColor(WHITE);

  if (colRold != colR) {
    lcd.drawFastVLine(2 + 3 * colRold / 8, colBarY0 + colBarY * 0, colBarHt, RGBto565(colRold, 0, 0));
    lcd.drawFastVLine(2 + 3 * colR / 8,   colBarY0 + colBarY * 0, colBarHt, YELLOW);
    colRold = colR;
  }
  if (colGold != colG) {
    lcd.drawFastVLine(2 + 3 * colGold / 8, colBarY0 + colBarY * 1, colBarHt, RGBto565(0, colGold, 0));
    lcd.drawFastVLine(2 + 3 * colG / 8,   colBarY0 + colBarY * 1, colBarHt, YELLOW);
    colGold = colG;
  }
  if (colBold != colB) {
    lcd.drawFastVLine(2 + 3 * colBold / 8, colBarY0 + colBarY * 2, colBarHt, RGBto565(0, 0, colBold));
    lcd.drawFastVLine(2 + 3 * colB / 8,   colBarY0 + colBarY * 2, colBarHt, YELLOW);
    colBold = colB;
  }

  lcd.fillRect(       2, 160 - 25 - 2, 50, 25, RGBto565(colR, colG, colB)); // ok

  if (setRGBMode == 0) {
    lcd.drawRect(0, colBarY0 + colBarY * 0 - 2, frw, colBarHt + 4, BLACK);
    lcd.drawRect(0, colBarY0 + colBarY * 1 - 2, frw, colBarHt + 4, BLACK);
    lcd.drawRect(0, colBarY0 + colBarY * 2 - 2, frw, colBarHt + 4, BLACK);
    lcd.drawRect(       0, 160 - 25 - 4, 50 + 4, 25 + 4, BLACK);
    lcd.drawRect(128 - 50 - 4, 160 - 25 - 4, 50 + 4, 25 + 4, BLACK);
    switch (pos) {
      case 0: lcd.drawRect(0, colBarY0 + colBarY * 0 - 2, frw, colBarHt + 4, WHITE); break;
      case 1: lcd.drawRect(0, colBarY0 + colBarY * 1 - 2, frw, colBarHt + 4, WHITE); break;
      case 2: lcd.drawRect(0, colBarY0 + colBarY * 2 - 2, frw, colBarHt + 4, WHITE); break;
      case 3: lcd.drawRect(       0, 160 - 25 - 4, 50 + 4, 25 + 4, WHITE); break;
      case 4: lcd.drawRect(128 - 50 - 4, 160 - 25 - 4, 50 + 4, 25 + 4, WHITE); break;
    }
  }
}

// -------------

uint16_t reqBgCol = RGBto565(0, 80, 0);
int reqY = 110;

void reqInit()
{
  lcd.fillScreen(reqBgCol);
  font.setColor(WHITE);
  font.printStr(ALIGN_CENTER, 50, "Are you sure?");
  font.setColor(YELLOW);
  font.printStr(8, reqY, " OK ");
  font.printStr(ALIGN_RIGHT, reqY, " CANCEL ");
}

void reqAction()
{
  if (encoderPos < 0) encoderPos = 0;
  if (encoderPos > 1 * encoderStep) encoderPos = 1 * encoderStep;
  int pos = encoderPos / encoderStep;
  lcd.drawRect(8, reqY - 3, 4 * 9 - 2, 20, reqBgCol);
  lcd.drawRect(128 - 8 * 9, reqY - 3, 8 * 9 - 4, 20, reqBgCol);
  if (pos == 0) lcd.drawRect(8, reqY - 3, 4 * 9 - 2, 20, WHITE); else if (pos == 1) lcd.drawRect(128 - 8 * 9, reqY - 3, 8 * 9 - 4, 20, WHITE);
}

// -------------

void showBattery()
{
  char flt[10];
  long v = readVcc();
  lcd.fillScreen(BLACK);
  dtostrf(v / 1000.0, 1, 3, flt);
  snprintf(buf, 90, "Vcc=%sV", flt);
  font.setColor(WHITE);
  font.printStr(16, 30, buf);
  lcd.drawRect(10, 60, 128 - 20 - 8, 50, WHITE);
  lcd.fillRect(10 + 128 - 20 - 8, 60 + 15, 8, 20, WHITE);
  int bwd = 128 - 20 - 8 - 8l;
  uint16_t c = YELLOW;
  if (v > 3600) c = GREEN;
  if (v < 3100) c = RED;
  long fill = constrain(map(v, 2900, 4200, 0, bwd - 10), 0, bwd - 10);
  lcd.fillRect(14, 64, fill + 10, 50 - 8, c);
}

void showIntTemp()
{
  char flt[10];
  lcd.fillScreen(BLACK);
  dtostrf(readIntTemp(), 2, 1, flt);
  snprintf(buf, 90, "Temp=%s'C", flt);
  font.setColor(WHITE);
  font.printStr(ALIGN_CENTER, 70, buf);
}

void dumpEEPROM()
{
  //font.setFont(&rre_4x7); font.setCharMinWd(4);
  font.setFont(&rre_5x8); font.setCharMinWd(5);
  if (encoderPos >= (128 - 16) * 2) encoderPos = (128 - 16) * 2;
  int st = encoderPos / encoderStep;
  for (int j = 0; j < 16; j++) {
    int ii = st * 8 + j * 8;
    ii &= 0x3ff; // max 1kB
    snprintf(buf, 8, "%03X", ii);
    font.setColor(YELLOW, BLACK);
    font.printStr(0, j * 10, buf);
    for (int i = 0; i < 8; i++) {
      int v = EEPROM.read(ii + i);
      snprintf(buf, 8, "%02X", v);
      font.setColor(WHITE, BLACK);
      font.printStr(5 * 4 + 2 + i * 13, j * 10, buf);
    }
  }
}

// -------------

void menuItemInit()
{
  setMenu(menuSel);
  switch (menuMode) {
    case 0: lcd.fillScreen(BLACK); encoderPos = 5 * encoderStep; break; // for setValue()
    case 1: showHelp(); break;
    case 2: showIntTemp(); break;
    case 3: showBattery(); break;
    case 4: lcd.fillScreen(BLACK); break; // for dumpEEPROM()
    case 6: setColorInit(&bgCol); break;
    case 7: setColorInit(&itemCol); break;
    case 8: setColorInit(&frameCol); break;
    case 9: setColorInit(&sliderCol); break;
    case 11: reqInit(); break;
    default: showSelected(menuTxt[menuSel]);
  }
}

void menuItemAction(int butt)
{
  switch (menuMode) {
    case 0: setValue(); endMenu(butt); break;
    case 4: dumpEEPROM(); endMenu(butt); break;
    case 6: setColorAction(&bgCol, butt); break;
    case 7: setColorAction(&itemCol, butt); break;
    case 8: setColorAction(&frameCol, butt); break;
    case 9: setColorAction(&sliderCol, butt); break;
    case 11: reqAction(); endMenu(butt); break;
    default: endMenu(butt);
  }
}

void handleMenu()
{
  int butt = readButton();
  if (encoderPos < 0) encoderPos = 0;
  if (encoderPosOld == encoderPos && !butt) return;
  encoderPosOld = encoderPos;
  if (menuMode == -1) {
    menuSel = encoderPos / encoderStep;
    if (menuSel >= numMenus) {
      menuSel = numMenus - 1;
      encoderPos = menuSel * encoderStep;
    }
    if (menuSel >= menuStart + numScrLines) {
      menuStart = menuSel - numScrLines + 1;
      printMenu();
    }
    if (menuSel < menuStart) {
      menuStart = menuSel;
      printMenu();
    }
    if (menuSelOld != menuSel) {
      drawFrame(menuSelOld, 0);
      drawFrame(menuSel, 1);
      drawMenuSlider();
      menuSelOld = menuSel;
    }
    if (butt) menuItemInit();
  } else menuItemAction(butt);
}

void setup()
{
  Serial.begin(9600);
  lcd.init();
  //lcd.fillScreen(bgCol);
  font.init(customRect, SCR_WD, SCR_HT); // custom fillRect function and screen width and height values
  initEncoder();
  initMenu();
}

void loop()
{
  /*
    if(encoderPosOld!=encoderPos) {
    encoderPosOld=encoderPos;
    snprintf(buf,20,"Encoder %02d",encoderPos);
    font.setColor(WHITE);
    lcd.fillRect(3,140,120,16,BLACK);
    font.printStr(3,140,buf);
    }*/

  handleMenu();
}

I supposed I have to changed this line but not sure.

void readEncoderInt()
{
  //(digitalRead(encoderPinA) == digitalRead(encoderPinB)) ? encoderPos++ : encoderPos--;
  uint8_t pd = PIND & B10100; // inputs #2 and #4 direct reading
  ((pd == B10100) || (pd == B00000)) ? encoderPos++ : encoderPos--;
}

Hello
All in all your sketch needs a button handler who takes care about debouncing and the up/down counting functionality.

You are right. But as newbie I am little bit confused where I add the button handler code. And which code need to eliminate now?

Hello,
start and try to brew a simple button handler by yourself.
Don´t use the delay() function.

@paulpaulson I have already practice it. Here is the code. But I cant know how add them in my main code?
Thanks for your quick reply.


byte menuPos;
const char* const menu[12] PROGMEM  = {"Binary to Decimal", "Binary to Octal", "Binary to Hexa Deci", "Decimal to Binary", "Decimal to Ocatl", "Decimal to Hexa Deci", "Octal to Binary",
                                       "Octal to decimal", "Octal to Hexa Deci", "Hexa-Decimal to Binary", "Hexa-Decimal to Ocatl", "Hexa-Deci to Decimal"
                                      };
#define btnEnt 4
#define btnUp 3
#define btnDwn 2

void setup() {
  Serial.begin(9600);
  pinMode(btnUp, INPUT_PULLUP);
  pinMode(btnDwn, INPUT_PULLUP);
  pinMode(btnEnt, INPUT_PULLUP);
  lcd.init();
  lcd.fillScreen(BLACK);
  delay(2000);
}

void loop() {
  if (isButtonDown(btnDwn) == true) {
      menuPos--;
  }
  
  if (isButtonDown(btnUp) == true) {
      menuPos++;
  }
  
  if (isButtonDown(btnEnt) == true) {
    if (menuPos == 0) {
      test1();
    }
    else if (menuPos == 1) {
      //test2();
    }
    else if (menuPos == 2) {
      //test2();
    }
    else if (menuPos == 3) {
      //test3();
    }
    else if (menuPos == 4) {
      //test4();
    }
    else if (menuPos == 5) {
      //test5();
    }
    else if (menuPos == 6) {
      //test6();
    }
    else if (menuPos == 7) {
      //test7();
    } else if (menuPos == 8) {
      //test1();
    }
    else if (menuPos == 9) {
      //test8();
    }
    else if (menuPos == 10) {
      //test9();
    }

    else if (menuPos == 11) {
      //test10();
    } else if (menuPos == 12) {
      //test11();
    }
    delay(100);
  }
}

bool isButtonDown(byte pin) {
  if (digitalRead(pin) == LOW) {
    delay(30);
    if (digitalRead(pin) == LOW)
      return true;
    return false;
  }
  return false;
}

void test1(){

  Serial.println(F("This is test1() function."));
}

Finally I solved my problem myself.

  if (isButtonDown(btnDwn) == true) {
    if (menuPos < MENU_LENGTH - 1) {
      menuPos++;
      if (menuPos - menuStartAt > 8 )
        menuStartAt++;
      showMenu();
    }
    delay(50);
  }
  
  if (isButtonDown(btnUp) == true) {
    if (menuPos > 0) {
      menuPos--;
      if (menuPos - menuStartAt < 0 && menuStartAt != 0)
        menuStartAt--;
      showMenu();
    }
    delay(50);
  }
  
  if (isButtonDown(btnEnt) == true) {
    if (menuPos == 0) {
      test1();
    }
    else if (menuPos == 1) {
      test2();
    }
    else if (menuPos == 2) {
      //test2();
    }
    else if (menuPos == 3) {
      //test3();
    }
    else if (menuPos == 4) {
      //test4();
    }
    else if (menuPos == 5) {
      //test5();
    }
    else if (menuPos == 6) {
      //test6();
    }
    else if (menuPos == 7) {
      //test7();
    } else if (menuPos == 8) {
      //test1();
    }
    else if (menuPos == 9) {
      //test8();
    }
    else if (menuPos == 10) {
      //test9();
    }

    else if (menuPos == 11) {
      //test10();
    } else if (menuPos == 12) {
      //test11();
    }
    delay(100);
  }

Hi
I had done the same thing, I share it to find ideas? 2 keys (plus 1 reset key) are re-looped on 2 interrupt inputs for simulate a signal in encoder quadrature. The values are displayed on the serial terminal. Then we can connect the real encoder to the 2 interrupt inputs (attention, the encoder provided is an optical encoder, with a very clean signal; if a mechanical encoder is used, its signals must be properly filtered, to be clean). Keyboard with anti-bounce and auto-repeat; encoder detection with removal of invalid configurations (quadrature). To facilitate the needs of the test, an instruction delay() is used, I have another code that replaces this dealy() with an interrupt for the keyboard.

// Programme d'anti-rebond (debounce) pour clavier et lecture d'un encodeur (quadrature) pour carte Arduino.
// Sans encodeur : 2 touches pilotent un signal en quadrature rebouclé sur 2 entrées pour permettre le test.
// Avec encodeur : raccordé sur les mêmes 2 entrées, les touches affichent sa position (débrancher 5 et 4!). 
//
// Clavier : 1..8 boutons, gestion sous interruption de période 5..25 ms ou sinon appel régulier (ici 10ms).
//           Anti-rebond, détection des appuis et des relachements, fonction flip-flop (toggle), auto-repeat
//           Ă  2 vitesses pour certaines touches choisies (le luxe). On peut aussi ajouter un Bip sur appui.
//           Bien sûr les touches peuvent être activées ensemble, pour faire une touche Shift, ou autres ...
// Encodeur : 2 phases raccordées sur 2 entrées sous interruption lors du changement d'état (broche 2 et 3).
//            Les signaux ne doivent pas avoir de rebonds, si nécessaire les filtrer avec un circuit adapté.
//      
// testé sur Pro-Mini 5V 16 Mhz                                                   
// Placer 3 résistances de 1K sur les entrées A0, A1, A2, suivies de 3 bouton-poussoirs raccordés au Gnd 0V; 
// Placer 2 résistances de 1K sur les sorties 4 et 5, qui sont rebouclées sur les broches 3 et 2 en entrées.

//**************************************************** // POUR LE CLAVIER : A0, A1, A2 en entrées
  #define KeyRight          B00000001                  // l'une des touches : PC0
  #define KeyLeft           B00000010                  // l'une des touches : PC1
  #define KeyZero           B00000100                  // l'une des touches : PC2
  #define Keys_All          B00000111                  // toutes les touches sur PortC en entrée
  #define KeysAutoRepeat    B00000011                  // DĂ©finir ici les touches en auto-repeat 
  #define TempoLong         60                         // tempo pendant 1er appui, multiple 10ms
  #define TempoShort        6                          // tempo de répétition après le 1er appui
  byte    PPImuSta;                                    // reflète l'état instantané des touches
  byte    PPImuMem;                                    //               (stockage intermédiaire)
  byte    PPImuFro;                                    // reflète le front ascendant des touches
  byte    PPImuRel;                                    // reflète le front descendant des touches
  byte    TempoRepeat =    TempoLong;                  //               (tempo pour auto-repeat)

 //*************************************************** // POUR L'ENCODEUR : pins 2,3 en entrées
  #define PhaseAIn          B00000100                  // l'un des signaux  pin  2 sous interr.
  #define PhaseBIn          B00001000                  // l'autre signal    pin  3 sous interr. 
  #define PhaseABIn         B00001100                  // les deux signaux
  volatile int  Position;                              // Valeur de position de l'encodeur
  volatile byte PreviPortD= PhaseAIn;                  // état antérieur; initialisé par défaut
  
//**************************************************** // POUR LA DEMO :    pins 4,5 en sorties
  #define PhaseAOut         B00010000                  // phase A en sortie
  #define PhaseBOut         B00100000                  // phase B en sortie 
  #define PhaseABOut        B00110000                  // les deux phases
  byte    Quadra;                                      // contient la suite des phases générées
  int     PositionKey;                                 // compteur d'appui sur Key droite/gauche

void setup(void) {                                     // INITIALISATION :
  DDRD  |= PhaseABOut;                                 // broches 4 et 5 en sorties pour Quadra
  PORTC  = Keys_All;                                   // Pullups sur les 3 entrées pour clavier
  attachInterrupt(digitalPinToInterrupt(2), ExtInt, CHANGE); // POUR L'ENCODEUR Pin 2 interrupt.
  attachInterrupt(digitalPinToInterrupt(3), ExtInt, CHANGE); // POUR L'ENCODEUR Pin 3 interrupt.
  Serial.begin(9600);  }                               // 
                                                       
void ExtInt() {                                        // INTERRUPTION ENCODEUR : broches 2 et 3
  byte PortD = PIND & PhaseABIn;                       // acquisition des signaux
  if ((PortD ^ PreviPortD) == PhaseAIn) Position++;    // détection du sens ->
  if ((PortD ^ PreviPortD) == PhaseBIn) Position--;    // détection du sens <-  
  if ((PortD != 0) && (PortD != PhaseABIn)) PortD ^= PhaseABIn;             // swap informat. A/B
  PreviPortD = PortD;  }                               //                  mieux vaut faire court
  
 
  
void loop(void) { //************************ et ouala *********************************************
  delay(10);                                           // brutal ! mais c'est seulement une démo...
  
  byte iii = ~PINC & Keys_All;                         // CLAVIER: lecture des touches et inversion
  byte jjj = PPImuSta;                                 //
  PPImuSta = iii & PPImuMem;                           // subsiste pendant tout le temps de l'appui
  PPImuMem = iii;                                      //        (PPImumMem pour la prochaine fois)
  PPImuFro = (jjj ^ PPImuSta) & PPImuSta;              // fugitif, actif jusqu'au prochain passage
  PPImuRel = (iii ^ jjj) & jjj;                        // fugitif, actif jusqu'au prochain passage
                                                       // (aussi : PPImuTog = PPImuTog ^ PPImuFro;)
      if (PPImuSta & KeysAutoRepeat) {                 // KeysAutoRepeat reflète les Keys à répéter
        TempoRepeat--;                                 // 
        if (TempoRepeat == 0) {                        // si l'auto-répétition n'est pas nécessaire
          TempoRepeat = TempoShort;                    // supprimer cette partie du code en retrait
          PPImuFro = PPImuSta;                         //
      } } else TempoRepeat = TempoLong;                //
                                                       // DECODAGE DES TOUCHES :
  if (PPImuFro & KeyRight) {                           // TOUCHE rotation Ă  droite avec auto-repeat
    if ((Quadra!=0)&&(Quadra!=PhaseABOut)) Quadra^=PhaseAOut;  else Quadra^=PhaseBOut; 
    PORTD = Quadra;                                    //
    PositionKey++;                                     //
    Serial.print("+"); }                               //
  
  if (PPImuFro & KeyLeft) {                            // TOUCHE rotation Ă  gauche avec auto-repeat
    if ((Quadra!=0)&&(Quadra!=PhaseABOut)) Quadra^=PhaseBOut;  else Quadra^=PhaseAOut;
    PORTD = Quadra;                                    //
    PositionKey--;                                     //
    Serial.print("-"); }                               //

  if (PPImuFro & KeyZero) {                            // TOUCHE de remise à zéro, sans auto-repeat
    Position = 0;                                      //
    PositionKey = 0;                                   //
    Serial.println("Position = 0");}                   //

  if (PPImuRel & (KeyRight | KeyLeft)) {               // TOUCHE rotation droite ou gauche relachée
    Serial.print("  Encodeur= ");                      // Quand un encodeur (physique) est branché,
    Serial.print(Position);                            // il faut appuyer (et relacher) les touches
    Serial.print(" Clavier= ");                        // <- -> pour voir la position de l'encodeur
    Serial.println(PositionKey); }                     //
}                                                      // 

1 Like

@PatMax
Please read the thread again what its about.
Here I want to replace the encoder with push button. So I asked for what code modification needed for push button.
I solved it. Thank you for your replay.

Hi muhit114474,
I did read the request, and saw that the problem was solved, but since I had exactly the right program (and the need to simulate an encoder with buttons is not that common), I shared my code for others who might be interested in having several examples, coming on this topic

1 Like