Multiple inputs keypad 3*4

Hi, for a schoolproject we need to make an elevator. We have a small program, but we have a question to put multiple numbers in our keypad before the steppers may rotate.

If you press ‘1’ on the keypad, the steppers rotate 1 rotation each (clockwise and counterclockwise). A text is then shown for 2 actions, the first one is that if you press ‘*’ and ‘1’ the steppers do the same as above.
If you press ‘#’ and ‘1’ the steppers turn different.

Above is a little context because the program is in Dutch, but my problem is that if I want to put in the 2 inputs, the program doesn’t want to run. In my program the keypad doesn’t remember the 2 inputs, but only the first one.

How do I program this so the program only goes on if I push ‘*’ and ‘1’?

sketch_oct22b.ino (4.74 KB)

I assume you mean 2 keys pressed together, not one after the other? I think to do that you need to look at the "multi key" example that's with the library.

lindsayBoxer, I've seen the example for multiKey, but do you have to hold the 2 keys? or can you release one of the 2 afterwards?

I've never used it, I just know it's there, sorry.

I would [u]speculate[/u] that if you wanted to say turn on an led iff both buttons were pressed, and found they were both pressed the led could be turned on. But whether or not the led would go off again if one was released would depend on the code in the "if" or a "switch..case" explicitly performing the off action.

I just used multiKey, but the only thing that is happening, is that the LCD shows when a key is pushed, released of idled, but nothing happens to the steppers…

This is what I had in mind to program, the project is about a automatic garage with 8 places. If you push a number from 1 to 8, a system should take a platform where you can park your car.

For example… If I push ‘1’ on the keypad, an arm takes out a platform from parkingspot number 1. Because I don’t use sensors it’s possible that the parkingspot is already taken, so if there is already a car on the platform you need to push ‘1’ but also ‘*’ so the arm places back the platform in the right spot.

If the platform is empty, you can ride your car on it, once you are out your car you need to push ‘1’ and ‘#’ to put the platform back in parkingspot 1.

The program isn’t for real life cars, but with 3D-printed cars.

#include <Stepper.h>
#define STEPS 2038 // aantal stappen per rotatie (28BYJ-48)
 Stepper motor1 (STEPS, 2, 4, 3, 5); // Motor 1 met: IN1->2, IN2->3, IN3->4, IN4->5
 Stepper motor2 (STEPS, 6, 8, 7, 9); // Motor 2 met: IN1->6, IN2->7, IN3->8, IN4->9
 Stepper motor3 (STEPS, 10, 12, 11, 13); // Motor 3 met: IN1->10, IN2->11, IN3->12, IN4->13
 
#include <Keypad.h>
const byte ROWS = 4; //Aantal rijen
const byte COLS = 3; //Aantal kolommen 
char keys[ROWS][COLS] = { //Cijfers invoeren volgens de keypad
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {22, 24, 26, 28}; //Rijen verbinden met Arduino
byte colPins[COLS] = {30, 32, 34}; //Kolommen verbinden met Arduino
Keypad keypad = Keypad (makeKeymap(keys), rowPins, colPins, ROWS, COLS);

#include <LiquidCrystal.h>
LiquidCrystal lcd (36, 38, 40, 42, 44, 46);                                                                                                                               

  void setup() {
    lcd.begin (16,2);
    lcd.setCursor(2,0);
    lcd.print("Vives Brugge");
    lcd.setCursor(5,1);
    lcd.print("Welkom");

  }
 
void loop() {
char key = keypad.getKey ();
if(int(key) !=0) {
  if(int(key)=='1'){ // the arm gets the platform
    lcd.begin (16,2);
    lcd.setCursor(3,0);
    lcd.print ("Even geduld");
    lcd.setCursor(1,1);
    lcd.print ("Platform halen");
 motor1.setSpeed(15); // 15 toeren per minuut
 motor1.step(2038); // draai 2038 stappen
 delay(500); // wacht 0,5 seconden
 motor1.setSpeed(15); // 15 toeren per minuut
 motor1.step(-2038); // draai 2038 stappen in de negatieve zin
 delay(500); // wacht 0,5 seconden
    motor2.setSpeed(15); // 15 toeren per minuut
    motor2.step(2038); // draai 2038 stappen
    delay(500); // wacht 0,5 seconden
    motor2.setSpeed(15); // 15 toeren per minuut
    motor2.step(-2038); // draai 2038 stappen in de negatieve zin
    delay(500); // wacht 0,5 seconden
        motor3.setSpeed(15); // 15 toeren per minuut
        motor3.step(2038); // draai 2038 stappen
        delay(500); // wacht 0,5 seconden
        motor3.setSpeed(15); // 15 toeren per minuut
        motor3.step(-2038); // draai 2038 stappen in de negatieve zin
        delay(500); // wacht 0,5 seconden
 lcd.begin (16,2);
 lcd.print("Vrij? druk 1#");
 lcd.setCursor(0,4);
 lcd.print("Anders 1*");
         } 
  if(int(key)==('1'&&'*')){ // the parkingspace is full, after you push '1' and '*' the car will go to parkingspace 1
    lcd.begin (16,2);
    lcd.print ("Even geduld");
    lcd.setCursor(0,0);
    lcd.print ("Platform plaatsen");
 motor1.setSpeed(15); // 15 toeren per minuut
 motor1.step(2038); // draai 2038 stappen
 delay(500); // wacht 0,5 seconden
 motor1.setSpeed(15); // 15 toeren per minuut
 motor1.step(-2038); // draai 2038 stappen in de negatieve zin
 delay(500); // wacht 0,5 seconden
    motor2.setSpeed(15); // 15 toeren per minuut
    motor2.step(2038); // draai 2038 stappen
    delay(500); // wacht 0,5 seconden
    motor2.setSpeed(15); // 15 toeren per minuut
    motor2.step(-2038); // draai 2038 stappen in de negatieve zin
    delay(500); // wacht 0,5 seconden
        motor3.setSpeed(15); // 15 toeren per minuut
        motor3.step(2038); // draai 2038 stappen
        delay(500); // wacht 0,5 seconden
        motor3.setSpeed(15); // 15 toeren per minuut
        motor3.step(-2038); // draai 2038 stappen in de negatieve zin
        delay(500); // wacht 0,5 seconden
    lcd.begin (16,2);
    lcd.setCursor(2,0);
    lcd.print("Vives Brugge");
    lcd.setCursor(5,1);
    lcd.print("Welkom");
         } 
if(int(key)=='1'&&'#'){ //the parkingspace is empty, you can put your car on it, after you push '1' and '*' the car will go to parkingspace 1
    lcd.begin (16,2);
    lcd.print ("Even geduld");
    lcd.setCursor(0,1);
    lcd.print ("U wagen plaatsen");
 motor1.setSpeed(15); // 15 toeren per minuut
 motor1.step(2038); // draai 2038 stappen
 delay(500); // wacht 0,5 seconden
 motor1.setSpeed(15); // 15 toeren per minuut
 motor1.step(-2038); // draai 2038 stappen in de negatieve zin
 delay(500); // wacht 0,5 seconden
    motor2.setSpeed(15); // 15 toeren per minuut
    motor2.step(2038); // draai 2038 stappen
    delay(500); // wacht 0,5 seconden
    motor2.setSpeed(15); // 15 toeren per minuut
    motor2.step(-2038); // draai 2038 stappen in de negatieve zin
    delay(500); // wacht 0,5 seconden
        motor3.setSpeed(15); // 15 toeren per minuut
        motor3.step(2038); // draai 2038 stappen
        delay(500); // wacht 0,5 seconden
        motor3.setSpeed(15); // 15 toeren per minuut
        motor3.step(-2038); // draai 2038 stappen in de negatieve zin
        delay(500); // wacht 0,5 seconden
    lcd.begin (16,2);
    lcd.setCursor(2,0);
    lcd.print("Vives Brugge");
    lcd.setCursor(5,1);
    lcd.print("Welkom");
         } 
         
    
 }
 }

I would be very much inclined to keep track of which bays are used and available. Could you not just have an array of 8 bools, where 1 means taken and 0 is vacant (or vice versa). Initialize them all as 0 for vacant, and set any bay to 1 when you fill it. Then when you ask for a bay, if it's taken the screen can say so, or blink a red led, or something, and the bay doesn't eject.

But in any case, what's the difference between 1* and 1#? Seems they both return the "trolley" to its place. Why differentiate between returning a previously filled bay and a newly filled one?

For that matter, why not just press 1 by itself to return the thing? Pressing a bay's number merely toggles its position: it ejects if it's home, and homes if it's ejected. You just need to keep track of where it is so the motors do the correct thing.

Do you know how to program it with the bools you said? I don't know how you can implement that in the program.

You said if it's already taken you can show it on the lcd or with a led, but don't you need to include a memory so the arduino knows there's already a car in that spot?

About 1* en 1#, you're right, it does the same thing (put the platform back in the box).

I would store the characters in an array. Once you have two characters in the array, compare against whatever you want to compare it to.

sterretje

How can I change the array of my keypad? If i change them in my program, then the array doesn't change on the keypad?

Kenneth_AS: Do you know how to program it with the bools you said? I don't know how you can implement that in the program.

You said if it's already taken you can show it on the lcd or with a led, but don't you need to include a memory so the arduino knows there's already a car in that spot?

In fact thinking about it, since you may want to eject a busy platform to either retrieve the car or park a new one, what I would do is have 2 arrays; one shows the physical position, the other its vacant/busy status.

Then if a number is pressed, and the platrform is homed, check if it's vacant. If it's not vacant, ask for a re-press of the same key to confirm eject to retrieve car, and if it is vacant, eject for new car anyway.

If a number is pressed, and the platform is out, send it in. (But just had a thought... and this is probably what you were getting at with the * and the #, it needs to know if it's returning an empty or full platform. I guess a platform could be ejected to retrieve a car, and another car immdiately snatches the slot. But it's easier if you ask me, to make the buttons pressed separately. Click (ie press and release) the number, and ask for a * for returning empty or # for a new car. Set the bay's position as home, and vacant or not depending.)

Two arrays like:

bool platformVacant = {1,1,1,1,1,1,1,1} //1= vacant
bool platformHome =  {1,1,1,1,1,1,1,1} //1= home

Add the below just before setup()

// character array to hold 2 characters and terminating '\0'
char keypadData[3];

Usually one would let somebody enter a number and next e.g. the # key to confirm or the * to cancel/erase; your requirement is different so I opted to write a function that takes the number of characters that needs to be entered. As this sounds like school work, I did not add comments; for you to figure out how it works. Only comment that I make is that once the required number of characters has been entered, the function will return true, else it returns false. Call the function from within loop(), test for the return value and use strcmp() to check what the user entered.

Add the below e.g. after loop().

bool getKeypadData(byte numChars)
{
  static byte index = 0;

  if (index == 0)
  {
    memset(keypadData, 0, sizeof(keypadData));
  }

  char key = keypad.getKey ();
  if (int(key) != 0)
  {
    if (index != numChars)
    {
      keypadData[index++] = key;
    }
  }
  if (index == numChars)
  {
    index = 0;
    return true;
  }
  else
  {
    return false;
  }
}

your requirement is different

Might not be an actual requirement (as in, part of the project brief) but rather the way Kenneth elected to implement the need for handling 2 keys.

I agree that it would be easier for the users to be prompted one key at a time.

Something like....

Screen: Press a number
User: 1
Screen: Bay 1 is in use. Press 1 again to retrieve the car or * to cancel
User: 1
Screen: Check it's safe, and press 1
User: 1
Screen: Bay 1 is ejecting... stand clear
Screen: Bay 1 has ejected, take the car, and y'all have a nice day now

Screen: Press a number
User: 1
Screen: Bay 1 is ejected. Press * to return empty  or # to park a new car
User: *
Screen: Bay 1 is returning... stand clear