What's wrong with millis() and nRF24 communication?

I'm trying to make a nRf24L01 network with multitasking, but no matter how i redo the codes for master and slaves and replace the millis(), they don't want to work properly.

What I want to do is a program that sends to slave an information about time interval which is selected before starting program1() and after that I want to turn on LED's on slaves for that interval and then turn them off.

The previous versions at first attempt were sending information about selected interval but the LED's were turning on at the second program run. Now the whole master program just ends immediately.

Here are the current codes:
Master:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <RF24Network.h>
#include <RF24Network_config.h>
#include <SPI.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

String screen[5]={"Run program","Choose Program","Reaction time","Shoots","Score"};
int screenIndex=0;

//button addresses
const int pinLeft=4;
const int pinRight=5;
const int pinUp=6;
const int pinDown=7;


//Modes
String difficultyLevels[5][5] = {{""},{"Rookie","Plus & minus","Risk","Speed"},{"1 sec","2 sec","5 sec","7 sec","10 sec"},{""},{""}}; 
int difficultyIndex = 0;

//Indexes 
int optionsIndex[5]={0,0,0,0,0};  


//Utils
bool screenWasChaned = true;
bool intputWasChaged_Left = false; //
bool intputWasChaged_Right = false;
bool intputWasChaged_Up = false;
bool intputWasChaged_Down = false;

byte LED = 0;

unsigned long currentTime;
unsigned long interval = 1000;

RF24 radio(10, 9);  //nRF24L01 pins (CE, CSN)

const uint64_t rAddress[] = {0xB00B1E50D2LL, 0xB00B1E50C3LL, 0xB00B1E50E5LL}; 
const uint64_t wAddress[] = {0xB00B1E50B1LL, 0xB00B1E50A4LL, 0xB00B1E50F6LL};

void setup() 
{
  Serial.begin(57600);
  Serial.println("Program start");
  radio.begin();
  radio.openReadingPipe(1, rAddress[0]); //open read pipe 
  radio.openReadingPipe(2, rAddress[1]); 
  radio.openReadingPipe(3, rAddress[2]); 
  radio.stopListening();
  pinMode(pinLeft, INPUT);
  pinMode(pinRight, INPUT);
  pinMode(pinDown, INPUT);
  pinMode(pinUp, INPUT);
  digitalWrite(pinLeft, HIGH); //button responds to 0 
  digitalWrite(pinRight, HIGH);
  digitalWrite(pinDown, HIGH);
  digitalWrite(pinUp, HIGH);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  currentTime = millis(); //
}

void loop()
{
  if(screenWasChaned){
    if (screenIndex==3)
    {
        displayScreen(screenIndex,String(optionsIndex[screenIndex]));
        screenWasChaned = false;
    }
    else{
      displayScreen(screenIndex,difficultyLevels[screenIndex][optionsIndex[screenIndex]]);
      screenWasChaned = false;
      }
    }
  inputControl();
  inputResolve();
}

void displayScreen(int screenIndex, String value)
{
  lcd.clear();
  lcd.print(screen[screenIndex]);
  lcd.setCursor(0,1);
  lcd.print(value);
}

void inputControl()
{
  int readingLeft=digitalRead(pinLeft);
  int readingRigth=digitalRead(pinRight);
  int readingUp=digitalRead(pinUp);
  int readingDown=digitalRead(pinDown);
  if (readingLeft == LOW)
  {
      if (screenIndex>0 && !intputWasChaged_Left)
      {
        screenIndex = screenIndex-1;
        screenWasChaned = true;
        intputWasChaged_Left = true; //czeka na resolve przyciku aby nie było podwójnych przeskoków przy trzymaniu klawisza;
      }
  }
    if (readingRigth == LOW)
  {
      if (screenIndex < 4 && !intputWasChaged_Right)
      {
        screenIndex = screenIndex+1;
        screenWasChaned = true;
        intputWasChaged_Right = true;
      }
  }
      if (readingUp == LOW)
  {
      if(screenIndex==0 && !intputWasChaged_Up)
      {
        StartProgram(optionsIndex[1]);
        intputWasChaged_Up = true;
      }
      if(screenIndex==3 && optionsIndex[screenIndex]>=3 && !intputWasChaged_Up)
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }
      
      if (optionsIndex[screenIndex]<3 && !intputWasChaged_Up)///lock opcji w góre
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }
  }
      if (readingDown == LOW)
  {
      if (optionsIndex[screenIndex]>0 && !intputWasChaged_Down)
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]-1;
        screenWasChaned = true;
        intputWasChaged_Down = true;
      }
  }
}
void inputResolve()
{
  int readingLeft=digitalRead(pinLeft);
  int readingRigth=digitalRead(pinRight);
  int readingUp=digitalRead(pinUp);
  int readingDown=digitalRead(pinDown);
  
  if (readingLeft == HIGH && intputWasChaged_Left)
  {
    intputWasChaged_Left = false; 
  }
  
  if (readingRigth == HIGH && intputWasChaged_Right)
  {
    intputWasChaged_Right = false;
  }
  
  if (readingUp == HIGH&&intputWasChaged_Up)
  {
        intputWasChaged_Up = false;
  }
      
  if (readingDown == HIGH&&intputWasChaged_Down)
  {
        intputWasChaged_Down = false;
  }
}

void StartProgram(int ProgramIndex)
{
  switch (ProgramIndex)
  {
  case 0:
        program1();
    break;
  case 1:
        program2();
    break;

  case 2:
        program3();
    break;

  case 3:
        program4();
    break;

  default:
    break;
  }
}

void program1()
{
  unsigned long sendLED;
  displayScreen(0, "Rookie start");
  if(sendTime(optionsIndex[2]))
  {
    sendLED = currentTime;
    for (int i = 0; i < optionsIndex[3]; i++)
    {
      byte targetIndex = random(0,3);
      LED = 1;
      if(currentTime - sendLED >= interval)
      {
        SendToSlave(LED,targetIndex);
        sendLED = currentTime;
      }
    }
  }
  displayScreen(0,"END");
} 

void program2(){displayScreen(0,"Program 2");}
void program3(){displayScreen(0,"Program 3");}
void program4(){displayScreen(0,"Program 4");}

bool sendTime(int recTime) //send the interval to slaves
{
  bool done = false;
  unsigned long sendRecTime;
  sendRecTime = currentTime;

  if(currentTime - sendRecTime>=1000)
  {
    radio.openWritingPipe(wAddress[0]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 1");
  }
  
  if(currentTime - sendRecTime>=2000)
  {
    radio.openWritingPipe(wAddress[1]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 2");
  }
  
  if(currentTime - sendRecTime>=3000)
  {
    radio.openWritingPipe(wAddress[2]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 3");
  }
  done = true;
  return done;
}

void SendToSlave(byte LED,byte adressIndex)
{
  radio.stopListening();
  Serial.print("Send to slave ");
  Serial.println(adressIndex);
  radio.openWritingPipe(wAddress[adressIndex]);
  radio.write(&LED, sizeof(LED));
}

Slave

#include <RF24Network.h>
#include <RF24Network_config.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>

RF24 radio(10, 9); //nRF24L01 pins (CE, CSN)
const uint64_t rAddress = 0xB00B1E50B1LL;
const uint64_t wAddress[1] = {0xB00B1E50D2LL};

int recTime = 0;

bool Hit = false; //sensor state

byte LED = 0;
byte pipe = 0;

unsigned long currentTime;
unsigned long baseTime = 0;
unsigned long timer1 = 1000;
unsigned long timer2 = 2000;

void setup() 
{
 Serial.begin(57600);
 Serial.println("Listening");
 radio.begin();
 radio.openReadingPipe(1, rAddress);
 radio.startListening();
 pinMode(3, OUTPUT); //LED green
 pinMode(4, OUTPUT); //LED red
 pinMode(5, OUTPUT); //LED blue
 pinMode(8, INPUT); //vibration sensor
 currentTime = millis();
}

void loop() 
{
 radio.startListening(); 
 while (radio.available(&pipe))           
 {
   if(recTime == 0)
   catchTime();

   radio.startListening();
   radio.read(&LED, sizeof(LED));          
   if (LED == 1 && recTime == 1)                             
   {
     recTime_1();
   }
   else if (LED == 1 && recTime == 2)                             
   {
     recTime_2();
   }
 }    
}

void catchTime()
{
 radio.read(&recTime, sizeof(recTime));
 Serial.print("Czas: ");
 Serial.println(recTime); 
}

void recTime_1()
{
 baseTime = currentTime;    
 Serial.println("Light");            
 digitalWrite(3, HIGH);
 if(currentTime - baseTime >= timer1)
 {
   digitalWrite(3, LOW);
   Serial.println("Darkness"); 
 }
}

void recTime_2()
{
 baseTime = currentTime;    
 Serial.println("Light");            
 digitalWrite(3, HIGH);
 if(currentTime - baseTime >= timer2)
 {
   digitalWrite(3, LOW);
   Serial.println("Darkness"); 
 }
}

millis is not to blame
It's not that it's not working properly, it's that you're using it incorrectly.

Your "currentTime" variable is not contains a really "current" millis(). It contains value of millis() at start of program and never updated in the code. As a result, all your time intervals works only during the first second after start and than freeze.
Please see the "blink without delay" IDE example and put the attention to the purpose of previousMillis variable

Could it be a problem that you call radio.stopListening(); in a couple of places but never call radio.startListening(); ?

startListening():
Be sure to call openReadingPipe() first. Do not call write() while in this mode, without first calling stopListening(). Call isAvailable() to check for incoming traffic, and read() to get it.

stopListening():
Do this before calling write().

Yeah, but when I moved the currentTime = millis() to the void loop, it still end immediately despite the fact that I'm using the formula previousTime = currentTime(just different variable name) in other functions, like:

bool sendTime(int recTime) //send the interval to slaves
{
  bool done = false;
  unsigned long sendRecTime;
  sendRecTime = currentTime;

  if(currentTime - sendRecTime>=1000)
  {
    radio.openWritingPipe(wAddress[0]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 1");
  }

I've placed the sendRecTime = currentTime first because, it will take a few seconds before this function starts, so I want to restart the value from which the millis() should count

I'm not calling the radio.startListening(); yet because the slave sends nothing to the master. So i was thinking that it is not required :confused:

That's never going to do anything because it is equivalent to:

  if(0 >= 1000)
  {

Zero is never going to be greater than 1000. :frowning:

Did you want to send the messages at intervals? That would be more like:

bool sendTime(int recTime) //send the interval to slaves
{
  static unsigned long cycleStartTime = 0;
  static bool done1 = true;
  static bool done2 = true;
  static bool done3 = true;

  // If the old cycle is done, start over
  if (done1 && done2 && done3)
  {
    done1 = false;
    done2 = false;
    done3 = false;
    cycleStartTime = millis();
  }

  unsigned long elapsedTime = millis() - cycleStartTime;

  if (!done1 && elapsedTime >= 1000)
  {
    done1 = true;
    radio.openWritingPipe(wAddress[0]);
    radio.write(&recTime, sizeof recTime);
    Serial.println("Time SL 1");
  }
  
  if (!done2 && elapsedTime >= 2000)
  {
    done2 = true;
    radio.openWritingPipe(wAddress[1]);
    radio.write(&recTime, sizeof recTime);
    Serial.println("Time SL 2");
  }
  
  if (!done3 && elapsedTime >= 3000)
  {
    done3 = true;
    radio.openWritingPipe(wAddress[2]);
    radio.write(&recTime, sizeof recTime);
    Serial.println("Time SL 3");
  }

  return done1 && done2 && done3;
}

Unfortunately it didn't change much. Now to get any result i have to start the program1() few times and in one run I can receive only one transmission to slave :worried:

Alright, I finally achieved codes which are sending information about selected reaction time and after that sending orders to turn on the LED's. The slaves also do their job with turning LED's on and off.

But neither of them respects the intervals no matter what value is in the variable, also there's problem with receiving the first message like it would be empty or the nRF24 wasn't able to read it.

So now it looks like this:
Let's assume I selected to send 10 orders to slaves
In first program run all slaves receive information about the reaction time, but only slave 2 & 3 gonna turn on the LED because master sent them at least 2 messages. Slave 1 got only one message and received only reaction time. After next program run all slaves can turn on LED's.

My questions are:

  1. Can I do something to make them respect the interval?
  2. How can I repair the first message reading?

Master code:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <RF24Network.h>
#include <RF24Network_config.h>
#include <SPI.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

String screen[5]={"Begin","Pick program","Reaction time","Shoots","Score"};
int screenIndex=0;

//Button pins
const int pinLeft=4;
const int pinRight=5;
const int pinUp=6;
const int pinDown=7;


//Modes
String difficultyLevels[5][5] = {{""},{"Rookie","Plus i minus","Risk","Speed"},{"1","2","5","7","10"},{""},{""}};
int difficultyIndex = 0;

//Indexes
int optionsIndex[5]={0,0,0,0,0}; 
byte LED = 0;


//Utils
bool screenWasChaned = true;
bool intputWasChaged_Left = false; //
bool intputWasChaged_Right = false;
bool intputWasChaged_Up = false;
bool intputWasChaged_Down = false;

unsigned long currentTime;
unsigned long interval = 5000;

RF24 radio(10, 9);  //nRF24L01 pins (CE, CSN)

const uint64_t rAddress[] = {0xB00B1E50D2LL, 0xB00B1E50C3LL, 0xB00B1E50E5LL}; 
const uint64_t wAddress[] = {0xB00B1E50B1LL, 0xB00B1E50A4LL, 0xB00B1E50F6LL};

void setup() 
{
  Serial.begin(57600);
  Serial.println("Program start");
  radio.begin();
  radio.openReadingPipe(1, rAddress[0]); 
  radio.openReadingPipe(2, rAddress[1]); 
  radio.openReadingPipe(3, rAddress[2]);
  radio.stopListening();
  pinMode(pinLeft, INPUT);
  pinMode(pinRight, INPUT);
  pinMode(pinDown, INPUT);
  pinMode(pinUp, INPUT);
  digitalWrite(pinLeft, HIGH); 
  digitalWrite(pinRight, HIGH);
  digitalWrite(pinDown, HIGH);
  digitalWrite(pinUp, HIGH);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  
}

void loop()
{
  currentTime = millis();
  if(screenWasChaned){
    if (screenIndex==3)
    {
        displayScreen(screenIndex,String(optionsIndex[screenIndex]));
        screenWasChaned = false;
    }
    else{
      displayScreen(screenIndex,difficultyLevels[screenIndex][optionsIndex[screenIndex]]);
      screenWasChaned = false;
      }
    }
  inputControl();
  inputResolve();
  delay(100);
}

void displayScreen(int screenIndex, String value)
{
  lcd.clear();
  lcd.print(screen[screenIndex]);
  lcd.setCursor(0,1);
  lcd.print(value);
}

void inputControl()
{
  int readingLeft=digitalRead(pinLeft);
  int readingRigth=digitalRead(pinRight);
  int readingUp=digitalRead(pinUp);
  int readingDown=digitalRead(pinDown);
  if (readingLeft == LOW)
  {
      if (screenIndex>0 && !intputWasChaged_Left)
      {
        screenIndex = screenIndex-1;
        screenWasChaned = true;
        intputWasChaged_Left = true;
      }
  }
    if (readingRigth == LOW)
  {
      if (screenIndex < 4 && !intputWasChaged_Right)
      {
        screenIndex = screenIndex+1;
        screenWasChaned = true;
        intputWasChaged_Right = true;
      }
  }
      if (readingUp == LOW)
  {
      if(screenIndex==0 && !intputWasChaged_Up)
      {
        StartProgram(optionsIndex[1]);
        intputWasChaged_Up = true;
      }
      if(screenIndex==3 && optionsIndex[screenIndex]>=3 && !intputWasChaged_Up)
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }
      
      if (optionsIndex[screenIndex]<3 && !intputWasChaged_Up)///lock opcji w góre
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }
  }
      if (readingDown == LOW)
  {
      if (optionsIndex[screenIndex]>0 && !intputWasChaged_Down)
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]-1;
        screenWasChaned = true;
        intputWasChaged_Down = true;
      }
  }
}
void inputResolve()
{
  int readingLeft=digitalRead(pinLeft);
  int readingRigth=digitalRead(pinRight);
  int readingUp=digitalRead(pinUp);
  int readingDown=digitalRead(pinDown);
  
  if (readingLeft == HIGH && intputWasChaged_Left)
  {
    intputWasChaged_Left = false; 
  }
  
  if (readingRigth == HIGH && intputWasChaged_Right)
  {
    intputWasChaged_Right = false;
  }
  
  if (readingUp == HIGH&&intputWasChaged_Up)
  {
        intputWasChaged_Up = false;
  }
      
  if (readingDown == HIGH&&intputWasChaged_Down)
  {
        intputWasChaged_Down = false;
  }
}

void StartProgram(int ProgramIndex)
{
  switch (ProgramIndex)
  {
  case 0:
        program1();
    break;
  case 1:
        program2();
    break;

  case 2:
        program3();
    break;

  case 3:
        program4();
    break;

  default:
    break;
  }
}

void program1()
{
  unsigned long sendLED = 0;
  displayScreen(0, "Rookie start");
  if(sendTime(optionsIndex[2]))
  {
    for (int i = 0; i < optionsIndex[3]; i++)
    {
      byte targetIndex = random(0,3);
      LED = 1;
      if(currentTime - sendLED >= interval) //The interval isn't respected
      {
        SendToSlave(LED,targetIndex);
        sendLED = millis();
      }
    }
  }
  displayScreen(0,"END");
} 

void program2(){displayScreen(0,"Program 2");}
void program3(){displayScreen(0,"Program 3");}
void program4(){displayScreen(0,"Program 4");}

bool sendTime(int recTime) //function for sending time
{
  bool done = false;
  unsigned long sendRecTime;
  if(currentTime - sendRecTime>=1000)
  {
    radio.openWritingPipe(wAddress[0]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 1");
  }
  
  if(currentTime - sendRecTime>=2000)
  {
    radio.openWritingPipe(wAddress[1]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 2");
  }
  
  if(currentTime - sendRecTime>=3000)
  {
    radio.openWritingPipe(wAddress[2]);
    radio.write(&recTime, sizeof(recTime));
    Serial.println("Time SL 3");
  }
  done = true;
  radio.startListening();
  return done;
}

void SendToSlave(byte LED,byte adressIndex)
{
  radio.stopListening();
  Serial.print("Sent to slave ");
  Serial.println(adressIndex + 1);
  radio.openWritingPipe(wAddress[adressIndex]);
  radio.write(&LED, sizeof(LED));
  radio.startListening();
}

Slave code:

#include <RF24Network.h>
#include <RF24Network_config.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>

RF24 radio(10, 9); //nRF24L01 pins (CE, CSN)
const uint64_t rAddress = 0xB00B1E50B1LL;
const uint64_t wAddress[1] = {0xB00B1E50D2LL};

int recTime = 0;

bool Hit = false;

byte LED = 0;
byte pipe = 0;

unsigned long currentTime;
unsigned long baseTime = 0;
unsigned long timer1 = 1000;
unsigned long timer2 = 2000;

void setup() 
{
  Serial.begin(57600);
  Serial.println("Listening");
  radio.begin();
  radio.openReadingPipe(1, rAddress);
  radio.startListening();
  pinMode(3, OUTPUT); 
  pinMode(4, OUTPUT); 
  pinMode(5, OUTPUT); 
  pinMode(8, INPUT);
  
}

void loop() 
{
  currentTime = millis();
  radio.startListening(); 
  while (radio.available(&pipe))         
  {
    if(recTime == 0)
    catchTime();

    radio.startListening();
    radio.read(&LED, sizeof(LED));          
    if (LED == 1 && recTime == 1)                             
    {
      recTime_1();
    }
    else if (LED == 1 && recTime == 2)                             
    {
      recTime_2();
    }
  }    
}

void catchTime() 
{
  radio.read(&recTime, sizeof(recTime));
  Serial.print("Time: ");
  Serial.println(recTime); 
}

void recTime_1()
{    
  Serial.println("Light");            
  digitalWrite(3, HIGH);
  if(currentTime - baseTime >= timer1)// Interval isn't respected
  {
    digitalWrite(3, LOW);
    Serial.println("Darkness");
    baseTime = millis(); 
  }
}

void recTime_2()
{   
  Serial.println("Light");            
  digitalWrite(3, HIGH);
  if(currentTime - baseTime >= timer2)
  {
    digitalWrite(3, LOW);
    Serial.println("Darkness");
    baseTime = millis();  
  }
}

void SendToMaster(byte xAddress, byte value)
{
  radio.stopListening();
  radio.openWritingPipe(wAddress[xAddress]);
  radio.write(&value, sizeof(value));
  Serial.print("Wyslano ");
  Serial.println(value);
  radio.startListening();
}

I took your 'slave' code and commented out most of the libraries you include. The sketch still compiled without error or warning so it might be good to reduce:

#include <RF24Network.h>
#include <RF24Network_config.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>

to

#include <RF24.h>

That is unlikely to fix your problem but it does reduce the amount of code you have to search to find the mistake.

You have several problems in the program

1 Your slaves cannot distinguish between messages with time and LED number in any way.

  1. Your recTime() programs only run when something comes on the radio. This makes it completely impossible to respect millis intervals.. If you want them to respect intervals, programs need to be updated every few milliseconds.

  2. You are using the baseTime variable incorrectly.

The logic of work should be like this - when a command comes from the master, the program lights the LED and remembers the time. You should assign baseTime only in this moment - i don't see any like in your code. Further, with each pass of loop(), you must go to the recTime() program, check the interval in it, and when it expires, turn off the LED.

Thank you, it really guided me to the solution of slave problem.
Can you say something more about the master problem? How can I separate this messages?

The usual way to distinguish messages of different types is include additional ID field in it.
You can use the message of 3 bytes - one for ID and two for parameter. The first byte of the message specifies, what is contained next - time or program number.

I don't know if this is what you meant but I tried to separate the messages with struct Data_Package and it makes no change.
I also tried to repair the intervals like in slave. I made it for me in a similar logic but this also doesn't want to work.

Can you give me some other hints?

Master:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <RF24Network.h>
#include <RF24Network_config.h>
#include <SPI.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

String screen[5]={"Begin","Select program","Reaction time","Shoots","Score"};
byte screenIndex = 0;
byte reactIndex[5] = {1,2,5,7,10};

//buttons
const int pinLeft=4;
const int pinRight=5;
const int pinUp=6;
const int pinDown=7;


//Modes
String difficultyLevels[5][5] = {{""},{"Rookie","Plus i minus","Risk","Speed"},{"1","2","5","7","10"},{""},{""}};

//Indexes
byte optionsIndex[5]={0,0,0,0,0};  
byte LED = 0;
byte stop = 0;// new variable
byte sent = 0;// new variable


//Utils
bool screenWasChaned = true;
bool intputWasChaged_Left = false; 
bool intputWasChaged_Right = false;
bool intputWasChaged_Up = false;
bool intputWasChaged_Down = false;

unsigned long currentTime, sendLED, sendRecTime;
unsigned long interval = 5000;


RF24 radio(10, 9);  //nRF24L01 pins (CE, CSN)
const byte wAddresses[3][6] = {"00001","00002","00003"};
const byte rAddresses[3][6] = {"00011","00022","00033"};

struct Data_Package
{
  byte ID;
  byte time;
  byte LED_state;
};

Data_Package data = {0, 0, 0};//create object

void setup() 
{
  Serial.begin(57600);
  Serial.println("Start program");
  radio.begin();
  radio.openReadingPipe(1, rAddresses[0]); //00011
  radio.openReadingPipe(2, rAddresses[1]); //00022
  radio.openReadingPipe(3, rAddresses[2]); //00033
  radio.stopListening();
  pinMode(pinLeft, INPUT);
  pinMode(pinRight, INPUT);
  pinMode(pinDown, INPUT);
  pinMode(pinUp, INPUT);
  digitalWrite(pinLeft, HIGH);
  digitalWrite(pinRight, HIGH);
  digitalWrite(pinDown, HIGH);
  digitalWrite(pinUp, HIGH);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  
}

void loop()
{
  currentTime = millis();
  if(screenWasChaned){
    if (screenIndex==3)
    {
        displayScreen(screenIndex,String(optionsIndex[screenIndex]));
        screenWasChaned = false;
    }
    else{
      displayScreen(screenIndex,difficultyLevels[screenIndex][optionsIndex[screenIndex]]);
      screenWasChaned = false;
      }
    }
  inputControl();
  inputResolve();
  if(data.ID == 1 && sent == 1)    //
  {                                                //
    sendLED = millis();                    //similar to slave logic
    sent  = 0;                                 //
  }                                                //
  if(data.ID == 1)  SendToSlave(); //  
}

void displayScreen(int screenIndex, String value)
{
  lcd.clear();
  lcd.print(screen[screenIndex]);
  lcd.setCursor(0,1);
  lcd.print(value);
}

void inputControl()
{
  int readingLeft=digitalRead(pinLeft);
  int readingRigth=digitalRead(pinRight);
  int readingUp=digitalRead(pinUp);
  int readingDown=digitalRead(pinDown);
  if (readingLeft == LOW)
  {
      if (screenIndex>0 && !intputWasChaged_Left)
      {
        screenIndex = screenIndex-1;
        screenWasChaned = true;
        intputWasChaged_Left = true; //czeka na resolve przyciku aby nie było podwójnych przeskoków przy trzymaniu klawisza;
      }
  }
    if (readingRigth == LOW)
  {
      if (screenIndex < 4 && !intputWasChaged_Right)
      {
        screenIndex = screenIndex+1;
        screenWasChaned = true;
        intputWasChaged_Right = true;
      }
  }
      if (readingUp == LOW)
  {
      if(screenIndex==0 && !intputWasChaged_Up)
      {
        StartProgram(optionsIndex[1]);
        intputWasChaged_Up = true;
      }
      if(screenIndex==3 && optionsIndex[screenIndex]>=0 && !intputWasChaged_Up)// ekran 3, ilość strzałów
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }
      
      if (screenIndex==2 && optionsIndex[screenIndex]<=3 && !intputWasChaged_Up)//ekran 2, blokada inkrementacji do 5 intervałów
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }

      if (screenIndex==1 && optionsIndex[screenIndex]<3 && !intputWasChaged_Up)//ekran 1, blokada inkrementacji do 4 programów
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]+1;
        screenWasChaned = true;
        intputWasChaged_Up = true;
      }
  }
      if (readingDown == LOW)
  {
      if (optionsIndex[screenIndex]>0 && !intputWasChaged_Down)
      {
        optionsIndex[screenIndex] = optionsIndex[screenIndex]-1;
        screenWasChaned = true;
        intputWasChaged_Down = true;
      }
  }
}
void inputResolve()
{
  int readingLeft=digitalRead(pinLeft);
  int readingRigth=digitalRead(pinRight);
  int readingUp=digitalRead(pinUp);
  int readingDown=digitalRead(pinDown);
  
  if (readingLeft == HIGH && intputWasChaged_Left)
  {
    intputWasChaged_Left = false; 
  }
  
  if (readingRigth == HIGH && intputWasChaged_Right)
  {
    intputWasChaged_Right = false;
  }
  
  if (readingUp == HIGH && intputWasChaged_Up)
  {
        intputWasChaged_Up = false;
  }
      
  if (readingDown == HIGH && intputWasChaged_Down)
  {
        intputWasChaged_Down = false;
  }
   delay(50);
}

void StartProgram(int ProgramIndex)
{
  switch (ProgramIndex)
  {
  case 0:
        program1();
    break;
  case 1:
        program2();
    break;

  case 2:
        program3();
    break;

  case 3:
        program4();
    break;

  default:
    break;
  }
}

void program1()
{
  displayScreen(0, "Rookie start");
  data.ID = 0;
  if(data.ID == 0)
  {
    sendTime(reactIndex[optionsIndex[2]]);
  }
  data.ID = 1;
  data.time = 0;
  data.LED_state = 1;
  if(stop ==1)
  displayScreen(0,"END");
} 

void program2(){displayScreen(0,"Program 2");}
void program3(){displayScreen(0,"Program 3");}
void program4(){displayScreen(0,"Program 4");}

void sendTime(byte recTime) 
{
  data.time = recTime;
  data.LED_state = 0;
  radio.openWritingPipe(wAddresses[0]);
  radio.write(&data, sizeof(Data_Package)); // sending struct object
  Serial.print("Time SL 1: ");
  Serial.println(data.time);
  
  radio.openWritingPipe(wAddresses[1]);
  radio.write(&data, sizeof(Data_Package));
  Serial.print("Time SL 2: ");
  Serial.println(data.time);
  
  radio.openWritingPipe(wAddresses[2]);
  radio.write(&data, sizeof(Data_Package)); 
  Serial.print("Time SL 3: ");
  Serial.println(data.time);
  radio.startListening();
}

void SendToSlave()
{
  for (int i = 0; i < optionsIndex[3]; i++)
  {
    if(currentTime - sendLED >= interval) //Still not respected
    {
      byte targetIndex = random(0,3);
      radio.stopListening();
      Serial.print("Wysył do slave-a ");
      Serial.println(targetIndex + 1);
      radio.openWritingPipe(wAddresses[targetIndex]);
      radio.write(&data, sizeof(Data_Package));
      radio.startListening();
      
    }
    sent  = 1;
  }
  data.ID = 0;
  stop = 1;
}

Slave:

#include <RF24Network.h>
#include <RF24Network_config.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>

RF24 radio(10, 9); //nRF24L01 pins (CE, CSN)
const byte rAddress[6] = "00001";
const byte wAddress[6] = "00011";

int SW_420=8;
int ledGreen = 3;
int ledRed = 4;
int ledBlue = 5; 

bool Hit = false; 

byte LED = 0;
byte pipe = 0;
byte recTime = 0;

unsigned long currentTime;
unsigned long baseTime;
unsigned long timer1 = 1000;
unsigned long timer2 = 2000;
unsigned long timer5 = 5000;
unsigned long timer7 = 7000;
unsigned long timer10 = 10000;

struct Data_Package
{
  byte ID;
  byte time;
  byte LED_state;
};

Data_Package data = {0, 0, 0};

void setup() 
{
  Serial.begin(57600);
  Serial.println("Listening");
  radio.begin();
  radio.openReadingPipe(1, rAddress);
  radio.startListening();
  pinMode(ledGreen, OUTPUT); //LED green
  pinMode(ledRed, OUTPUT); //LED red
  pinMode(ledBlue, OUTPUT); //LED blue
  pinMode(SW_420, INPUT); //SW-420
  
}

void loop() 
{
  currentTime = millis();
  radio.startListening(); 
  while (radio.available(&pipe))           
  {
    if(recTime == 0)
    catchTime(); 
  
  radio.startListening();
  radio.read(&data, sizeof(Data_Package));
  Serial.print("LED: ");
  Serial.println(data.LED_state);
  LED = data.LED_state;
  }          
  if (LED == 1 && (recTime == 1 || recTime == 2 || recTime == 5 || recTime == 7 || recTime == 10))                             
  {
    Serial.println("Light");            
    digitalWrite(ledGreen, HIGH);
    baseTime = millis();
    LED = 0;
  }
  
 if(recTime==1) recTime_1();
 if(recTime==2) recTime_2();
 if(recTime==5) recTime_5();
 if(recTime==7) recTime_7();
 if(recTime==10) recTime_10();   
}

void catchTime()
{
  radio.read(&data, sizeof(Data_Package)); 
  Serial.print("Time: ");
  Serial.println(data.time);
  recTime = data.time; 
}

void recTime_1()
{    
  Hit=digitalRead(SW_420);
  if((currentTime - baseTime >= timer1 || currentTime - baseTime >= timer2 || currentTime - baseTime >= timer5 || currentTime - baseTime >= timer7 || currentTime - baseTime >= timer10) && !Hit)//Intervals are respected
  {
    digitalWrite(ledGreen, LOW);
  }
  
  if(Hit)
  {
    digitalWrite(ledGreen, LOW);
    Serial.println("Mrok"); 
  }
}

void recTime_2()
{
  Hit=digitalRead(SW_420);
  if(currentTime - baseTime >= timer2 && !Hit)
  {
    digitalWrite(ledGreen, LOW);
  }

  if(Hit)
  {
    digitalWrite(ledGreen, LOW);
    Serial.println("Mrok"); 
  }
}

void recTime_5()
{
  Hit=digitalRead(SW_420);
  if(currentTime - baseTime >= timer5 && !Hit)
  {
    digitalWrite(ledGreen, LOW);
  }

  if(Hit)
  {
    digitalWrite(ledGreen, LOW);
    Serial.println("Mrok"); 
  }
}

void recTime_7()
{
  Hit=digitalRead(SW_420);
  if(currentTime - baseTime >= timer7 && !Hit)
  {
    digitalWrite(ledGreen, LOW);
  }

  if(Hit)
  {
    digitalWrite(ledGreen, LOW);
    Serial.println("Mrok"); 
  }
}

void recTime_10()
{
  Hit=digitalRead(SW_420);
  if(currentTime - baseTime >= timer10 && !Hit)
  {
    digitalWrite(ledGreen, LOW);
  }

  if(Hit)
  {
    digitalWrite(ledGreen, LOW);
    Serial.println("Mrok"); 
  }
}

void SendToMaster(byte xAddress, byte value)
{
  radio.stopListening();
  radio.openWritingPipe(wAddress);
  radio.write(&value, sizeof(value));
  Serial.print("Sent ");
  Serial.println(value);
  radio.startListening();
}