Run leds functions in loop and use the keypad at the same time

Hi, I have a question, I made a code for a Daft Punk helmet with WS8212 RGB leds, and i want to use a keypad 4x4 and a i2c 16x2 lcd display to control the different effects for the helmet, i have all the effect functions ready but i want to select a function and run it in loop, but i wanna still use the keypad to move trough the menu when any effects is running to change it o stop it, also i have the menu ready and it's working with the LCD, thanks for any help. i'm a begginer and Excuse my bad english.

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

#define LED_TYPE    WS2812B   // type of RGB LEDs 
#define COLOR_ORDER GRB       // sequence of colors in data stream
#define NUM_LEDS    36        // 60 LEDs numbered [0..59]
#define DATA_PIN    11        // LED data pin
#define DATA_PIN2   12        // LED data pin
#define BRIGHTNESS  100       // brightness range [off..on] = [0..255]

CRGB leds[NUM_LEDS];// Define the array of RGB control data for each LED

/////TECLADO////////
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

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

///////LCD////////////
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
/////////////////////

char key;
int counter=1;

void setup()
{
 FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);  // initialize library using CRGB LED array
 FastLED.addLeds<LED_TYPE, DATA_PIN2, COLOR_ORDER>(leds, NUM_LEDS);  // initialize library using CRGB LED array
 
 Serial.begin(9600);
 lcd.init();
 lcd.backlight();
 menu_1();  //HOMESCREEN
  
}

void loop()
{
 key = numpad.getKey() ;
 if (key != 0) 
  {
   lcd.clear();
   } 
 if(counter == 3){ menu_3();accion_3();}
 if(counter == 2){ menu_2();accion_2();}
 if(counter == 1){ menu_1();accion_1();}
 
} 

/////////////////////Menu_1 //////////////////////////////
void menu_1()
{

 FastLED.setBrightness(250);
 lcd.backlight();
 lcd.setCursor(0,0);         
 lcd.print("DAFT PUNK HELMET");
 lcd.setCursor(2,1);
 lcd.print("CONTINUE #");
 }

/////////////////////Accion 1 //////////////////////////////
void accion_1()
{ 
  if(key == '#') 
    {
    lcd.clear();
    counter=2;
    }
}
 
/////////////////////Menu_2  //////////////////////////////////
void menu_2()
{ 
   lcd.setCursor(2,0);
   lcd.print("LIGHTS");
   lcd.setCursor(8,0);
   lcd.print("VISOR");   
   lcd.setCursor(0,1);
   lcd.print("ON-1"); 
   lcd.setCursor(6,1);
   lcd.print("OFF-2");
   lcd.setCursor(13,1);
   lcd.print("<-*");
}

/////////////////////Accion 2 //////////////////////////////
void accion_2(){ 
  if(key == '1') {
    lcd.clear();
    counter=3;
  }
  if(key == '2') cascooff();
  if(key == '*') {
    lcd.clear();
    counter=1;
  }
}

/////////////////////Menu_3  //////////////////////////////////
void menu_3()
{ 
   lcd.setCursor(4,0);
   lcd.print("EFFECTS");
   lcd.setCursor(0,1);
   lcd.print("1 2 3 4 5 6");
   lcd.setCursor(13,1);
   lcd.print("<-D");
}

/////////////////////accion_3  //////////////////////////////////
void accion_3(){ 
  if(key == '1') effect1();
  if(key == '2') effect2();
  if(key == '3') effect3();
  if(key == '4') effect4();
  if(key == '5') effect5();
  if(key == '6') effect6();
  if(key == 'D') {
    lcd.clear();
    counter=2;
  }
}

/////////////////////EFFECTS//////////////////////////////////

int m=0;
int x=0;

uint32_t color[] = {CRGB::Red, CRGB::Orange, CRGB::Yellow,
                   CRGB::GreenYellow, CRGB::Green, CRGB::LightSeaGreen,
                   CRGB::Blue, CRGB::Purple, CRGB::White,};

/////////////////////apagado casco//////////////////////////////////

void cascooff()
{
fill_solid( &(leds[0]), 35 /*number of leds*/, CRGB::Black);
FastLED.setBrightness(0);
FastLED.show();
lcd.clear();
counter=1;
}

/////////////////////EFECTO 1//////////////////////////////////

void effect1()
{ 
int f=0; 
for (f=8;f>=0;f--)
 {
 int top=(f*4)+3;
 for (m=0;m<=top;m+=4)
  {
  unsigned long start = millis()+25;
  while(start > millis())
   {
   fill_solid( &(leds[m]), 4 /*number of leds*/,color[x]);
   FastLED.show();
   fill_solid( &(leds[m]), 4 /*number of leds*/, CRGB::Black);
   }
  fill_solid( &(leds[m]), 4 /*number of leds*/,color[x]);
  fill_solid( &(leds[0]), m /*number of leds*/,CRGB::Black);
  }
 if (x<8)(x++);
 else (x=0);
 }
for (f=8;f>=0;f--)
 {
 int top=(f*4);
 for (m=top;m>=0;m-=4)
  {
  unsigned long start = millis()+25;
  while(start > millis())
   {
   fill_solid( &(leds[m]), 4 /*number of leds*/,CRGB::Black);
   FastLED.show();
   fill_solid( &(leds[m]), 4 /*number of leds*/, color[x]);
   FastLED.show();
   }
  fill_solid( &(leds[top]), 4 /*number of leds*/,CRGB::Black);
  FastLED.show();
  }
 if (x<8)(x++);
 else (x=0);
 }
}

/////////////////////EFFECT 2//////////////////////////////////

void effect2()
{
  int f=0;
for (f=8;f>=0;f--){
  for (m=0;m<NUM_LEDS;m+=4)
  {
   unsigned long start = millis()+50;
   while(start > millis()){
   fill_solid( &(leds[m]), 4 /*number of leds*/,color[f]);
   FastLED.show();}
   f--;
   fill_solid( &(leds[m]), 4 /*number of leds*/, CRGB::Black);
   }
  fill_solid( &(leds[0]), NUM_LEDS /*number of leds*/, CRGB::Black);
  FastLED.show();
  }
  f==0;
for (f=0;f<=8;f++){
  for (m=36;m>0;m-=4)
  {
   unsigned long start = millis()+50;
   while(start > millis()){
   fill_solid( &(leds[m-4]), 4 /*number of leds*/,color[f]);
   FastLED.show();}
   f++;
   fill_solid( &(leds[m-4]), 4 /*number of leds*/, CRGB::Black);
   }
  fill_solid( &(leds[0]), NUM_LEDS /*number of leds*/, CRGB::Black);
  FastLED.show();
}
}


/////////////////////EFFECT 3//////////////////////////////////
void effect3()
{
  int f=0;
for (f=8;f>=0;f--){
  for (m=0;m<NUM_LEDS;m+=4)
  {
   unsigned long start = millis()+50;
   while(start > millis()){
   fill_solid( &(leds[m]), 4 /*number of leds*/,color[f]);
   FastLED.show();}
   f--;
   fill_solid( &(leds[m]), 4 /*number of leds*/, CRGB::Black);
   }
  fill_solid( &(leds[0]), NUM_LEDS /*number of leds*/, CRGB::Black);
  FastLED.show();
}
}
/////////////////////EFFECT 4////////////////////////////////// 
void effect4 () 
{
  int f=0;
for (f=0;f<=8;f++){
  for (m=0;m<NUM_LEDS;m+=4)
  {
   unsigned long start = millis()+50;
   while(start > millis()){
   fill_solid( &(leds[m]), 4 /*number of leds*/,color[f]);
   FastLED.show();}
   fill_solid( &(leds[m]), 4 /*number of leds*/, CRGB::Black);
   }
  fill_solid( &(leds[0]), NUM_LEDS /*number of leds*/, CRGB::Black);
  FastLED.show();
}
}


/////////////////////EFFECT 5////////////////////////////////// 
void effect5()
{
unsigned long start = millis()+5000;
while(start > millis())
 {
 uint8_t thishue = millis()*(255-200)/255;
 fill_rainbow(leds, NUM_LEDS, thishue, 10);            
 FastLED.show();
 }
}

/////////////////////EFFECT 6////////////////////////////////// 
 
void effect6(){
  effect1();
  effect2();
  effect2();
  effect2();
  effect2();
  effect3();
  effect3();
  effect3();
  effect3();
  effect3();
  effect3();
  effect4();
  effect5();
  }

All of your functions that display patterns on the LEDs are blocking functions. You will need to completely rewrite the code to be non-blocking.

On each pass through loop(), see if a key has been pressed. If so, deal with that, which may change the pattern.

On each pass through loop(), call the function for the active pattern. In that function, determine if it is time to change the display, or not. If it is, record the time for the next iteration, and make whatever changes are needed to the display. This will, of course, require global variables instead of all the local variables in the functions today.

Things like below do not make sense to me

      unsigned long start = millis() + 50;
      while (start > millis()) {
        fill_solid( &(leds[m]), 4 /*number of leds*/, color[f]);
        FastLED.show();
      }

For 50 milliseconds, constantly change the same led and update the complete strip. Could just as well have been

      fill_solid( &(leds[m]), 4 /*number of leds*/, color[f]);
      FastLED.show();
      delay(50);

sterretje:
Things like below do not make sense to me

      unsigned long start = millis() + 50;

while (start > millis()) {
        fill_solid( &(leds[m]), 4 /number of leds/, color[f]);
        FastLED.show();
      }



For 50 milliseconds, constantly change the same led and update the complete strip. Could just as well have been


fill_solid( &(leds[m]), 4 /number of leds/, color[f]);
      FastLED.show();
      delay(50);

At first i have all the functions with delay, but i read if you use delay you can't make run other things while the function is running, so i change all the delays for millis(), first i tried whit a "if" but i can't make it work, but when i tried "while" the functions works as if where a delay.

PaulS:
All of your functions that display patterns on the LEDs are blocking functions. You will need to completely rewrite the code to be non-blocking.

On each pass through loop(), see if a key has been pressed. If so, deal with that, which may change the pattern.

On each pass through loop(), call the function for the active pattern. In that function, determine if it is time to change the display, or not. If it is, record the time for the next iteration, and make whatever changes are needed to the display. This will, of course, require global variables instead of all the local variables in the functions today.

Hi, thanks for the response, can you give me a little example of a non-blocking function, that's new to me, i think if I use millis instead of delay it will work, but it seems not.