losing keypad keys in nano program caused by receiving serial data

Hello,
I wrote a program to receive keypad keys on a nano. The nano is mbedded in the keypad as is a LED and a piezo. The nano is connected to a Mega and can receive command over serial comm. on 57600 bd.
The program functions when no commands from the Mega are received, but when a command like “LEDOn” which takes almost no time on the nano (since the delay to send “LEDOff” is done on the Mega) is send by the Mega (command = executed by the Nano), I loose key inputs unless I wait about a half second between inputting 2 keys. Example when I input 0123456789 on the keypad I see that my PSW array that the nano builds = 0369 or 02579. I only send a command from the Mega every 2 seconds in order to blink the LED during input.

#define DEBUG     
#ifdef DEBUG
#define DP(...) Serial.print(__VA_ARGS__)
#define DPL(...) Serial.println(__VA_ARGS__)
#else
#define DP(...)
#define DPL(...)
#endif

#include <Keypad.h>

char serInputString[200];
char beepAantChar[10];
int beepAant=3;
char beepDuurChar[10];
int beepDuur=500;
char beepDelayChar[10];
int beepDelay=200;
int LEDPin=13;
boolean geenBeep=false;
byte speakerPin=5;// voor tone()

int serInTeller=0;
boolean serInputComplete=false;
boolean dbg=false; 
int wacht=100;

//vr KEYPAD
const byte ROWS = 6; 
const byte COLS = 4; 
//define the cymbols on the buttons of the keypads
/*char hexaKeys[ROWS][COLS] = {
  {'0,'1','2','3'},
  {'4','5','6','7'},
  {'8','9','A','B'},
  {'C','D','E','F'}
};
*/

char hexaKeys[ROWS][COLS] = {// jelly Comb:  0-9 en enter is "A"; q is escape
  {'A','y','u','0'},//rij6 (= laatste rij); vanRnrL wordt vLnrR!!
  {'3','3','2','1'},//rij5
  {'6','6','5','4'},//rij 4
  {'9','9','8','7'},// rij3
  {'1','2','3','C'},// ongebruikt
  {'f','d','P','q'} // rij 1; q is escape; verder ongebruikt; P= rekenmachine-logo voor zorgen dat de MEGA een PSW opvraagt
};

byte rowPins[ROWS] = {19, 18, 17, 16,15,14}; //connect to the row pinouts of the keypad A0 is pin 14
byte colPins[COLS] = {10, 9, 8, 7}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 
boolean getCommand(){ // via seriele monitor!!! kan van MEG komen
    if (strstr(serInputString,"beepAant")!=NULL) {//  die commando's moeten ook in D6DITmon staan om door te geven aan de nano
      delay(wacht);
      strcpy(beepAantChar,serInputString+8);
      beepAant=atoi(beepAantChar);
      return true;
    }
    if (strstr(serInputString,"beepDuur") !=NULL){ 
        delay(wacht);
        strcpy(beepDuurChar,serInputString+8);
        beepDuur=atoi(beepDuurChar);
        return true;
    }  
    if (strstr(serInputString,"beepDelay") !=NULL){  
        delay(wacht);
        strcpy(beepDelayChar,serInputString+9);
        beepDelay=atoi(beepDelayChar);
        beepReeks(beepAant,beepDuur, beepDelay); 
        return true;
    }
    if (strstr(serInputString,"geenBeepNano") !=NULL){
        delay(wacht);
        geenBeep=true;
        return true;
        }
        
    if (strstr(serInputString,"beepNano") !=NULL){ 
        delay(wacht);
        geenBeep=false;
        //if (dbg){Serial.println("beepNano");}
        return true;
        }

     if (strstr(serInputString,"dbgn") !=NULL){ 
            delay(wacht);
            dbg=!dbg;
        return true;
        }
     if (strstr(serInputString,"LEDOff") !=NULL){ 
            delay(wacht);
            digitalWrite(LEDPin,LOW);
        return true;
        }
     if (strstr(serInputString,"LEDOn") !=NULL){ 
            delay(wacht);
            digitalWrite(LEDPin,HIGH);
        return true;
        }
} // getComm


void beepenPiezzo(int duur){ 
    if (!geenBeep){
        tone(speakerPin, 6000);
        if (duur==0) {noTone(speakerPin);return;}
        delay(duur);
        noTone(speakerPin);
    } else {
        digitalWrite(LEDPin,HIGH);
        if (duur==0) return;
        delay(duur);
        digitalWrite(LEDPin,LOW); 
  }
}

void beepReeks(byte aantal,int duur, int wacht){
  do {
      beepenPiezzo(duur);
      delay(wacht);
  aantal--;    
  }   
  while (aantal>0); 
  if (dbg) {if (geenBeep) {DPL("geenBeep");}
  } 
}

void setup(){

  pinMode (LEDPin,OUTPUT);
  digitalWrite(LEDPin,LOW);
  geenBeep=false; beepReeks(6,200, 200);
  geenBeep=true;  beepReeks(6,500, 300); geenBeep=false; //LED blink
  Serial.begin(57600);
  if (dbg){Serial.println("ready (dbg=ON)");}
}
  
void loop(){
  // get commands
  
  while(Serial.available() > 0)   { 
        char inChar = Serial.read();
        serInputString[serInTeller] = inChar;
        if (dbg) Serial.println(inChar);
        serInTeller++;
        
        if (dbg){DP(".");DP(inChar);}
        if (inChar== '\n') {
          serInputString[serInTeller] = '\0';
          serInputComplete=true;
          if (dbg)DPL(serInputString);
          serInTeller=0;
          if (dbg)DPL("input complete");
          break;
          //DPL(serInputString);
        }
    } //while
  if (serInputComplete)  {
    serInTeller = 0;
    //DPL(serInputString); 
    while (!getCommand()) {};
    serInputString[0] = '\0';
    serInputComplete=false;
    serInTeller=0;
    delay(100);
  }

  //send keys to Mega
  char customKey = customKeypad.getKey();
  
  if (customKey){
    Serial.println(customKey); 
  }
}

Anybody an idea why and how to avoid?

I see tons of delays() everywhere... that's not good if you want to keep your keyboard responsive

I suspect the problem is this line:

    while (!getCommand()) {};

Why keep trying if the command is not valid?!?

Also: At the end of getCommand() you forgot to put in "return false;", You should have gotten a warning messages about that. Set warnings to ALL.

J-M-L:
I see tons of delays() everywhere... that's not good if you want to keep your keyboard responsive

The delays are not executed since dbg is false; The only ones executed are 'wacht' which is 100mSec only if a command was detected. The fastest rate at which command arrive is every 2000mSec.

johnwasser:
I suspect the problem is this line:

    while (!getCommand()) {};

Why keep trying if the command is not valid?!?

Also: At the end of getCommand() you forgot to put in “return false;”, You should have gotten a warning messages about that. Set warnings to ALL.

That’s true, but in this application I only use commands resulting in true so they cannot provoke a delay there. And they are always executed ( I checked with debugging code after each command but I omitted it at the LEDOn, since it interferes with the reception of the key codes in the MEGA).

100ms would still be an issue for user interface, I'm not sure what's the purpose of this wait anyway.

I don't understand either why you do    while (!getCommand()) {}; what's the while() for? why don't you just call getCommand();. If what you entered is not a proper command, you'll possibly end up stuck in the while loop since your function does not return a boolean as pointed by JohnWasser

also the other thing you might want to do in order to probe your keypad more often is to replace the   while (Serial.available() > 0)  {by a  if (Serial.available() > 0)  {this way you use the loop to empty the serial buffer and you ping the keypad at every character you receive, you don't get stuck in the while to read 10 characters if they all arrived in one go

To be safe, you should also test for buffer overflow in your when adding data (just in case) char serInputString[200];

J-M-L:
100ms would still be an issue for user interface, I'm not sure what's the purpose of this wait anyway.

I don't understand either why you do    while (!getCommand()) {}; what's the while() for? why don't you just call getCommand();. If what you entered is not a proper command, you'll possibly end up stuck in the while loop since your function does not return a boolean as pointed by JohnWasser

also the other thing you might want to do in order to probe your keypad more often is to replace the   while (Serial.available() > 0)  {by a  if (Serial.available() > 0)  {this way you use the loop to empty the serial buffer and you ping the keypad at every character you receive, you don't get stuck in the while to read 10 characters if they all arrived in one go

To be safe, you should also test for buffer overflow in your when adding data (just in case) char serInputString[200];

I tried all suggestions and even added an interrupt based LED Flashing without solving the problem.
Also when I give the command to put off the LED by means of the Mega, it takes >3 second before the command is executed.

This Mega code, situated in the Serial1.available loop, sending commands to The Nano is only partially executed on the Nano!

if ((strlen(PSW)>=PSWLENGTH-1) ){ //buffer safety
              PSWComplete=true;
              beepNano();// command for nano to use beeper instead of LED
              beepReeks(1,1000,100);//(command for nano to beep 1 sec and wait 100msec) is NOT  executed at all!!!!!!!!
              Serial1.println("LEDOff");// command to put LED off takes >3sec before it's executed on Nano!!!!
              DPL("LED IS OFF");
              return;
            }
void beepNano(){
Serial1.println("beepNano");  
Serial.println("command=beepNano");  
}
  void beepReeks(byte aantal,int duur, int wacht){ //  exec by nano
char c[20]; 
strcpy(c,"beepAant");strcat(c,String(aantal).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
strcpy(c,"beepDuur");strcat(c,String(duur).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
strcpy(c,"beepDelay");strcat(c,String(wacht).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
}

All those commands function when given in SerialMonitor of the nano running code from post#1. !!

post full code. explain how things are connected

J-M-L:
post full code. explain how things are connected

Full Mega code: (since suggestions above didn’t help I used my old code)

// for Mega to give commands to Nano in keypad (LED control and beeps) and to receive 5 keystrokes (PSW) from nano keypad; connection Mega TX1 to nano RX and vice versa

#define DEBUG       
#ifdef DEBUG
#define DP(...) Serial.print(__VA_ARGS__)
#define DPL(...) Serial.println(__VA_ARGS__)
#else
#define DP(...)
#define DPL(...)
#endif

int PSWLENGTE=6;
char PSW[6]; 
int serPSWTeller=0; 
boolean PSWComplete=false;
long startPSW=0;
long PSWTijdsInterval=25000;
int speakerPin=5;// not used here
boolean dbg=false;
long vrgPSWBeepTijd;


void geenBeepNano(){
Serial1.println("geenBeepNano");  
Serial.println("command=geenBeepNano"); 
}
void beepNano(){
Serial1.println("beepNano");  
Serial.println("command=beepNano");  
}

void setup() {
  // initialize serial communication:
  Serial.begin(115200);
  Serial1.begin(57600);// input van bvb Jelly Comb numeric keypad
  Serial.println("ready:");
  pinMode(13,OUTPUT);
  pinMode(5,OUTPUT);
  strcpy(PSW,"");
  delay(1000);
 } 
 
boolean getPSW(){
  
    boolean LEDOn=false;
    byte beeps=1;
    while(Serial1.available()){Serial1.read();}// clear
    startPSW=millis(); 
    strcpy(PSW,""); 
    serPSWTeller=0;


    
    Serial1.println("LEDOff");
    delay(5000);// nodig !!
    DPL("-----------------------------");
    DPL("wacht til aft10 beeps to give PSW PSW"); 
    beepNano();// this functions
    beepReeks(10,70,100);
    delay(1000);// needed !

    long vrgPSWBeepTijd=millis();
    long PSMStartTijd=millis();
    
    while (!PSWComplete){ // also if didn't help

          Serial1.println("LEDOn");
          if (dbg) {DP("P_startPSWIs");DP(startPSW);  // mag getoond: gaat ook
              DP("  PSWTijdsIntervalIs");DP(PSWTijdsInterval);
              DP("  nogTijdIs");DPL(aftellenSec(startPSW,PSWTijdsInterval));delay(300);
          } else {DP(".");}
          delay(100);
          if ((millis()-startPSW)>=PSWTijdsInterval) {DPL("TIMEOUT");return false;}//<<<<<<<< //juiste formaat
          while (Serial1.available() > 0) {
            char c= Serial1.read();
            Serial.print(int(c));DP(" c=");
            Serial.print(c);DP(".");
            if ((c=='q') || (c=='f')) { // ESC of backspace
              while(Serial1.available()){Serial1.read();}// clear
              strcpy(PSW,"");
              serPSWTeller=0;
              DPL("na q");
              exit;
            }

            if ((int(c)>=48) && (int(c)<58)){// 0 - 9
            Serial.print(int(c));Serial.print(": ");
            Serial.print(c);
            PSW[serPSWTeller] = c;
            serPSWTeller+=1;
            PSW[serPSWTeller] = '\0';
            Serial.print("serPSWTeller=");Serial.println(serPSWTeller);
            Serial.print("nu is PSW=");Serial.print(PSW); Serial.print(" (lengte PSW=");Serial.println(strlen(PSW));
            } 
            if ((strlen(PSW)>=PSWLENGTE-1) ){ //for safety 5 char!!
              PSWComplete=true;
              beepNano();
              beepReeks(1,1000,100);//NOT  executed!!!!!!!!
              Serial1.println("LEDOff");// takes >3sec before executed!!!!
              DPL("LED IS OFF");
              return;
            }     
    }
    //digitalWrite(13,HIGH); Serial.println("LedON");delay(3000);digitalWrite(13,LOW);Serial.println("LedOFF");//
    if (PSWComplete) exit;
  }  // eindeloos
} // getPSW

   
   
 long aftellenSec(long start, long interv){
  
  return ((PSWTijdsInterval-((millis()-start)))/1000);
  
  }
  void beepReeks(byte aantal,int duur, int wacht){ //  wordt uitgevoerd door nano
char c[20]; 
strcpy(c,"beepAant");strcat(c,String(aantal).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
strcpy(c,"beepDuur");strcat(c,String(duur).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
strcpy(c,"beepDelay");strcat(c,String(wacht).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
}

void loop(){
  if (!PSWComplete) {
      //beepReeks(1,1000,200); // if uncommented: no serial.available() on nano!!
      getPSW();}
  if (PSWComplete) {
    Serial.print("PSW=");Serial.println(PSW);
    serPSWTeller=0;
    while(Serial1.available()){Serial1.read();}// clear
    strcpy(PSW,"");// clear
    PSWComplete=false;
    delay(7000);
    }
delay(2000);
}

Why do you get rid of what’s in the Serial bufffer when you call getPSW(). Seems you are trying to second guess timing of an asynchronous protocol there, this does not work.

I would suggest to study Serial Input Basics to handle this serial input in the right way

And what’s the delay(5000);// nodig !! in there ??

You might want to build this as a state machine

Couple other points:

I would suggest to indent code properly, this is hard to read. Press ctrl-T in the IDE

Don’t use the String class as you do here

 char c[20]; 
strcpy(c,"beepAant");strcat(c,String(aantal).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
strcpy(c,"beepDuur");strcat(c,String(duur).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
strcpy(c,"beepDelay");strcat(c,String(wacht).c_str());Serial.print("beepcommando=");Serial.println(c);Serial1.println(c);
}

that might lead to disappointment and uses tons of memory. You can use the itoa() function to get your integral numbers to their ascii representation or if you have enough memory use sprintf()

Thanks for yr remarks, but can this really produce a retardation of 3.5 seconds?
Reducing the 7 sec didnt help either. (The 7 seconds was intended to the time the user has to find the keyboard unit when it beeps for input.) This delays are not part of the serial.available() loop. The problem is situated at the Nano not receiving key strokes fast enough after a incoming command is threated and at some places it is even not executed as indicated in the comment.

can you post both codes ? the Nano and the Mega

J-M-L:
can you post both codes ? the Nano and the Mega

Nano code see post #1; Mega in #9.
When I commentout line 3 to 5 in

   if ((strlen(PSW)>=PSWLENGTE-1) ){ //for safety 5 char!!
              PSWComplete=true;
              beepNano();
              beepReeks(1,1000,100);//NOT  executed!!!!!!!!
              Serial1.println("LEDOff");// takes >3sec before executed!!!!

on Mega, everything works fine (but then I don't control LED and beeps).

if you call beepReeks(1,1000,100); that calls

beepenPiezzo(1000);
delay(100);

and beepenPiezzo(1000) does

if (!geenBeep) {
    tone(speakerPin, 6000);
    delay(1000);
    noTone(speakerPin);
  } else {
    digitalWrite(LEDPin, HIGH);
    delay(1000);
    digitalWrite(LEDPin, LOW);
  }

so you have a couple delays() there... at least 1.1 second.

also can I get this right, this is your setup:


Can you clarify who should give what commands where, where are things to be executed and what's the data flow you expect ?

Hello, yr diagram is correct. I only want the Mega code to inform the Nano to beep or to put ON/OFF the LED dependent on the received keys strokes from the Nano, but this looks to be hard due to the delay in capturing the key strokes when the Nano receives commands from the Mega. Without those commands, as said, key stroke capturing is very fast…
About the delay on the led. I modified the Nano software to avoid delays by working with a timer.
The new Nano code is

#define DEBUG     
#ifdef DEBUG
#define DP(...) Serial.print(__VA_ARGS__)
#define DPL(...) Serial.println(__VA_ARGS__)
#else
#define DP(...)
#define DPL(...)
#endif

#include <Keypad.h>

char serInputString[200];
char beepAantChar[10];
int beepAant=3;
char beepDuurChar[10];
int beepDuur=500;
char beepDelayChar[10];
int beepDelay=200;
int LEDPin=13;
boolean geenBeep=false;
byte speakerPin=5;// voor tone()
//int alarmBeepPin=5;
int serInTeller=0;
boolean serInputComplete=false;
boolean dbg=false; 
int wacht=100; 

//vr KEYPAD
const byte ROWS = 6; 
const byte COLS = 4; 
//define the cymbols on the buttons of the keypads
/*char hexaKeys[ROWS][COLS] = {
  {'0,'1','2','3'},
  {'4','5','6','7'},
  {'8','9','A','B'},
  {'C','D','E','F'}
};
*/

char hexaKeys[ROWS][COLS] = {// jelly Comb:  0-9 en enter is "A"; q is escape
  {'A','y','u','0'},//rij6 (= laatste rij); vanRnrL wordt vLnrR!!
  {'3','3','2','1'},//rij5
  {'6','6','5','4'},//rij 4
  {'9','9','8','7'},// rij3
  {'1','2','3','C'},// ongebruikt
  {'f','d','P','q'} // rij 1; q is escape; verder ongebruikt; P= rekenmachine-logo voor zorgen dat de MEGA een PSW opvraagt
};

byte rowPins[ROWS] = {19, 18, 17, 16,15,14}; //connect to the row pinouts of the keypad A0 is pin 14
byte colPins[COLS] = {10, 9, 8, 7}; //connect to the column pinouts of the keypad

boolean toggle1 = 0;


//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//generates pulse wave of frequency 1Hz/2 = 0.5kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle1){
    digitalWrite(LEDPin,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(LEDPin,LOW);
    toggle1 = 1;
  }
}

boolean getCommand(){ // via seriele monitor!!! kan van MEG komen
    if (strstr(serInputString,"beepAant")!=NULL) {//  die commando's moeten ook in D6DITmon staan om door te geven aan de nano
      delay(wacht);
      strcpy(beepAantChar,serInputString+8);
      beepAant=atoi(beepAantChar);
      return true;
    }
    if (strstr(serInputString,"beepDuur") !=NULL){ //retourneert de string waarin gezocht indien gevonden ander NULL
        delay(wacht);
        strcpy(beepDuurChar,serInputString+8);
        beepDuur=atoi(beepDuurChar);
        return true;
    }  
    if (strstr(serInputString,"beepDelay") !=NULL){  // dit doet effectief beepen
        delay(wacht);
        strcpy(beepDelayChar,serInputString+9);
        beepDelay=atoi(beepDelayChar);
        beepReeks(beepAant,beepDuur, beepDelay); 
        if (dbg){
          DP("beepAant");  DP(beepAant);
          DP("  beepDuur");  DP(beepDuur);DP(" beepDelay");  DPL(beepDelay);
          Serial.println("gebeept"); 
        }
        return true;
    }
    if (strstr(serInputString,"geenBeepNano") !=NULL){  // moet VOOR de volgende staan!!
        delay(wacht);
        geenBeep=true;
        //if (dbg){Serial.println("geenBeepNano");}
        return true;
        }
        
    if (strstr(serInputString,"beepNano") !=NULL){ 
        delay(wacht);
        geenBeep=false;
        //if (dbg){Serial.println("beepNano");}
        return true;
        }

     if (strstr(serInputString,"dbgn") !=NULL){ 
            delay(wacht);
            dbg=!dbg;
            if (dbg){Serial.println("dbg Toggled; gezien nu ON zal veel naar MEGA gestuurd (nt alleen numerische toetsen)");}
            return true;
        }
     if (strstr(serInputString,"LEDOff") !=NULL){ 
            delay(wacht);
            cli();
            TIMSK1 =0;// disable timer1
            if (dbg) DPL("Timer disabled");
            sei();
            if (toggle1==0) digitalWrite(LEDPin,LOW);
            //digitalWrite(LEDPin,LOW);
            return true;
        }
     if (strstr(serInputString,"LEDOn") !=NULL){ 
            delay(wacht);
            cli();
            TIMSK1 |= (1 << OCIE1A);// enable
            sei();
            if (dbg) DPL("Timer enabled");
            //digitalWrite(LEDPin,HIGH);
        return true;
        }
     if (dbg) DPL("Slecht commando");
     return true;// bij slecht commando niks doen
} // getComm


void beepenPiezzo(int duur){ // als duur==0 dan niet weer afzetten: 
    if (!geenBeep){// wel beep
        tone(speakerPin, 6000);
        if (duur==0) {noTone(speakerPin);return;}
        delay(duur);
        noTone(speakerPin);
        //delay(wacht);
    } else {
        digitalWrite(LEDPin,HIGH);
        if (duur==0) return;
        delay(duur);
        digitalWrite(LEDPin,LOW); 

  }
}

void beepReeks(byte aantal,int duur, int wacht){
  do {
      beepenPiezzo(duur);
      delay(wacht);
  aantal--;    
  }   
  while (aantal>0); 
  if (dbg) {if (geenBeep) {DPL("geenBeep");}
  } 
}

void setup(){
  pinMode (LEDPin,OUTPUT);
  digitalWrite(LEDPin,LOW);
  
  //set timer1 interrupt at 1Hz
  cli();//stop interrupts
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624; // = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  //TIMSK1 |= (1 << OCIE1A);
  TIMSK1 |= (1<<TOIE1);
  sei();//allow interrupts
  TIMSK1 |= (1 << OCIE1A);
  
  // VR INLEZEN van commandos vr leds = beepen
  geenBeep=false; beepReeks(6,200, 200); 
  geenBeep=true;  beepReeks(6,500, 300); geenBeep=false; //LED
  Serial.begin(57600); 
  if (dbg){Serial.println("ready (dbg=ON)");}
}
  
void loop(){
  // inlezen commando's van MEGA
  while(Serial.available() > 0)   { 
        char inChar = Serial.read();
        serInputString[serInTeller] = inChar;
        serInTeller++;
        if (dbg){DP(".");DP(inChar);}
        if (inChar== '\n') {
          serInputString[serInTeller] = '\0';
          serInputComplete=true;
          if (dbg)DPL(serInputString);
          serInTeller=0;
          if (dbg)DPL("input complete");
          break;
          //DPL(serInputString);
        }
    } //while
  if (serInputComplete)  {
    serInTeller = 0;
    //DPL(serInputString); 
    while (!getCommand()) {};// ££££ **** hier niet uit voor getCommand true is !!!!!!!!!
    serInputString[0] = '\0';
    serInputComplete=false;
    serInTeller=0;
    delay(100);
  }


  //send keys
  char customKey = customKeypad.getKey();
  
  if (customKey){
    Serial.println(customKey); // keybord toetsen moeten steeds doorgestuurd!! en de enige zijn na debugfase!!
  }

Now the LEDOn and LEDOff execution should be much faster since I only enable/disable the timer interrupt…
All this didn’t helped either…

I would structure this differently.

I hacked this together here based on some existing code I had posted as a tutorial (in French) for using Serial or Keypad and your own keypad definition, so I can’t guarantee this works or even compile …

On the MEGA:

// ARDUINO MEGA

#define nanoSerial Serial1
const char endMarker = 'A';
const uint8_t maxMessageSize = 31;
char nanoMessage[maxMessageSize + 1];  // +1 as we want to add a trailing '\0' to terminate a cSrting
char serialMessage[maxMessageSize + 1]; // +1 as we want to add a trailing '\0' to terminate a cSrting

boolean listenSerial()
{
  static byte messageIndex = 0;
  boolean incomingMessage = true;

  while (incomingMessage) {
    int c = Serial.read();
    if (c != -1) {
      switch (c) {
        // message complete?
        case endMarker:
          serialMessage[messageIndex] = '\0'; // terminate the c-string
          messageIndex = 0; // get ready for next time
          incomingMessage = false;
          break;
        // ignore CR
        case '\r':
          break;
        // otherwise if we have room left, store the incoming char
        default:
          if (messageIndex < maxMessageSize) serialMessage[messageIndex++] = (char) c;
          break;
      }
    } else break; // -1 means nothing to read
  }
  return incomingMessage;
}

boolean listenNano()
{
  static byte messageIndex = 0;
  boolean incomingMessage = true;

  while (incomingMessage) {
    int c = nanoSerial.read();
    if (c != -1) {
      switch (c) {
        // message complete?
        case endMarker:
          nanoMessage[messageIndex] = '\0'; // terminate the c-string
          messageIndex = 0; // get ready for next time
          incomingMessage = false;
          break;
        // ignore CR
        case '\r':
          break;
        // otherwise if we have room left, store the incoming char
        default:
          if (messageIndex < maxMessageSize) nanoMessage[messageIndex++] = (char) c;
          break;
      }
    } else break; // -1 means nothing to read
  }
  return incomingMessage;
}

// ANALYSE WHAT WE RECEIVED EITHER FROM SERIAL OR SERIAL1
void analyseInput(const char* message)
{
  if (strstr(message, "123")) {
    Serial.println(F("I received 123"));
    Serial.println(F("Sending 'Led On' to Nano"));
    Serial1.println(F("Led On"));
  }
  /* else */ // you could use else if you want to find only one command in the Serial buffer
  if (strstr(message, "456")) {
    Serial.println(F("I received 456"));
    Serial.println(F("Sending 'Led Off' to Nano"));
    Serial1.println(F("Led Off"));
  }
}

void handleNano()
{
  if (! listenNano()) analyseInput(nanoMessage);
}

void handleSerial()
{
  if (! listenSerial()) analyseInput(serialMessage);
}

// here you do everything that has been asked, but in a non blocking way using millis()
void handleStateMachine()
{

}

void setup()
{
  Serial.begin(115200);
  nanoSerial.begin(115200);
  Serial.print(F("Messages must end with '"));
  Serial.print(endMarker);
  Serial.println(F("' to validate input"));
}

void loop()
{
  handleNano();
  handleSerial();
  handleStateMachine();
}

On the Nano:

// ARDUINO NANO

#include <Keypad.h>
const byte ROWS = 6;
const byte COLS = 4;

char hexaKeys[ROWS][COLS] = {// jelly Comb:  0-9 en enter is "A"; q is escape
  {'A', 'y', 'u', '0'}, //rij6 (= laatste rij); vanRnrL wordt vLnrR!!
  {'3', '3', '2', '1'}, //rij5
  {'6', '6', '5', '4'}, //rij 4
  {'9', '9', '8', '7'}, // rij3
  {'1', '2', '3', 'C'}, // ongebruikt
  {'f', 'd', 'P', 'q'} // rij 1; q is escape; verder ongebruikt; P= rekenmachine-logo voor zorgen dat de MEGA een PSW opvraagt
};

byte rowPins[ROWS] = {19, 18, 17, 16, 15, 14}; //connect to the row pinouts of the keypad A0 is pin 14
byte colPins[COLS] = {10, 9, 8, 7}; //connect to the column pinouts of the keypad

Keypad membraneKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

const char endMarker = '\n';  // the MEGA sends commands using println() 
const uint8_t maxMessageSize = 31;
char localMessage[maxMessageSize + 1]; // +1 as we want to add a trailing '\0' to terminate a cSrting

boolean listenSerial()
{
  static byte messageIndex = 0;
  boolean incomingMessage = true;

  while (incomingMessage) {
    int c = Serial.read();
    if (c != -1) {
      switch (c) {
        // message complete?
        case endMarker:
          localMessage[messageIndex] = '\0'; // terminate the c-string
          messageIndex = 0; // get ready for next time
          incomingMessage = false;
          break;
        // ignore CR
        case '\r':
          break;
        // otherwise if we have room left, store the incoming char
        default:
          if (messageIndex < maxMessageSize) localMessage[messageIndex++] = (char) c;
          break;
      }
    } else break; // -1 means nothing to read
  }
  return incomingMessage;
}

boolean handleKeypad()
{
  char c = membraneKeypad.getKey();
  if (c != NO_KEY) {
    Serial.write(c);
  }
  return (c != NO_KEY);
}

// ANALYSE WHAT WE RECEIVED FROM SERIAL
void analyseInput(const char* message)
{
  if (strstr(message, "Led Off")) {
    digitalWrite(LED_BUILTIN, LOW);
  } else if (strstr(message, "Led On")) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    // handle wrong input
  }
}

void handleSerial()
{
  if (! listenSerial()) analyseInput(localMessage);
}

// here you do everything that has been asked, but in a non blocking way using millis()
void handleStateMachine()
{

}

void setup()
{
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop()
{
  handleKeypad();
  handleSerial();
  handleStateMachine();
}

(you have a very weird keypad with some keys sending the same code…)

Anything that is not microsecond fast I would write as a state machine and integrate that in the handleStateMachine() function on both side (for example if you have a blinking command you don’t want to be stuck blinking, so you would have a mode to remember you need to blink and then use the ‘blink without delay’ approach with millis())

if all goes as planned, if you type on the keypad 123[b][color=red]A[/color][/b] (A is the validation key the MEGA expects at the end of a message) then the built in LED of the Nano will turn on and if you type on the keypad 456[b][color=red]A[/color][/b] then the LED will turn off. In both cases there is a round trip of data to the MEGA

(as the code on the MEGA also listens to its own Serial input from the console, if your type 123A or 456A in the console then it will do the same thing. (don’t forget the ‘A’)

Note that console needs to be set at 125200 bauds

Looks very interesting and well structured, JML!
Many Thanks. The duplicate keycodes are keys I never use.(+-*/ etc).
One more question, how can I, on the Nano, produce a specific number of beeps without using delay or millis()? With 2 timers?

The keystrokes are effectively entered very fast which is already a great point!!!
I have tried to start a series of beeps (without delaycommands) with the command ‘beepDelay1000’ e.g. in the serial monitor with this code below (added to your structure) and still there are 2 strange things. First, it takes > 3 seconds after I gave the beep-command to start the beep and second, I hear only one beep even if beepCount is 5.

// ARDUINO NANO
// enter beepDelay500 or    Led ON    or    LED Off
  const byte speakerPin=5;
unsigned long lastPeriodStart;
const int duration=1000;
const int interval=6000;
boolean noBeep=false;
char beepCountChar[10];
int beepduration=1000;
char beepdurationChar[10];
int defaultBeeps=5;// default
int beepCount=5;
int beepDelay=200;
char beepDelayChar[10];
int LEDPin=13;
boolean dbg=true;
boolean beepCMD=false;

#define DEBUG       // DEBUG enables human readable logging and info messages // tijdelijk
#ifdef DEBUG
#define DP(...) Serial.print(__VA_ARGS__)
#define DPL(...) Serial.println(__VA_ARGS__)
#else
#define DP(...)
#define DPL(...)
#endif

#include <Keypad.h>
const byte ROWS = 6;
const byte COLS = 4;

char hexaKeys[ROWS][COLS] = {// jelly Comb:  0-9 en enter is "A"; q is escape
  {'A', 'y', 'u', '0'}, //rij6 (= laatste rij); vanRnrL wordt vLnrR!!
  {'3', '3', '2', '1'}, //rij5
  {'6', '6', '5', '4'}, //rij 4
  {'9', '9', '8', '7'}, // rij3
  {'1', '2', '3', 'C'}, // ongebruikt
  {'f', 'd', 'P', 'q'} // rij 1; q is escape; verder ongebruikt; P= rekenmachine-logo voor zorgen dat de MEGA een PSW opvraagt
};

byte rowPins[ROWS] = {19, 18, 17, 16, 15, 14}; //connect to the row pinouts of the keypad A0 is pin 14
byte colPins[COLS] = {10, 9, 8, 7}; //connect to the column pinouts of the keypad

Keypad membraneKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

const char endMarker = '\n';  // the MEGA sends commands using println() 
const uint8_t MEGAMessageSize = 31;
char MEGAMessage[MEGAMessageSize + 1]; // +1 as we want to add a trailing '\0' to terminate a cSrting

boolean listenSerial()
{
  static byte messageIndex = 0;
  boolean incomingMessage = true;

  while (incomingMessage) {
    int c = Serial.read();
    if (c != -1) {
      switch (c) {
        // message complete?
        case endMarker:
          MEGAMessage[messageIndex] = '\0'; // terminate the c-string
          messageIndex = 0; // get ready for next time
          incomingMessage = false;
          break;
        // ignore CR
        case '\r':
          break;
        // otherwise if we have room left, store the incoming char
        default:
          if (messageIndex < MEGAMessageSize) MEGAMessage[messageIndex++] = (char) c;
          break;
      }
    } else break; // -1 means nothing to read
  }
  return incomingMessage;
}

boolean handleKeypad()
{
  char c = membraneKeypad.getKey();
  if (c != NO_KEY) {
    Serial.write(c);
  }
  return (c != NO_KEY);
}

// ANALYSE WHAT WE RECEIVED FROM SERIAL
void analyseInput(const char* message)
{
  if (strstr(message, "Led Off")) {
    digitalWrite(LEDPin, LOW);
  } else if (strstr(message, "Led On")) {
    digitalWrite(LEDPin, HIGH);
  } else if ( strstr(message,"beepNano") !=NULL){ 
        delay(interval);
        noBeep=false;
        //if (dbg){Serial.println("beepNano");}
        return true;
  } else if (strstr(message,"beepCount")!=NULL) {//  die commando's moeten ook in D6DITmon staan om door te geven aan de nano
      delay(interval);
      strcpy(beepCountChar,message+8);
      beepCount=atoi(beepCountChar);
      return true;
   } else if (strstr(message,"beepduration") !=NULL){ //retourneert de string waarin gezocht indien gevonden ander NULL
        delay(interval);
        strcpy(beepdurationChar,message+8);
        beepduration=atoi(beepdurationChar);
        return true;
    }  else if (strstr(message,"beepDelay") !=NULL){  // dit doet effectief beepen
        delay(interval);
        strcpy(beepDelayChar,message+9);
        beepDelay=atoi(beepDelayChar);
        if (beepCount==0) beepCount=defaultBeeps;
        if (dbg){
            DP("----------------->");
            DP("beepCount=");  DP(beepCount);
            DP("  beepduration="); DP(beepduration);
            DP("  beepDelay="); DPL(beepDelay);
        }
        beepCMD=true;
        beepCue(); 
        return true; 
    } else {
      DPL ("wrong input");
  }
}

void handleSerial()
{
  if (! listenSerial()) analyseInput(MEGAMessage);
}

// here you do everything that has been asked, but in a non blocking way using millis()
void handleStateMachine()
{ 
  if (beepCMD)  beepCue();
}

void beepCue(){ 
  if (beepCount==0) {
     beepCMD=false;DPL("beepCount 0");return;
  }
   beepPiezzo();
   beepCount--;   DP("beepCount in Cue=");DPL(beepCount); 
}  
 
void beepPiezzo(){  
    if (!noBeep){// yes beep
        if (millis()-lastPeriodStart>=interval)
        {
          lastPeriodStart+=interval;
          DP("lastPeriodStart=");DPL(lastPeriodStart);
          tone(speakerPin,6000, duration); 
          Serial.println("beeped once");
        }
    } else { // later
//        digitalWrite(LEDPin,HIGH);
//        if (duration==0) return;
//        delay(duration);
//        digitalWrite(LEDPin,LOW); 
    }
}

void setup()
{
  Serial.begin(115200);
  pinMode(LEDPin, OUTPUT);
  digitalWrite(LEDPin, HIGH);
  delay(1000);
  digitalWrite(LEDPin, LOW);
}

void loop()
{
  handleKeypad();
  handleSerial();
  handleStateMachine();

}

Any idea?

As documented, your beeps need to be handled in the function handleStateMachine();, don't slow down anything when handling the serial ports, just set a flag that something needs to happen and deal with it asynchronously. One technique if you have a few things to do like beep, blink a LED, toggle a relay, is to define a bitmask of current active actions

enum : uint8_t {NO_ACTION = 0, BEEP_ON = 0b1, BEEP_OFF = 0b10, LED_ON = 0b100, LED_OFF = 0b1000, RELAY_ON = 0b10000, RELAY_OFF = 0b100000} actions = NO_ACTION;

void handleStateMachine()
{
  if (actions == NO_ACTION) return;
  if (actions & BEEP_ON) {

  } else if (actions & BEEP_ON) {

  }

  if (actions & LED_ON) {

  } else if (actions & LED_OFF) {

  }

  if (actions & RELAY_ON) {

  } else if (actions & RELAY_OFF) {

  }
}

the analyse() function would then just set the flag and initialize some timing variable that you will use in the handleStateMachine() and the state machine will remove the flag when the action is finished using the "blink without delay" type of technique.

To set a flag, for example RELAY_ON, you would do actions |= RELAY_ON;and to remove the flag you would do actions &= ~RELAY_ON;. This way flags are cumulatives, each bit in the actions byte represent an actions. (I chose a 8 bit type as I had only 6 actions, the same technique can easily scale to more bits by using uint16_t or uint32_t etc)

There are many interesting articles to read, some posted at the top of the forum, look up for state machines and also how you can use millis() (“How to do several things at a time”) etc