Reset Data Entry

I am using some code I found on the forum for entering decimal values. It was written by @GolamMostafa in Dec, 2019.

The entry code works fine, but I want the ability to either delete a keystroke or re-enter the value so a mistake can be corrected. I couldn’t figure out how to delete a keystroke so I opted for re-entry of the entire value. I can get rejection, but I can’t seem to get the entry system to restart.

My code is below without my various restart code tries.

Please be gentle – I am 78 and before playing with Arduino, my only coding experience was Visual Basic back in the early 1990s.

Many thanks,

Don

//LIBRARIES USED
#include <Keypad_I2C.h> // I2C Keypad library from https://github.com/joeyoung/arduino_myKeypads
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>  // I2C LCD Library from https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
#include <Stepper.h>
#include <Wire.h>


/*** SET lcd ***/
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define lcd_addr 0x27     // I2C address of typical I2C LCD Backpack
#define myKeypad_addr 0x20  // I2C address of I2C Expander module


//LCD Pins to I2C LCD Backpack - These are default for HD44780 LCD's
#define Rs_pin 0
#define Rw_pin 1
#define En_pin 2
#define BACKLIGHT_PIN 3
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7


// Define the myKeypad pins
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};


// Keypad pins connected to the I2C-Expander pins P0-P7
byte rowPins[ROWS] = {0, 1, 2, 3}; // connect to the row pinouts of the myKeypad
byte colPins[COLS] = {4, 5, 6, 7}; // connect to the column pinouts of the myKeypad

// Create instance of the Keypad name myKeypad and using the PCF8574 chip
Keypad_I2C myKeypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS, myKeypad_addr, PCF8574 );


char myData[5] = {'_', '_', '.', '_', '\0'};
int arrayTracker = 3;
byte counter = 0;
float enteredValue;
char customKey;


void setup()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();


  // Initialize Keypad
  myKeypad.begin(makeKeymap(keys) );

  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);

  lcd.setCursor(0, 0);       //cursor position
  lcd.print("Enter Code:");
  lcd.setCursor(0, 1);
  lcd.print(myData);
}

void loop()
{

  DecimalEntry();
}

/**** FUNCTIONS ****/

void DecimalEntry()
{
  customKey = myKeypad.getKey();  //scan myKeypad
  if (customKey != 0x00)       //if scan code is non-zer0
  {
    myData[arrayTracker] = customKey;   //store the ASCII code of the lable of key in array
    ShowOnLCD();
    counter++;
    Serial.print("myData: "); Serial.println(myData);
    Serial.print("arrayTracker: "); Serial.println(arrayTracker);
    Serial.print("counter: "); Serial.println(counter);

    if (counter == 3)
    {
      enteredValue = atof(myData);
      HashToComplete();
      AcceptReject();
    }
  }
}


// DISPLAY ENTRY VALUE
void ShowOnLCD()
{
  lcd.setCursor(0, 1);
  lcd.print(myData);
  if (counter != 2)
  {
    myData[0] = myData[1];
    myData[1] = myData[3];
  }
}


// PRESS # TO ACCEPT
char HashToComplete()
{
  lcd.setCursor(0, 3);
  lcd.print("Press #  to Complete");
  Serial.println();
  Serial.println("Press #  to Complete");
  customKey = myKeypad.getKey();  // wait for the "*" key to be pushed
  while (customKey != '#')
  {
    customKey = myKeypad.getKey();
  }
}

// ACCEPT OR REJECT
void AcceptReject()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("You entered "); lcd.print(enteredValue, 1);
  lcd.setCursor(0, 1);
  lcd.print("A - Accept");
  lcd.setCursor(0, 2);
  lcd.print("B - ReEnter");
  Serial.println();
  Serial.print("You entered "); Serial.println(enteredValue, 1);
  Serial.println("A - Accept");
  Serial.println("B - ReEnter");

  customKey = myKeypad.getKey();

  while (customKey != 'Z')
  {
    customKey = myKeypad.getKey();

    //customKey = myKeypad.getKey();
    if  (customKey == 'A')  // accept entry and move on to next action
    {
      ChoiceA();
    }

    else if (customKey == 'B')  // reject entry & re-enter values
    {
      ChoiceB();
    }
  }
}

void ChoiceA()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Okay, Move On ");
  Serial.println("Okay, Move On ");
}

void ChoiceB()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Reset Entry ");
  Serial.println("Reset Entry ");
  // At this juncture I want to return to the
  // DecimalEntry function to re-enter the values.
  // Calling the function does not work.
}

I updated the name so Golam should be notified of the post.

Your AcceptReject() function tries to read a key and then enteres a while() loop if the key is not ‘Z’.

The first time through, nothing is pressed so getKey() return NO_KEY (or NOKEY) which is not equal to ‘Z’ and the while loop never executes. You probably want waitForKey() instead so the program will not return until a key has been pressed.

blh64: Are you suggesting I replace the while() loop with the waitForKey()?

If so, it did not work. Pressing A or B to select Accept or Re-Enter did not do anything. The A or B was just treated as an entry key and the an entry of 23.6 became 23.A.

If I misinterpreted you (a very real possibility), could you please add to your response and clarify? I would be most appreciative.

I think what you want is to wait until someone presses A or B, not until someone presses ‘Z’ which will never happen.

  do
  {
    customKey = myKeypad.getKey();
  }
  while (customKey != 'A' && customKey != 'B');

The ChoiceB() function will return to the AcceptReject() function which will return to the DecimalEntry() function which will return to loop() which will again call DecimalEntry(). All you have to do here is set your global ‘counter’ variable back to the way it was at the beginning:
counter = 0;

@johnwasser - I tried your method (see code) and got no further along. I can (and could originally) make my choice to accept or reject. And when I reject, I can move on to some new function.

But I cannot get my code to return to the DecimalEntry() function to re-enter new values.

I am totally flummoxed, but I do suspect that there is some rather simple answer that is simply outside my knowledge base.

...

void loop()
{
  DecimalEntry();
}

/**** FUNCTIONS ****/

void DecimalEntry()
{
  customKey = myKeypad.getKey();  //scan myKeypad
  if (customKey != 0x00)       //if scan code is non-zer0
  {
    myData[arrayTracker] = customKey;   //store the ASCII code of the lable of key in array
    ShowOnLCD();
    counter++;

    if (counter == 3)
    {
      enteredValue = atof(myData);
      HashToComplete();
      AcceptReject();
    }
  }
}


// DISPLAY ENTRY VALUE
void ShowOnLCD()
{
  lcd.setCursor(0, 1);
  lcd.print(myData);
  if (counter != 2)
  {
    myData[0] = myData[1];
    myData[1] = myData[3];
  }
}


// PRESS # TO ACCEPT
char HashToComplete()
{
  lcd.setCursor(0, 3);
  lcd.print("Press #  to Complete");

  customKey = myKeypad.getKey();  // wait for the "*" key to be pushed
  while (customKey != '#')
  {
    customKey = myKeypad.getKey();
  }
}

// ACCEPT OR REJECT
void AcceptReject()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("You entered "); lcd.print(enteredValue, 1);
  lcd.setCursor(0, 1);
  lcd.print("A - Accept");
  lcd.setCursor(0, 2);
  lcd.print("B - ReEnter");

// Here is @johnwasser's suggested do loop //
  do
  {
    customKey = myKeypad.getKey();
  }
  while (customKey != 'A' && customKey != 'B');
  {
    if  (customKey == 'A')  // accept entry and move on to next action
    {
      ChoiceA();
    }
    else if (customKey == 'B')  // reject entry & return to DecimalEntry() to re-enter values
    {
      ChoiceB();
    }
  }
}

void ChoiceA()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Okay, Move On ");
}

void ChoiceB()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Re-Enter Values");
  counter = 0;
  delay(2000);
  AnotherFunction(); // to test moving from one function to another
}

// this function is simply to use as a destination to prove moving on to another function //
// test function
void AnotherFunction()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Another Function");
}

Sorry, I missed the code in ShowOnLCD() where the character being typed go shifted into the 1st and 2nd characters of ‘myData’. This should reset those to ‘_’ and display them before waiting for new data.

void ChoiceB()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Re-Enter Values");

  delay(2000);
  AnotherFunction(); // to test moving from one function to another
  delay(2000);

  // Reset the data input buffer
  myData[0] = '_';
  myData[1] = '_';
  myData[3] = '_';

  // Display the prompt, like in setup()
  lcd.setCursor(0, 0);       //cursor position
  lcd.print("Enter Code:");
  lcd.setCursor(0, 1);
  lcd.print(myData);

  counter = 0; // Set back to 0
}

@ johnwasser – YOU ARE A STAR!

Your solution worked perfectly for me. Thank you.

I am re-writing a program I wrote in 2017 when recovering from lung surgery. It was my first Arduino effort. The program controls a linear screw that positions a camera for macro photography. The code was all written in Setup with nothing in Loop, and I certainly knew nothing about writing functions. The new code is all function-oriented.

This decimal entry scheme is the final brick in the re-write. Previously everything was entered in integer form and then divided to achieve decimal values.

Once again, thanks for your help.

Don