keypad: enter, backspace, and reset buttons

using a 4x4 keypad arranged like this,

1 2 3 A

4 5 6 B

7 8 9 C

  • 0 # D

i need to rotate a stepper motor as many times as inserted and as fast as it needs to go (by assigning the A, B, and C with a set rpm). the first thing you need to insert is the number of rotations. i want to assign the * button as an “enter” button, so that the rotation menu moves on to the speed menu. just in case the user inputs the wrong number, i need a “backspace” button, which will be the # button. when an emergency stop is needed, i need a “reset” button to make everything go back to the rotation menu. however, i am having difficulties programming this. how can i get these buttons to do what i said?

tl;dr: i need to assign the * button as an “enter” button, # button as “backspace” button, and “D” button as a “reset” button. how do i program this?

am having difficulties programming this.

Post what you have written so far use the icon in the top left corner of the reply box that looks like </> and paste your code between the square brackets command that pops up.

What happens when you press 2 buttons at once?

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

const int FullCycle = 200;
const int A = 60;
const int B = 120;
const int C = 180;
const int D = 240;
Stepper motor (fullrevolution, 10, 11, 12, 13);

const byte ROWS = 4; 
const byte COLS = 4; 

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 
LiquidCrystal_I2C lcd(0x21, 16, 2);

void setup(){
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  }
  
void loop(){
  lcd.setcursor(0,0);
  lcd.print("Rotations:");
  
  char entry1 = customKeypad.getKey();
  
  if (entry1){
    Serial.println(entry1);
  }
    
  if (entry1=="*"){
    lcd.setcursor(0,0);
    lcd.print("Length:");
  }

  char entry2 = customKeypad.getKey();

  if(entry2=="A"){
    lcd.print("42-50cm");
  }

  if(entry2=="B"){
    lcd.print("32-40cm");
  }

  if(entry2=="C"){
    lcd.print("22-30cm");
  }

  if(entry2=="D"){
    lcd.print("8-20cm")
  }

  if(entry2=="*"){
    lcd.clear
    motor.step(FullCycle*entry1);
    motor.setSpeed(entry2);
  }

  
}

i’m not sure on how to code the # button… i’m thinking of changing it to a reset button instead of a backspace, and the D button as a higher speed.

GoForSmoke:
What happens when you press 2 buttons at once?

i never thought of that tbh.

edit: there are mistakes in the code. i fixed it

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

const int FullCycle = 200;
const int A = 60;
const int B = 120;
const int C = 180;
const int D = 240;
Stepper motor (fullrevolution, 10, 11, 12, 13);

const byte ROWS = 4; 
const byte COLS = 4; 

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 
LiquidCrystal_I2C lcd(0x21, 16, 2);

void setup(){
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  }
  
void loop(){
  lcd.setcursor(0,0);
  lcd.print("Rotations:");
  
  char entry1 = customKeypad.getKey();
  
  if (entry1){
    Serial.println(entry1);
  }
    
  if (entry1=="*"){
    lcd.setcursor(0,0);
    lcd.print("Length:");
  }

  char entry2 = customKeypad.getKey();

  if(entry2=="A"){
    lcd.print("42-50cm");
  }

  if(entry2=="B"){
    lcd.print("32-40cm");
  }

  if(entry2=="C"){
    lcd.print("22-30cm");
  }

  if(entry2=="D"){
    lcd.print("8-20cm")
  }

  if(entry2=="*"){
    lcd.clear
    motor.step(FullCycle*entry1);
    motor.setSpeed(entry2);
  }

  
}

Emergency buttons should directly cut power to the motor and not rely on additional hardware,

Havin said that, your program can be in one of two modes; data selection or running. You can add the below just after the #include statements in your code.

#define SELECT 0
#define RUNNING 1

Add a variable after that that remembers the mode

#define SELECT 0
#define RUNNING 1

byte mode = SELECT;

Next in loop(), you can check that variable and take action based on the value.

void loop()
{
  switch(mode)
  {
    case SELECT:
      distanceSelection();
      break:
    case RUNNING:
      run()
      break:
  }
}

Next you can implement the two functions; first the distance selection (you already have that part in your current code)

void distanceSelection()
{
  char entry1 = customKeypad.getKey();

  // implement the keypad code for distance selection here
  ...
  ...

  // when the user presses the <enter> key
  if(entry1 == '*')
  {
    // set the mode
    mode = RUNNING;
  }
}

And the code for the running; because you’re independent of the code for the distance selection, the below uses ‘#’ (instead of ‘D’) and ‘’. '’ will take the user back to the distance selection.

void run()
{
  char entry1 = customKeypad.getKey();

  // do whatever is required when running

  // when the user presses the <reset> key
  if(entry1 == '#')
  {
    // do emergency stuff
    ...
    ...
  }

  // when user presses the <return> key
  if(entry1 == '*')
  {
    // do whatever is needed to finish what was going on
    ...
    ...

    // switch back to selection mode
    mode = SELECT;
  }
}

I hope that this gives you a bit of an idea. The key might not be required.

hungrycoco:
i'm not sure on how to code the # button... i'm thinking of changing it to a reset button instead of a backspace, and the D button as a higher speed.

Quite often the hardest part is not writing the code, it is writing down exactly what you want the program to do.

Generally what are you trying to do?
How could you assign buttons on a keypad to do that?
Then go thru and write down each separate step to do these things.

Write yourself out a fairly detailed 'specification' of what you want the code to do,
For Example:

I need to rotate a stepper motor as many times as inserted and as fast as it needs to go
I only need a few different speeds, like .... whatever you want....
and I want to be able to set the number of rotations .... from 1 to some number...
then press a button and let it run.
On the keypad, I'll use A,B,C,D to pick one of the speeds
The number of rotations will be entered using the numbers, might need more than one button press.
So I could press number buttons to get the digits like '1', '2', '3' then some ENTER button
So in use you would:
Display shows: "Hello or Press A,B,C,D for Speed"
Press A,B,C,D to set the speed
Display shows: "Speed set to ?? " or "enter rotations"
Press a number (e.g. '1')
Display shows "Rotations: 1"
Press another number (e.g.'2')
Display shows "Rotations: 12"
Then press ENTER
Display now shows: "Speed ?? Rotations: 12" or "press # to GO"
Then press # to make it go (or could press another button to start again)

Then you can try to figure out how to code all that lot. It is not pretty obvious that there are several separate states you have to go thru, so your code will have to know which state you are on.

For example, if the program is in some "ENTERING_ROTATIONS" state, the key that is pressed should be a digit to add to NoOfRotations or the ENTER button to save that and step the the next READY_TO_GO state.

Like in sterretje's post you want to define the 'states' or 'modes' like:

#define STARTUP  1
#define PICK_SPEED 2
#define ENTER_ROTATIONS 3
#define READY_TO_GO 4
#define RUNNING 5

byte mode= STARTUP;

  switch(mode)
  {
    case STARTUP:
      // Display  "Hello or Press A,B,C,D for Speed"
      mode= PICK_SPEED;
      break:
    case PICK_SPEED:
      //  test for key == A,B,C,D here then
      //   Display : "Speed set to ????"  or "enter rotations"
      //   set mode= ENTER_ROTATIONS
      break:
    case ENTER_ROTATIONS:
      // Press a number (e.g. '1')
      // Display  "Rotations:  1"
      // Press another number (e.g.'2')
      // Display  "Rotations:  12"
      // Then press ENTER
      //   set mode= READY_TO_GO
      break:
    case READY_TO_GO:
      // Display: "Speed ?? Rotations: 12"  or "press # to GO"
      // Then press # to make it go  (or could press another button to start again)
      //   set mode= RUNNING
      break:
    case RUNNING:
      run()
      break:
  }

Notice I've put lines from the 'specification' as comments in that 'mode stepping code'
Write the stepping thru the modes bit first with printing to your display (at this stage you could make any button step to the next mode)

When you can press buttons to simply step thru display messages, you can fill in the code to actually pick a speed and then to add up digits for the number of rotations and then the rest.

Yours,
TonyWilk

Because opposite corners at the same time....