Entering several data items via keypad once only

I need to enter several multi-digit data items via keypad before running a timing loop. I thought the keypad library would allow me to do this in Setup, i.e. some sort of do-until loop. I can’t find any examples and now have grave doubts. I have a keypad sample derived from arduinogetstarted.com but they all seem to be much the same, and I understand a new key is polled each time around the loop.

So, am I obliged to come up with a loop that has several parallel branch-and-returns controlled by a flag?

The keypad library (all code) doesn’t know if it is running in setup() or loop() or some other function you defined. Yes, you have to poll the keypad to check for keys being pressed, but that can be done in a user defined function. If you all of your input is the same, e.g. digits and then the ‘#’ key for ‘ENTER’ then you can write a function that does that and returns the value entered and call it multiple times for all the data you need.

If I collect the relevant commands from the loop and put it in a function, it will do exactly what’s required if I call it from the loop, but I get nothing if I call it from Setup. I guess it may be possible to get the first digit, but I never have. I think I might be able to do this with five switched cases in the loop, flagged by the Enter key.

It's time for you to post an example sketch that shows the problem of calling the data collection function from setup() not working

Please edit your post and add code tags to the sketch

Codes


/ * Created by ArduinoGetStarted.com
 * This example code is in the public domain
 * Tutorial page: https://arduinogetstarted.com/faq/how-to-input-a-multiple-digits-number-using-the-keypad*/

#include <Keypad.h>
const byte numRows= 4;
const byte numCols= 3;
char keymap[numRows][numCols]={
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[numRows] = {33,43,41,37};                                                                                                
byte colPins[numCols]= {35, 31, 39}; 
Keypad keypad = Keypad( makeKeymap(keymap), rowPins, colPins, numRows, numCols );

String inputString;
long inputInt;

void setup() {
  Serial.begin(9600);
  inputString.reserve(4); // maximum number of digit for a number is 10, change if needed
NumIN();
}

void loop() {
 //NumIN();
}

void NumIN() {
 char key = keypad.getKey();
  if (key) {
   Serial.println(key);
    if (key >= '0' && key <= '9') {     // only act on numeric keys
      inputString += key;               // append new character to input string
    } else if (key == '#') {
      if (inputString.length() > 0) {
        inputInt = inputString.toInt(); // YOU GOT AN INTEGER NUMBER
        inputString = "";               // clear input
        // DO YOUR WORK HERE
Serial.print(inputInt);
      }
    } else if (key == '*') {
      inputString = "";                 // clear input
    }
  }  
}

You either need to stay in the function that gets the numbers or call it multiple times

Here is an example I wrote at some point

#include <Keypad.h>

const byte numRows = 4;
const byte numCols = 3;
char keymap[numRows][numCols] = {
    { '1', '2', '3' },
    { '4', '5', '6' },
    { '7', '8', '9' },
    { '*', '0', '#' }
};

byte rowPins[numRows] = { 2, 4, 7, 8 };
byte colPins[numCols] = { 10, 11, 12 };
Keypad keypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);

int numbers[10];  //allow for 10 numbers
const byte totalNumbers = sizeof(numbers) / sizeof(numbers[0]);

void setup()
{
    Serial.begin(115200);
    Serial.println("Starting");
    getNumbers(3);  //get 3 numbers
    printNumbers(3);
}

void loop()
{
}

void getNumbers(byte count)
{
    byte currentNumber = 0;
    prompt(currentNumber);

    while (true)
    {
        char key = keypad.getKey();
        if (key)
        {
            if (key >= '0' && key <= '9')
            {
                numbers[currentNumber] = (numbers[currentNumber] * 10) + key - '0';
                Serial.print(key);
            }
            else if (key == '#')
            {
                currentNumber++;  //move to next number
                Serial.println();
                if (currentNumber >= count)
                {
                    return;
                }
                prompt(currentNumber);
            }
        }
    }
}

void printNumbers(byte count)
{
    Serial.println("You entered :");
    for (int n = 0; n < count; n++)
    {
        Serial.println(numbers[n]);
    }
}

void prompt(byte n)
{
    Serial.print("Enter number ");
    Serial.print(n);
    Serial.println(" followed by #");
}

no need for a while loop. poll the keypad, capture codes in an array and process the array when an 'end' key (e.g. '#') is pressed

the processing of the input can affect the state of the running code.

Here is the idea in the simplest way you might see, or do, it. You tried a function.

But loop() would call the function over and over. You recognized the need for some kind of loop, which you could place in setup().

void setup() {
  Serial.begin(115200);
  inputString.reserve(4);

  while (true) {
    NumIN();

// and you need to figure out why to stop this part:

    if ("we are done with this part")
      break;
    }
}

void loop() {
 //NumIN();
}

Another and different way is seen alla time. Use a global boolean variabke

bool  needToDo = true;

and just let your loop() handle the, um, looping. It may look ugly but no one cares.

void loop() {

  if (needToDo) {
    NumIN();

// and still, you'll need to say when enough is enough, viz:

    if ("enough is enough")
      needToDo = false;

    return;  // skip out on the rest of the loop for now
  }


// below here is the real runs allatime after setup

}

BTW while I was typing this, the 20th century called and wanted its baud rate back. Hence the 115200 edit. :expressionless:

a7

while( condition ) { … };

do { … } while( condition );

you didn’t put it in a loop inside of setup().

That I did NOT know was possible but I guess it’s obvious - once you consider it might be. And probably the most easily adaptable. Thank you one and al, I will pursue this….

Did you try the code in post #8 ?

It’s 0130, I’ll pursue this tomorrow

Thank you

OK

It appears that I cannot put a real “void loop ()” loop in Setup after all, but I can do a loop by other means. The code in post#8 works but I cannot use it. It requires me to specify the number of numbers, which re-incurs the problem, and I don’t know what to do with the output anyway.

I can start a “while” from Setup, but I cannot get out of it. I was looking for a key “#” to do this. The result is what I want, an int, and It can be any number of digits. The

inputString.reserve(4);

line is ineffective, although I think it is in the right position. I’m not quibbling about this, the result at toInt is all I need.

#include <Keypad.h>
const byte numRows= 4;
const byte numCols= 3;
char keymap[numRows][numCols]={
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[numRows] = {33,43,41,37};                                                                                                
byte colPins[numCols]= {35, 31, 39}; 
Keypad keypad = Keypad( makeKeymap(keymap), rowPins, colPins, numRows, numCols );
char key = "";
String inputString;
int inputInt;
int numShots;

void setup() {
  Serial.begin(9600);
  Serial.println("Starting");
  inputString.reserve(4); // maximum number of digit for a number is 10, change if needed

while (key !='#') {
NumIN();
}
Serial.println(inputInt);
numShots = inputInt;
Serial.print("numShots ln27 =   ");
Serial.print(numShots);
}

void loop() {
Serial.println(inputInt);
Serial.print("numShots ln33=   ");
Serial.print(numShots);
 delay(5000);
}

void NumIN() {
 char key = keypad.getKey();

  if (key) {
   Serial.println(key);
    if (key >= '0' && key <= '9') {     // only act on numeric keys
      inputString += key;               // append new character to input string
    } else if (key == '#') {
      if (inputString.length() > 0) {
        inputInt = inputString.toInt(); // YOU GOT AN INTEGER NUMBER
        inputString = "";               // clear input
Serial.print("inputInt in srtn ln50  ");
Serial.println(inputInt);//This is OK to here

      }
    } else if (key == '*') {
      inputString = "";                 // clear input
    }
  }
}

I guess all I need is an elegant exit, but I certainly need it. While a switch case in the loop should work, I now realise it’s a really bad idea.

do { something } while ( condition ); // loops until condition is false

You CAN’T make a loop with an escape clause?

I take it that’s a question. The answer is no, I have never had the need to exit a loop before.

You cannot write a while loop without specifying the exit condition

Try this modified version of my previous example. It makes no assumptions as to how many numbers will be entered beyond the size of the numbers array in which they are stored. Ideally the code should check that it is not writing outside of the array and it would be easy to do that

Once the numbers are in the array it is up to you what you do with them

#include <Keypad.h>

const byte numRows = 4;
const byte numCols = 3;
char keymap[numRows][numCols] = {
    { '1', '2', '3' },
    { '4', '5', '6' },
    { '7', '8', '9' },
    { '*', '0', '#' }
};

byte rowPins[numRows] = { 2, 4, 7, 8 };
byte colPins[numCols] = { 10, 11, 12 };
Keypad keypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);

int numbers[10];  //allow for 10 numbers
const byte totalNumbers = sizeof(numbers) / sizeof(numbers[0]);

void setup()
{
    Serial.begin(115200);
    Serial.println("Starting");
    int count = getNumbers();  //get the numbers
    useTheNumbers(count);
}

void loop()
{
}

byte getNumbers()
{
    byte currentNumber = 0;
    prompt(currentNumber);
    char key = ' ';
    while (key != '#')  //# ends input of the list of numbers
    {
        key = keypad.getKey();
        if (key)
        {
            if (key >= '0' && key <= '9')
            {
                numbers[currentNumber] = (numbers[currentNumber] * 10) + key - '0';
                Serial.print(key);
            }
            else if (key == '*')  //* ends current number input
            {
                currentNumber++;  //move to next number
                Serial.println();

                prompt(currentNumber);
            }
        }
    }
    return currentNumber;
}

void useTheNumbers(byte count)
{
    Serial.println("You entered :");
    for (int n = 0; n < count; n++)
    {
        Serial.println(numbers[n]);
    }
}

void prompt(byte n)
{
    Serial.print("Enter number ");
    Serial.print(n);
    Serial.println(" followed by *");
    Serial.println("Enter # to end the list of numbers");
}

do

{

something;

something;

something;

if ( condition ) break;

something;

something;

something;

} while( 1 ); // loop with exit in the middle

while ( condition ) // loop with exit at the top

{

something;

something;

something;

};

OK, this is now looking pretty good. An unexpected bonus is that entering time with the same general procedure has worked out well……

#include <Keypad.h>

const byte numRows = 4;
const byte numCols = 3;
char keymap[numRows][numCols] = {
    { '1', '2', '3' },
    { '4', '5', '6' },
    { '7', '8', '9' },
    { '*', '0', '#' }
};

byte rowPins[numRows] = {33,43,41,37};                                                                                                
byte colPins[numCols]= {35, 31, 39}; 
Keypad keypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);

int numbers[6];  //allow for 6 numbers
int exposure, numShots, camera, hh, mm, ss;
long time2run, finishtime;
const byte totalNumbers = sizeof(numbers) / sizeof(numbers[0]);

void setup()
{
    Serial.begin(9600);
    Serial.println("Starting WATCH FOR FLASH");
    Serial.println("Enter # to end the list of numbers");
    int count = getNumbers();  //get the numbers
    useTheNumbers(count);
 numShots = numbers[0];
 exposure = numbers[1];
   camera = numbers[2];
       hh = numbers[3];
       mm = numbers[4];
       ss = numbers[5];
printOut();
}

void loop()
{
}

byte getNumbers()
{
    byte currentNumber = 0;
    prompt(currentNumber);
    char key = ' ';
    while (key != '#')  //# ends input of the list of numbers
    {
        key = keypad.getKey();
        if (key)
        {
            if (key >= '0' && key <= '9')
            {
                numbers[currentNumber] = (numbers[currentNumber] * 10) + key - '0';
                Serial.print(key);
            }
            else if (key == '*')  //  ends current number input
            {
                currentNumber++;  //move to next number
                Serial.println();

                prompt(currentNumber);
            }
        }
    }
    return currentNumber;
}

void useTheNumbers(byte count)
{
    Serial.println("Summary :");
    for (int n = 0; n < count; n++)
    {
        Serial.print(numbers[n]);
        Serial.print("  ");
        
    }
    Serial.println();
    
}

void prompt(byte n)
{
 switch (n) {
    case 0:
    Serial.println("Number of shots?    ");
      break;
    case 1:
    Serial.println("Exposure in seconds?");
      break;
    case 2:
    Serial.println("Cameras in use? 1/2 ");
      break;
    case 3:
     Serial.println("Start time hh*mm*ss* ");
      break;
 }
}

void printOut() {
Serial.print("Number of shots= ");
Serial.println(numShots);
Serial.print("exposure secs=   ");
Serial.println(exposure);
if (camera == 1)
{
  Serial.println("1 camera, allow 1sec");
  Serial.println(" for storage        ");
  time2run = (numShots * (exposure+1));
}
else 
{
  Serial.println("2 cameras used, each");
  Serial.println("shooting alternately");
  time2run = (numShots * exposure);
}
Serial.print("Start time  "); 
hhmmss();
}

void hhmmss() {
  if (hh<10) {
  Serial.print("0");
}                                
Serial.print(hh);
Serial.print(":");      
if (mm<10) {            
  Serial.print("0");  
}                       
Serial.print(mm);
Serial.print(":");            
if (ss<10) {
    Serial.print("0");
}                                 
Serial.println(ss);
}

Thank you.

Starting WATCH FOR FLASH
Enter # to end the list of numbers
Number of shots?
300
Exposure in seconds?
8
Cameras in use? 1/2
2
Start time hh*mm*ss*
3
45
00
Summary :
300 8 2 3 45 0
Number of shots= 300
exposure secs= 8
2 cameras used, each
shooting alternately
Start time 03:45:00