Displaying multiple keypresses whilst being entered.

Hi

I am fairly new to programming so maybe have gone about this the wrong way. (too much cut and paste!!)

I have 3 variables to be entered. Each with multiple digits.

I used a subroutine to return the requisite variable. This all works. However it only updates the variable on the display once the # (break key) has been pressed on the keyboard. I am trying to find a way of the display showing the number AS it is being entered.

My code so far is:

/*
The device uses a  16 pin 20x4 LCD display driven by a 74HC595 Shift Register using the ShiftLCD library

The LCD circuit: 
 
 ---Shift Register 74HC595---
 * SR Pin 14 to Arduino pin 2
 * SR Pin 12 to Arduino pin 3
 * SR Pin 11 to Arduino pin 4
 * SR Pin  8 to Ground
 * SR Pin 16 to +5v
 * SR Pin 13 to Ground
 * SR Pin 10 to +5v
 -----Shift Reg to LCD--------
 * SR Pin 15 to D4
 * SR Pin 1  to D5
 * SR Pin 2  to D6
 * SR Pin 3  to D7
 * SR Pin 5  to Gnd
 * SR Pin 4  to Enable
 * SR Pin 6  to RS
 -----LCD HD44780-------------
 * Vss to Ground
 * Vdd to +5V
 * Vo  to 10k Wiperclk
 
 * R/W to Ground
 * 5v  to +5v
 * Gnd t0 Gnd

The other pin assignments are as follows:

D
0  none  TX used for Serial coms
1  none  RX used for Serial coms
2, 3, 4 LCD/Shift as above
5 None
6 
7
8 
9   
10, 11, 12,13

A
0,1,2 
3 
4 RTC SDA keypad
5 RTC SCL keypad



*/

// include the libraries:
#include <LiquidCrystal_SR3W.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <Wire.h>
#define I2CADDR 0x22

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {0, 1, 2, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6}; //connect to the column pinouts of the keypad

Keypad_I2C kpd( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// initialize the ShiftLCD library with the numbers of the interface pins
LiquidCrystal_SR3W lcd(2, 4, 3);



// variables required
int WaterReq = 0;
int TempReq = 0;
int TimeReq = 0;
int WaterReqMax = 1500;
int TempReqMax = 99;
int TimeReqMax = 120;
int WaterAct = 0;
int TempAct = 0;
int TimeAct = 0;
int TimeRemain = 0;
 

void setup(){
  Wire.begin( );
  kpd.begin( makeKeymap(keys) );
  Serial.begin(9600);


// set up the LCD's number of rows and columns: 
 lcd.begin(20, 4);
}


void loop(){
  
writeMainDisplay();

  WaterReq = GetNumber();
   if ((WaterReq >= WaterReqMax) || (WaterReq <= 0)){
     WaterReq = 0;
     WaterReq = GetNumber ();
   }
   Serial.println ();
   Serial.print ("WaterReq  ");
   Serial.print (WaterReq);

writeMainDisplay();     
   
  TempReq = GetNumber();
   if ((TempReq >= TempReqMax) || (TempReq <= 0)){
     TempReq = 0;
     TempReq = GetNumber ();
   }
   Serial.println ();
   Serial.print ("TempReq  ");
   Serial.print (TempReq);

writeMainDisplay(); 

  TimeReq = GetNumber();
    if ((TimeReq >= TimeReqMax) || (TimeReq <= 0)){
     TimeReq = 0;
     TimeReq = GetNumber ();
   }
   Serial.println ();
   Serial.print ("TimeReq  ");
   Serial.print (TimeReq);

writeMainDisplay();

}


void writeMainDisplay(){   

lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Water Req: ");
lcd.print (WaterReq);
lcd.print ("  Act: ");
lcd.print (WaterAct);

lcd.setCursor(0, 2);
lcd.print("Temp Req: ");
lcd.print (TempReq);
lcd.print ("  Act: ");
lcd.print (TempAct);

lcd.setCursor(0, 3);
lcd.print("Time Req: ");
lcd.print (TimeReq);
lcd.print ("  Act: ");
lcd.print (TimeAct);

}


int GetNumber()
{
   unsigned int num = 0;
   char key = kpd.getKey();
   while(key != '#')
   {
      switch (key)
      {
         case NO_KEY:
            break;

         case '0': case '1': case '2': case '3': case '4':
         case '5': case '6': case '7': case '8': case '9':
//            lcd.print(key);
            num = num * 10 + (key - '0');
            break;

         case '*':
            num = 0;
            break;
      }
      key = kpd.getKey();
   }

   return num;
}

Many thanks

Peter

// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {0, 1, 2, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6}; //connect to the column pinouts of the keypad

Keypad_I2C kpd( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// initialize the ShiftLCD library with the numbers of the interface pins
LiquidCrystal_SR3W lcd(2, 4, 3);

So the keypad and the LCD share pins? How does that work?

I am trying to find a way of the display showing the number AS it is being entered.

What's the problem? Add an LCD.print() in GetNumber(). The only challenging aspect will be defining where to print on the LCD.

You seem to have tried to do this before in this line in GetNumber()

      //            lcd.print(key);

But, as Paul says, the issue is in positioning the place that the number is output on the LCD. You need to use lcd.setCursor() before you call GetNumber() and uncomment the line above.

Not certain why you think the lcd and keypad use the same pins ... Except the fact that I didn't say I'm using an UNO!!! SDA and SCL are on A4 and A5.

Not certain why you think the lcd and keypad use the same pins

What are all those pin numbers for, then?

What are all those pin numbers for, then?

These are the pin numbers on the PFC8574 chip which connect to the pins on the keypad. Not to the arduino

Thanks both of you.

Solevd - Bodged the positioning for teh cancel (*) by defining row, column and digits as variables and writing " " in each space.

Is there a better way of doing it?

Just need to tidy up the routine to not allow it to write more than the specified digits. Will do that tomorrow.

Thanks again.

/*
The device uses a  16 pin 20x4 LCD display driven by a 74HC595 Shift Register using the ShiftLCD library

The LCD circuit: 
 
 ---Shift Register 74HC595---
 * SR Pin 14 to Arduino pin 2
 * SR Pin 12 to Arduino pin 3
 * SR Pin 11 to Arduino pin 4
 * SR Pin  8 to Ground
 * SR Pin 16 to +5v
 * SR Pin 13 to Ground
 * SR Pin 10 to +5v
 -----Shift Reg to LCD--------
 * SR Pin 15 to D4
 * SR Pin 1  to D5
 * SR Pin 2  to D6
 * SR Pin 3  to D7
 * SR Pin 5  to Gnd
 * SR Pin 4  to Enable
 * SR Pin 6  to RS
 -----LCD HD44780-------------
 * Vss to Ground
 * Vdd to +5V
 * Vo  to 10k Wiperclk
 
 * R/W to Ground
 * 5v  to +5v
 * Gnd t0 Gnd

The other pin assignments are as follows:

D
0  none  TX used for Serial coms
1  none  RX used for Serial coms
2, 3, 4 LCD/Shift as above
5 None
6 
7
8 
9   
10, 11, 12,13

A
0,1,2 
3 
4 RTC SDA keypad
5 RTC SCL keypad



*/

// include the libraries:
#include <LiquidCrystal_SR3W.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <Wire.h>
#define I2CADDR 0x22

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
// Digitran keypad, bit numbers of PCF8574 i/o port
byte rowPins[ROWS] = {0, 1, 2, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6}; //connect to the column pinouts of the keypad

Keypad_I2C kpd( makeKeymap(keys), rowPins, colPins, ROWS, COLS, I2CADDR );

// initialize the ShiftLCD library with the numbers of the interface pins
LiquidCrystal_SR3W lcd(2, 4, 3);



// variables required
int WaterReq = 0;
int TempReq = 0;
int TimeReq = 0;
int WaterReqMax = 1500;
int TempReqMax = 99;
int TimeReqMax = 120;
int WaterAct = 0;
int TempAct = 0;
int TimeAct = 0;
int TimeRemain = 0;
int row = 0;
int col = 0;
int dig = 0;
int digleft = 0;

void setup(){
  Wire.begin( );
  kpd.begin( makeKeymap(keys) );
  Serial.begin(9600);


// set up the LCD's number of rows and columns: 
 lcd.begin(20, 4);
}


void loop(){
  
writeMainDisplay();

row=1;  //position of WaterReq 
col=11;
dig=4;
  lcd.setCursor (col,row);  
  WaterReq = GetNumber();
   if ((WaterReq >= WaterReqMax) || (WaterReq <= 0)){
     WaterReq = 0;
     WaterReq = GetNumber ();
   }
   Serial.println ();
   Serial.print ("WaterReq  ");
   Serial.print (WaterReq);

writeMainDisplay();     

row =2;    //position of Tempreq
col = 10;
dig = 2;
  lcd.setCursor (col,row);     
  TempReq = GetNumber();
   if ((TempReq >= TempReqMax) || (TempReq <= 0)){
     TempReq = 0;
     TempReq = GetNumber ();
   }
   Serial.println ();
   Serial.print ("TempReq  ");
   Serial.print (TempReq);

writeMainDisplay(); 

row = 3; //position of TimeReq
col = 10;
dig = 3;
  lcd.setCursor (col,row);  
  TimeReq = GetNumber();
    if ((TimeReq >= TimeReqMax) || (TimeReq <= 0)){
     TimeReq = 0;
     TimeReq = GetNumber ();
   }
   Serial.println ();
   Serial.print ("TimeReq  ");
   Serial.print (TimeReq);

writeMainDisplay();

}


void writeMainDisplay(){   

lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Water Req: ");
lcd.print (WaterReq);
lcd.print ("  Act: ");
lcd.print (WaterAct);

lcd.setCursor(0, 2);
lcd.print("Temp Req: ");
lcd.print (TempReq);
lcd.print ("  Act: ");
lcd.print (TempAct);

lcd.setCursor(0, 3);
lcd.print("Time Req: ");
lcd.print (TimeReq);
lcd.print ("  Act: ");
lcd.print (TimeAct);

}


int GetNumber()
{
   unsigned int num = 0;
   char key = kpd.getKey();
   while(key != '#')
   {
      switch (key)
      {
         case NO_KEY:
            break;

         case '0': case '1': case '2': case '3': case '4':
         case '5': case '6': case '7': case '8': case '9':
            lcd.print(key);
            num = num * 10 + (key - '0');
            break;

         case '*':
         lcd.setCursor(col,row);
            num = 0;
            lcd.print(num);
          lcd.setCursor(col+1,row); // to clear other digits
            for (digleft = 0; digleft < dig - 1; digleft = digleft + 1) {
          lcd.print(" ");
    }
            
            
            lcd.setCursor(col,row);
            break;
      }
      key = kpd.getKey();
   }

   return num;
}

Bodged the positioning

That's the only way to do it unless you want to clear the whole LCD You could either set the LCD rows and columns before calling GetNumber() or pass them to the function, which is neater.

or pass them to the function, which is neater.

UKHeliBob can you please explain or give an example please. I'm very new to programming so have no idea what you are talking about!!! :)

But always wanting to learn to make it better!

Thanks

The function would look like this

void GetNumber(byte lcdCol, byte lcdRow)
{
   lcd.setCursor(lcdCol, lcdRow);
   lcd.print("   ");  //delete the number already there
   lcd.setCursor(lcdCol, lcdRow);  //put the cursor back where it started

//your stuff goes here

Call it like this

GetNumber(10,1);      //column 10, row 1

WARNING - I may well have got the rows and columns round the wrong way and I have not checked.

Thanks.

By passing them to the function, as you say it certainly looks neater. Are there other benefits? Less memory used, faster or anything like that?

Is byte faster than using int?

Thanks for helping me learn!

Probably less memory used because the setCursor() code only exists once. Bytes take up half the space of an int so more memory saving. Not much, but it adds up and works just the same as long at the variable will never be any bigger than 255.

More importantly, it is about style, maintainabilty of the code and knowing how to do things so that they can be useful when you really need them. Passing parameters really comes into its own when you want to do nearly the same thing several times in a program.

Thanks for all that. Do you ever sleep??? :)