How to override "waitforkey" function

Hello everyone,

I am new to this forum and have a few question hoping that you guys can help. My project consists of Arduino, keypad, LCD screen, PWM output, and a rotary encoder. I got everything working, and I have merged all the code together except the rotary encoder that does not work properly which I suspect that "waitforkey" function hold up the whole process, and it results in the encoder only run once after I input the value. I want it to run in parallel to the main code. Therefore, I am trying to find a way to override "waitforkey" function. Any help would be appreciated. Thank you in advance.

Main code:

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


LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
char key;
char PWM_value_array[4] = {' ',' ',' ',' '};
int val;

const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns
// Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = { 13, 12, 11, 10 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = { 9, 8, 7 }; 

// Create the Keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


  void setup() {

    // set up

    pinMode(5,OUTPUT);

    Serial.begin(9600);
    
    lcd.begin(16,2);   // iInit the LCD for 16 chars 2 lines
   
    lcd.print("KEYPAD LCD PWM"); 

  }

  void loop() 

  {
    BEGINNING: //Label for beginning
    key = kpd.waitForKey();
    if (key == '#' || key == '*'){
      //If key entered is # or *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
      
    }
     lcd.setCursor(0, 1);
    lcd.print("KEY= "+String(key)+"_");
    
    PWM_value_array[0] = key;

    delay(250);
   //Waiting for SECOND number
    key = kpd.waitForKey();
    if ( key != '*' && key != '#'){
      PWM_value_array[1] = key;
      lcd.setCursor(0, 1);
      lcd.print("KEY= "+String(PWM_value_array[0])+String(PWM_value_array[1])+"_");
    }
    Serial.println(key);
    if (key == '*'){
      //If key entered *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if(key == '#'){
      //We're done
      val = String(PWM_value_array[0]).toInt();
      goto ENDING;
      }
    delay(250);
    
      //Waiting on 3rd number
        key = kpd.waitForKey();
    if ( key != '*' && key != '#'){
      PWM_value_array[2] = key;
      lcd.setCursor(0, 1);
      lcd.print("KEY= "+String(PWM_value_array[0])+String(PWM_value_array[1])+String(PWM_value_array[2])+"_");
    }
    if (key == '*'){
      //If key entered *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if(key == '#'){
      //We're done
      val = String(String(PWM_value_array[0])+String(PWM_value_array[1])).toInt();
      goto ENDING;
      }
    delay(250);

     //Waiting on 4th character
        key = kpd.waitForKey();
    if ( key != '*' && key != '#'){
      lcd.setCursor(0, 1);
      lcd.print("NUMBER TOO LARGE");
      delay(1000);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if (key == '*'){
      //If key entered *, go back to beginning
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if(key == '#'){
      //We're done
      val = String(String(PWM_value_array[0])+String(PWM_value_array[1])+String(PWM_value_array[2])).toInt();
      }

  ENDING:
  if(val > 255){
    val = 255;
  }
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("KEYPAD LCD PWM");
  lcd.setCursor(0, 1);
  lcd.print("KEY= ");
  
  Serial.println(val);

  analogWrite(5,val);
  
  }

Encoder Code:

#define encoder0PinA  2
#define encoder0PinB  4

volatile long encoder0Pos=0;
long newposition;
long oldposition = 0;
unsigned long newtime;
unsigned long oldtime = 0;
long vel;

void setup()
{
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor
  attachInterrupt(0, doEncoder, RISING);  // encoDER ON PIN 2
  Serial.begin (9600);
  Serial.println("start");                // a personal quirk
}

void loop()
{
newposition = encoder0Pos;
newtime = millis();
vel = (newposition-oldposition)/600;
Serial.print ("speed = ");
Serial.println (vel);
oldposition = newposition;
oldtime = newtime;
delay(1000);
}

void doEncoder()
{
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    encoder0Pos++;
  } else {
    encoder0Pos--;
  }
}

PS. In my encoder code, I am not using time in calculation for the angular velocity but instead I used delay(1000). I believe there is a better way to do it. If you have any suggestion, please let me know. Thank you again.

It is not completely clear to me what your problem is. The second sketch does not use waitforkey().

Anyway, this is interesting:

    BEGINNING: //Label for beginning
    key = kpd.waitForKey();
    if (key == '#' || key == '*'){
      //If key entered is # or *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
     
    }

I don't often see examples of goto in C/C++ code. Of course it can be completely valid. In this case, it will be an endless loop until a '#' or '*' is entered. Is that what you want ?

it will be an endless loop until a '#' or '*' is entered

The construct loops only in the cases that # or * is entered, perhaps for number-only entry.

@OP: there is no need to use "waitForKey()". Use getKey() instead. It returns zero if no key is entered, so you can take any action you like. See Arduino Playground - HomePage

Note: it is a bad idea to use Strings on Arduino. They cause memory problems and program crashes.

lcd.print("KEY= "+String(key)+"_");

@6v6gt my apology for not stating it clear. What I meant is I use "waitforkey" in my main code, and when I try to merge with the encoder code, it hold up the process in the encoder because of the command "waitforkey" which results in the encoder does not work unless a key is pressed. My goal is I want it to run along with the main code without waiting for the key to be pressed.

@jremington I tried using "getKey()" and unfortunately it does not work. The LCD screen repeatedly displays "NUMBER IS TOO LARGE" and the encoder does not run. I might have done something wrong here. here is my maincode after merging with the encoder.

Please let me know if you have any suggestion. Thank you for your time.

#include <Keypad.h>
#include <Wire.h>  
#include <LiquidCrystal_I2C.h>
#define encoder0PinA  2
#define encoder0PinB  4

volatile long encoder0Pos=0;
long newposition;
long oldposition = 0;
unsigned long newtime;
unsigned long oldtime = 0;
long vel;


LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
char key;
char PWM_value_array[4] = {' ',' ',' ',' '};
int val;

const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns
// Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = { 13, 12, 11, 10 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = { 9, 8, 7 }; 

// Create the Keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


  void setup() {

    // set up

    pinMode(5,OUTPUT);

    Serial.begin(9600);
    
    lcd.begin(16,2);   // iInit the LCD for 16 chars 2 lines
   
    lcd.print("KEYPAD LCD PWM"); 
    
     pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor
  attachInterrupt(0, doEncoder, RISING);  // encoDER ON PIN 2
  Serial.begin (9600);
  Serial.println("start");                // a personal quirk

  }

  void loop() 

  {
    newposition = encoder0Pos;
newtime = millis();
vel = (newposition-oldposition)/600;
Serial.print ("speed = ");
Serial.println (vel);
oldposition = newposition;
oldtime = newtime;
delay(1000);

    BEGINNING: //Label for beginning
    key = kpd.getKey();
    if (key == '#' || key == '*'){
      //If key entered is # or *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
      
    }
     lcd.setCursor(0, 1);
    lcd.print("KEY= "+String(key)+"_");
    
    PWM_value_array[0] = key;

    delay(250);
   //Waiting for SECOND number
    key = kpd.getKey();
    if ( key != '*' && key != '#'){
      PWM_value_array[1] = key;
      lcd.setCursor(0, 1);
      lcd.print("KEY= "+String(PWM_value_array[0])+String(PWM_value_array[1])+"_");
    }
    Serial.println(key);
    if (key == '*'){
      //If key entered *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if(key == '#'){
      //We're done
      val = String(PWM_value_array[0]).toInt();
      goto ENDING;
      }
    delay(250);
    
      //Waiting on 3rd number
        key = kpd.getKey();
    if ( key != '*' && key != '#'){
      PWM_value_array[2] = key;
      lcd.setCursor(0, 1);
      lcd.print("KEY= "+String(PWM_value_array[0])+String(PWM_value_array[1])+String(PWM_value_array[2])+"_");
    }
    if (key == '*'){
      //If key entered *, go back to beginning
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if(key == '#'){
      //We're done
      val = String(String(PWM_value_array[0])+String(PWM_value_array[1])).toInt();
      goto ENDING;
      }
    delay(250);

     //Waiting on 4th character
        key = kpd.getKey();
    if ( key != '*' && key != '#'){
      lcd.setCursor(0, 1);
      lcd.print("NUMBER TOO LARGE");
      delay(1000);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("KEYPAD LCD PWM");
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if (key == '*'){
      //If key entered *, go back to beginning
      lcd.setCursor(0, 1);
      lcd.print("KEY= ");
      goto BEGINNING;
    }
    if(key == '#'){
      //We're done
      val = String(String(PWM_value_array[0])+String(PWM_value_array[1])+String(PWM_value_array[2])).toInt();
      }

  ENDING:
  if(val > 255){
    val = 255;
  }
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("KEYPAD LCD PWM");
  lcd.setCursor(0, 1);
  lcd.print("KEY= ");
  
  Serial.println(val);

  analogWrite(5,val);
  
  }

    void doEncoder()
{
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    encoder0Pos++;
  } else {
    encoder0Pos--;
  }
}

unfortunately it does not work.

Of course it works. You are not using it correctly.

Check for a return of zero, which means no key is entered. Decide what should be done when no key is entered; what to do when a valid key is entered and write your program accordingly (as in the examples).