Immediately start a function when keypad key is pressed

Hi all,

I have read tons of forum threads, blogs and how to-pages but I'm new to C++ and Arduino so I need some help.

I want to use one keypad, one lcd screen and one temp/RH sensor. As default I want to show temperatur and RH from sensor on the LCD. When a key is pressed on the keypad I want to run a function which saves the number from keypad to eeprom. After saving, it will go back to default and show current temp/RH again. Sounds quite easy to do, right?

This works: I can display temp/RH on lcd. I can read values from temp/RH sensor. I can use keypad to enter and save new temp to eeprom.

My problem is that I can't figure out how to go to function directly when a key is pressed. In all my attempts I need to press the keys many, many times before the function starts. Once started, the function works.

My code has changed several times during my tests but the latest try is here:

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

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

const byte ROWS = 4; // Four rows
const byte COLS = 4; // Three columns
// Define the Keymap
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] = { 11, 10, 9, 8 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = { 7, 6, 5, 4 }; 

// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

#define ledpin 13
#define DHTPIN 2    // DHT sensor pin 

//Define sensor type
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

//Initialize DHT sensor
DHT dht(DHTPIN, DHTTYPE);

int value = 0;
int T = 0;
int RH = 1;
byte Tvalue;
byte RHvalue;

bool change = false;

void setup()
{
  pinMode(ledpin,OUTPUT);
  digitalWrite(ledpin, HIGH);
  lcd.begin(16,2);   // initialize the lcd for 16 chars 2 lines, turn on backlight
  Serial.begin(9600);
  dht.begin();

  //Read/set initial temperatur and RH
  Tvalue = EEPROM.read(T);
  RHvalue = EEPROM.read(RH);
  if (Tvalue == NULL) {
  EEPROM.write(T, 20);
  Tvalue = EEPROM.read(T);
  }
  if (RHvalue == NULL) {
  EEPROM.write(RH, 80);
  RHvalue = EEPROM.read(RH);
  }  

  // Add an event listener for this keypad
  keypad.addEventListener(keypadEvent);
  
}

void loop()
{

  //scan the pins of the keypad
  char key = keypad.getKey();
  
  if (change == true) getnum();
  else lcdprint();
  
}
 
// Starting getnum() when * is pressed
void keypadEvent(KeypadEvent key){
    switch (keypad.getState()){
    
    case PRESSED:
        if (key == '*') {
            //when '*' is pressed allow the user to input a key.
            change = true;
        }
        break;
    }
}


void lcdprint() {
                    // Reading temperature and humidity
                    float Hsensor = dht.readHumidity();
                    // Read temperature as Celsius (the default)
                    float Tsensor = dht.readTemperature();

                    lcd.clear();
                    lcd.setCursor(0,0); 
                    lcd.print("T:  ");
                    lcd.setCursor(4,0); 
                    lcd.print(Tsensor, 1);
                    lcd.setCursor(8,0);
                    lcd.print((char)223);
                    lcd.print("C  ");
                    lcd.print(Tvalue);
                    lcd.print((char)223);
                    lcd.print("C");
                    
                    lcd.setCursor(0,1);
                    lcd.print("RH: ");
                    lcd.setCursor(4,1);
                    lcd.print(Hsensor, 1);
                    lcd.setCursor(8,1);
                    lcd.print("%   ");
                    lcd.print(RHvalue);
                    lcd.print("%");   
                    delay(2000);
}

void getnum() {
  
  char key = keypad.waitForKey();

         switch (key) {
           case NO_KEY:
             // Wait and then tell user they can start the Serial Monitor and type in characters to
             break;
                               
           case '0': case '1': case '2': case '3': case '4':
           case '5': case '6': case '7': case '8': case '9':
           
             // Digits from 0 to 9
             // Don't forget we deal with ASCII characters and not numbers
             value = value * 10 + key - '0';
             if (value >= 100 ){
             lcd.clear();
             lcd.setCursor(0,0); //Start at character 0 on line 0
             lcd.print("For hogt varde!" );
             lcd.setCursor(0,1); //Start at character 0 on line 0
             lcd.print("A: Temp    B: RH");     
             value = 0;   
             }
              
             lcd.clear();
             lcd.setCursor(0,0); //Start at character 0 on line 0
             lcd.print("Nytt varde: ");
             lcd.print(value);
             lcd.setCursor(0,1); //Start at character 0 on line 0
             lcd.print("A: Temp    B: RH");
             break;

              case 'A':
              EEPROM.update(T, value);
              value = 0;
              Serial.print ("Temperatur: ");
              Tvalue = EEPROM.read(T);
              Serial.println (Tvalue);
              Serial.print ("Luftfuktighet: ");
              RHvalue = EEPROM.read(RH);
              Serial.println (RHvalue); 
            change = false;
                   
            case 'B':
              EEPROM.update(RH, value);
              value = 0;
              Serial.print ("Temperatur: ");
              Tvalue = EEPROM.read(T);
              Serial.println (Tvalue);               
              Serial.print ("Luftfuktighet: ");
              RHvalue = EEPROM.read(RH);
              Serial.println (RHvalue);
             change = false;
  
      }
}

Any suggestions on how to make function getnum() start as soon as * (or any other) key is pressed? There must be some kind of delay in the code printing sensor values to lcd.

You have a delay in your lcdprint. During that delay, you can hammer the keyboard but it will not do anything.

Check out the blink without delay example that comes with the IDE. The trick is to measure time and only when a certain period has lapsed you refresh the text on the LCD.

Something in the line of

void lcdprint()
{
  // for you to implement based on blink without delay
  if(it is time)
  {
    // Reading temperature and humidity
    float Hsensor = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float Tsensor = dht.readTemperature();

    lcd.clear();
    lcd.setCursor(0, 0);

    ...
    ...

    //reset timer
    ...
    ...

  }
}

Thanks for your reply. I didn't think of the possibility to refresh instead of using delay. It will probably solve the issue - I'll try it. :slight_smile: