try this example which demonstrates how to call my function multiple times
--> I moved the code from the setup() into the loop() and use it in a non blocking way
--> input data on first line of the LCD, display what has been typed on second line
--> option in the code (commented out lines) to either allow user to change his mind and type a new number starting from the one already entered (using '*' on the keypad to erase existing digits) or if you comment out the existing line and un-comment the 2 other one, alternative is to start from a blank entry again.
give it a try
// ****** HANDLE KEYPAD ******
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[ROWS] = { 34, 36, 38, 40 };
// Connect keypad COL0, COL1, COL2 and COL3 to these Arduino pins.
byte colPins[COLS] = {41, 39, 37, 35};
//initialize an instance of class Keypad
Keypad membraneKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// ****** HANDLE LCD ******
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const byte nbCols = 20;
const byte nbLines = 4;
LiquidCrystal_I2C lcd( 0x3F, nbCols, nbLines); // my LCD is at I2C address 0x3F, 20 cols, 4 rows
// **********************************************************************************
// getNumber()
// if prepare is true, we initialize everything to receive data in a specific field on the LCD
// otherwise it handles the data input
// returns true when user has pressed the # key
// Note: defined defaults value to simplify calling the function when not in prepare stage (see below)
// **********************************************************************************
boolean getNumber(long *dataEntry, const boolean prepare = false, const uint8_t x = 0, const uint8_t y = 0, const uint8_t fieldSize = 2, const char asciiChar = '_')
{
boolean entryCompleted = false;
static uint8_t _x0, _y0, _x, _w;
static char _p; //padding Char
static boolean _fullEntry = false;
if (prepare) { // initialize the capture field
const byte maxLongLength = 12; // enough for -2147483648 so 11 characters + trailing null
char dataBuffer[maxLongLength];
_x0 = _x = x;
_y0 = y;
_w = fieldSize;
_p = asciiChar;
lcd.setCursor(_x0, _y0);
for (uint8_t i = 0; i < _w; i++) lcd.write(_p);
lcd.setCursor(_x0, _y0);
if (dataEntry) { // if we gave an initial value, display the part that fits into the area
ltoa(*dataEntry, dataBuffer, 10); // convert value into c-string in base 10
if (strlen(dataBuffer) < _w) { // do we fit in the reserved area?
_fullEntry = false;
lcd.print(dataBuffer);
_x = _x0 + strlen(dataBuffer);
} else {
dataBuffer[_w] = '\0';
*dataEntry = atol(dataBuffer);
_fullEntry = true;
lcd.print(dataBuffer);
_x = _x0 + strlen(dataBuffer) - 1;
lcd.setCursor(_x, _y0); // and don't go further than the reserved space
}
}
lcd.blink();
} else {
char entry = membraneKeypad.getKey();
switch (entry) // don't deal with case 'A'...'D':
{
case '0'...'9': // add this digit
lcd.print(entry);
if (_fullEntry) {
*dataEntry = (*dataEntry / 10) * 10 + entry - '0'; // overwrite the last digit
lcd.setCursor(_x, _y0); // and don't go further than the reserved space
} else {
*dataEntry = *dataEntry * 10 + entry - '0';
_x++;
if (_x >= _x0 + _w) {
_x--;
lcd.setCursor(_x, _y0);
_fullEntry = true;
}
}
break;
case '*': // erase last digit
*dataEntry = *dataEntry / 10;
if (_fullEntry) {
_fullEntry = false;
} else {
if (_x > _x0) _x--;
}
lcd.setCursor(_x, _y0);
lcd.write(_p);
lcd.setCursor(_x, _y0);
break;
case '#':
lcd.noBlink();
if (!_fullEntry)
for (uint8_t i = _x; i < _x0 + _w; i++) lcd.write(' '); // replace padding with white spaces
entryCompleted = true;
break;
}
}
return entryCompleted;
}
void setup() {
Serial.begin(115200);
lcd.begin();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Min=")); // to see the area
// prepare the data entry. initial value in empty, prepare mode, start col for field entry, start line for field entry, padding number during entry
getNumber(NULL, true, 4, 0, 5, '_');
}
void loop() {
static long dataEntry = 0; // important to be static to survive across loops
if (getNumber(&dataEntry)) { // wait until we get an entry validated by #
// erase the second line
lcd.setCursor(0, 1);
for (byte i = 0; i < nbCols; i++) lcd.print(F(" "));
lcd.setCursor(0, 1);
// print the data we got
lcd.print(F("Min set @ "));
lcd.print(dataEntry);
// prepare the next data entry. initial value is what has been entered
getNumber(&dataEntry, true, 4, 0, 5, '_'); // we start from the existing value, use * for example on the pad to erase digits if necessary
// if you want to restart from an empty value you would do that instead of the line above
// dataEntry = 0;
// getNumber(NULL, true, 4, 0, 5, '_'); // start with no value
}
// here you could do other stuff
}