Show LCD messages for 5 seconds without delay

Hi,

I’m hitting another shortfall in my “programming skills”.
What I want to do seems to be quite simple but I spent now more then 3 hours on it and it still doesn’t work.

What I want to achief is this:
The program runs as per normal but when I press the #-key on the keypad a function (MainMenu()) will be called and this in turn will show the main menu on an LCD for 5 seconds and will then revert back to it’s original state.

The program I wrote works to a certain extend: It shows the Serial.println(“It works”) for one clock cycle and that’s it. So, calling the function is not a problem but it will only show briefly; What I’m I doing wrong?
Here is the simple sketch:

/* Code for 4x4 Keypad with menu. http://www.instructables.com/id/Connecting-a-4-x-4-Membrane-Keypad-to-an-Arduino */
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
char KeyValue;
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
// Time variables
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  //the value is a number of milliseconds

void setup(){
   Serial.begin(9600);
   startMillis = millis();  //initial start time
}
  
void loop()
{
   KeyValue=keypad.getKey();
    if(KeyValue == '#') {
       MainMenu();}
       else {
        Serial.println("Nothing pressed");
       }
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void MainMenu(){
currentMillis = millis();
  if ((currentMillis - startMillis) >= period) {
     Serial.println("It works");  
  startMillis = currentMillis;
 }
}

You use milis().

uint32_t nLCDTimer = 0;

void loop()
{
    if (/*turn on LCD screen*/ && (nLCDTimer == 0))
   {
        nLCDTimer = millis() + 20/*seconds*/ * 1000/*1000 milliseconds per second*/;
        turnOnLCDScreen();
    }
    .
    .
    .
    .
    .
    if (millis() >= nLCDTimer)
    {
         turnOffLCDScreen();
         nLCDTimer = 0;
    }
}

In all paths your KeyValue = keypad.getKey( ); is right after you set startMillis.
Re-think about where that statement is and how it affects your timing.

Thanks Boolrules,

I moved the startMillis = millis(); to the function where I call to open up the menu. However, now I can’t even call the function anymore.

From what you said you basically stated that the startMillis needs to be started when the functions opens, hence why I moved it out of the setup() function.

Could you please elaborate on that a bit more?

/* Code for 4x4 Keypad with menu. http://www.instructables.com/id/Connecting-a-4-x-4-Membrane-Keypad-to-an-Arduino */
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
char KeyValue;
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
// Time variables
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  //the value is a number of milliseconds

void setup(){
   Serial.begin(9600);
   //startMillis = millis();  //initial start time
}
  
void loop()
{
   KeyValue=keypad.getKey();
    if(KeyValue == '#') {
       MainMenu();}
       else {
        Serial.println("Nothing pressed");
       }
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void MainMenu(){
  startMillis = millis();  //initial start time
currentMillis = millis();
  if ((currentMillis - startMillis) >= period) {
     Serial.println("It works");  
  startMillis = currentMillis;
 }
}

I’ve got it working now with a FOR-loop.
Although it has the planned outcome I was hoping for it is still not good enough as whilst the program runs the FOR-loop nothing else is happening.
If I could replace the FOR-loop with the millis() function then it would be great.
Here’s my updated code:

/* Code for 4x4 Keypad with menu. http://www.instructables.com/id/Connecting-a-4-x-4-Membrane-Keypad-to-an-Arduino */
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
char KeyValue;
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void setup(){
   Serial.begin(9600);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  
void loop()
{KeyValue=keypad.getKey();
    if(KeyValue == '#') {
       MainMenu();}
       else {
        Serial.println("Nothing pressed");
       }
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void MainMenu(){
      for(int i=0; i<=1000; i++)
{  
      Serial.println("It works");  }
}

With 33 posts, you might be able to follow this: