-1

I am having trouble with a 16x2 I2C LCD screen using a 4x3 keyboard.

The following are the steps I need to do: 1.Take a numeric value through the keyboard onto the top line of the screen. This numeric value should not exceed 3 digits. 2. The keyboard should only be active (and the screen editable) when * key is pressed once. 3. The keyboard should again become inactive when # key is pressed once. 4. Whatever value has been placed in the screen should be remembered so when a sensor runs it should be able to compare its value to the screen value, achieving equality to which the core process stops.

Below is my code which is not doing the job. Can someone suggest a solution? Thanks.

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

LiquidCrystal_I2C lcd(0x27, 16, 4); 

#include<stdio.h>
const int ROW_NUM = 4; 
const int COLUMN_NUM = 3; 
char keys[ROW_NUM][COLUMN_NUM] = {
{'1','2','3'}, 
{'4','5','6'},
{'7','8','9'},
{'*','0','#'},
};
byte pin_rows[ROW_NUM] = {8,7,6,5}; 
byte pin_column[COLUMN_NUM] = {4,3,2}; 
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

int counter = 0;

void setup() {
  // put your setup code here, to run once:
lcd.init(); 
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Volume.        ml");
   lcd.setCursor(0, 1); 
   lcd.print("Filled        ml");
  

}


void loop() {
  // put your main code here, to run repeatedly:
  keypadfunction();

}

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

  if (key)
  {
    
  }
  if (key == '*')
  {
    while (key != '#' || counter <=3)
    {
      lcd.setCursor(8, 1);
      lcd.setCursor(8+counter, 1); 
      lcd.print(key);
      counter = counter+1;
    }
  }
}

changes after suggestions from @C1sc0:

#include <Keypad.h>
#include <LiquidCrystal_I2C.h> 
#include <Wire.h>
 
LiquidCrystal_I2C lcd(0x27, 16, 4); 

#include<stdio.h>
const int ROW_NUM = 4; 
const int COLUMN_NUM = 3; 
char keys[ROW_NUM][COLUMN_NUM] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'},
};
byte pin_rows[ROW_NUM] = {8,7,6,5}; 
byte pin_column[COLUMN_NUM] = {4,3,2}; 
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, 
ROW_NUM, COLUMN_NUM );

char volume[3];
byte volumeCount = 0;
bool edit = 0;
int finalValue = 0;


void setup() 
{
  // put your setup code here, to run once:
lcd.init(); 
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Volume        ml");
   lcd.setCursor(0, 1); 
   lcd.print("Filled        ml");


}


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

  if(key) // check if any key was pressed
  {
    if(key == '*') // if * was pressed switch to edit mode
    {
        lcd.setCursor(0,0); // set your cursor at columnt 0, row 0
        lcd.clear();
        lcd.print("Enter volume: ");
        edit = true;
        lcd.setCursor(0,1); // set your cursor to second row 
        volumeCount = 0;
        volume[0] = '0';
        volume[1] = '0';
        volume[2] = '0';
    }

    if(edit && volumeCount < 3) // enter edit mode
    {
        volume[volumeCount] = key; // save key to a char array
        lcd.setCursor(volumeCount,1);  // set your cursor to the 
next position
        lcd.print(volume[volumeCount]); // print the pressed button to lcd
        volumeCount++; // increment the array index (cursor position)
    }

    if(volumeCount == 3 || key == '#') // array.length == 3 OR you pressed #
    {
        edit = false; // disable edit mode
        volumeCount = 0; // reset your counter
    lcd.setCursor(0,0);
    lcd.clear();//new
    lcd.print(volume); 
    finalValue = atoi(volume); // save your entered value for further usage
    //volume[0] = '0';
    //volume[1] = '0';
    //volume[2] = '0';
    }
  }

  buttonState1 = digitalRead(buttonPin1);
    if (buttonState1 == HIGH)
    {
     //do process basis 'finalValue'
    }


}

Screen output

  • Separate the problem into two parts, reading the value to some variable and displaying this value on the screen. For reading the value you can create a state machine (if * is entered, you are in edit state, and you are in this state, until you press 3 numbers or #.) If # is pressed you set some variable where you want to store for further processing. The second task is to display this value on the screen while you are editing them. (read into an array an display this array on your display in the loop function of your code.) – IamK Oct 09 '22 at 15:44
  • @C1sc0 This is what I am trying to do but I can't imagine it in code, I am a mechanical engineer by profession. I have reached this stage of code in the question using all my creativity. Can u help? – Lord Voldemort Oct 09 '22 at 17:24
  • @C1sc0 check out my loop function – Lord Voldemort Oct 09 '22 at 17:26

1 Answers1

0

Create a bool (or byte) variable, for signaling the "edit" state

if (key == '*') { edit= true; }

in your loop (this will be your first if condition).

Create another if and here check the edit flag (if it is true, then you are waiting for the 3 values. You can read the pressed keys to a char array

char values[3];

// create this variable, before setup()

Here for the index you can use a counter (which is already present in your code as I saw. So, put all these lines in your second if condition, and increment your counter by one here. And you can display the entered character here too:

lcd.setCursor(8+counter, 1);
lcd.print(key);

Create a third if block, and check the counter is # key or counter == 3. If this condition will be satisfied you have to do 3 things reset the counter to zero, reset the edit state to false, and finally convert your value to an int (with atoi function).

After it works, you can refactor your code to make it more efficient/readable.

You need something like this:

char volume[3];
byte volumeCount = 0;
bool edit = 0;
int finalValue = 0;
void loop() 
{

  
  
  char key = keypad.getKey();
  
  if(key) // check if any key was pressed
  {
    if(key == '*') // if * was pressed switch to edit mode
    {
        lcd.setCursor(0,0); // set your cursor at columnt 0, row 0
        lcd.print("Enter volume: ");
        edit = true;
        lcd.setCursor(0,1); // set your cursor to second row 
        volumeCount = 0;
        volume[0] = '0'; 
        volume[1] = '0'; 
        volume[2] = '0';
    }
    
    if(edit && volumeCount < 3 && key != '*' && key != '#')
    {
        volume[volumeCount] = key; // save key to a char array
        lcd.setCursor(volumeCount,1);  // set your cursor to the next position
        lcd.print(volume[volumeCount]); // print the pressed button to lcd
        volumeCount++; // increment the array index (cursor position)
    }
    
    if(volumeCount == 3 || key == '#') // array.length == 3 OR you pressed #
    {
        edit = false; // disable edit mode
        volumeCount = 0; // reset your counter
        finalValue = atoi(volume); // save your entered value for further usage
        volume[0] = '0'; 
        volume[1] = '0'; 
        volume[2] = '0'; # ty for the fix!!!
    }
  }
  
  
  
  
}
IamK
  • 2,753
  • 5
  • 30
  • 39
  • Based on your suggestions I made some changes but the code doesn't work even though it compiles. Can you check where I went wrong? I have added it to my question – Lord Voldemort Oct 10 '22 at 12:40
  • @LordVoldemort I added a code snippet. – IamK Oct 10 '22 at 17:35
  • This code isn't accepting /* volume = {'0', '0', '0'}; */ . Error is - "Assigning to an array from an initializer list". How do I resolve? – Lord Voldemort Oct 11 '22 at 04:27
  • ok, managed to fix it by writing the code like this - volume[0] = '0'; volume[1] = '0'; volume[2] = '0'; – Lord Voldemort Oct 11 '22 at 05:04
  • Oh, i'll fix the answer :P ty, that means it is working? – IamK Oct 11 '22 at 05:58
  • Nah, its not working, when I press * it get printed when it should not, and then only the Key 1 is getting printed and that too only twice...its not working yet. I'm trying to make it work, please let me know if a solution strikes you. – Lord Voldemort Oct 11 '22 at 06:36
  • post your whole code, it should work now :O – IamK Oct 11 '22 at 06:37
  • I've edited my whole code (in the second code posting in my question). You'll notice some alterations I've done (just cosmetic). So the problem is this, first the * is also getting printed and it is taking the fist place in the array so only two more key spaces are left. Second, I am unable to get anything from the keyboards's second column and third row. Why would that be? – Lord Voldemort Oct 11 '22 at 07:09
  • I've also added a picture below it all to show my screen output – Lord Voldemort Oct 11 '22 at 07:18
  • I've updated my code (check the second if condition) – IamK Oct 11 '22 at 07:20
  • Working beautifully, but two issues remain. 1. What explains my inability to type anything from the second column and third row on keypad? 2. If suppose I want to type only two digits, like just 63, then I'll have to type 063. If I type 63 and press # then it takes up 630. Any way to sort that out? – Lord Voldemort Oct 11 '22 at 07:33
  • the first is maybe a mapping issue? the second if you press the # and the volumeCount != 3 insert a null terminating character into the array '\0' volume[volumeCount] = '\0'; // place an if in the third if before the volumeCount = 0; line – IamK Oct 11 '22 at 07:43
  • 1
    resolved, the keyboard was faulty, got a new one. The other issue got resolved with your suggestion. Thanks for the help – Lord Voldemort Oct 13 '22 at 10:23
  • Hi, I need some clarity regarding this solution. After this has been done, I am initiating some process by pressing a tactile switch based on the value stored in 'finalvalue'. But if I press the switch before pressing # key, then something strange is happening, lots of zeroes are getting printed after the value input there and the process is going haywire. Can we do something so that if we press the tactile switch before we press the 3 key, in the remaining places of the array it just saves null characters and then allows the 'finalvalue' to be taken for the process to follow ? – Lord Voldemort Oct 21 '22 at 07:21
  • 1
    Or maybe if it could just throw a warning that # key has not been pressed. – Lord Voldemort Oct 21 '22 at 07:22