Per quanto riguarda il richiamo di 'updateRL2_state' ovviamente andrebbe sia dentro che fuori dal while, ma è evidente che volendo realizzare diverse cose che avanzano con tempi indipendenti bisognerebbe richiamare tutte le altre dentro i cicli di ciascuna, per cui non è una buona idea.
Anche con il for sarebbe la stessa cosa. Il problema non è il tipo di ciclo ma la struttura dell'esecuzione.
Mi sembra che hai cercato di curare un certo ordine, pur con alcuni "peccati" del principiante (ad esempio tutte le variabili, a parte quelle per i tempi, possono essere byte e non int, dimezzando l'uso della memoria).
Quelle che hai chiamato "Variabili che non cambiano" sono in realtà variabili globali, che permangono durante tutta l'esecuzione (differenza delle variabili locali delle funzioni che svaniscono al termine delle funzioni stesse), ma non è che i valori non possono cambiare.
La funzione 'updateRL2_state', a parte il fatto che potrebbe essere ridotta, è strutturata correttamente come un piccolo processo da richiamare continuamente, e che non si prende mai tutto il tempo macchina con delay o cicli bloccanti. Anche tutto il resto dovrebbe essere pensato nello stesso modo: programmazione a stati, ricordando che il concetto fondamentale è che "ogni ritardo o attesa è creato permanendo in un certo stato per un certo numero di cicli".
Questo è un esempio di come potrebbe essere ristrutturato il tuo codice. Nota che nelle funzioni non compaiono mai i numeri dei pin, o i livelli HIGH o LOW, questi sono tutti definiti con le etichette/nomi di comodo all'inizio in modo da non confondersi nel resto del programma (per convenzione tutti questi nomi si scrivono in maiuscolo per distinguerli dalle variabili). Ci sono solo tre "trucchetti" un po' avanzati, uno in ogni funzione. La funzione 'updateRL1_process' prende il posto del ciclo while, ed è la variabile di stato 's' a stabilire quale parte deve essere eseguita ad ogni giro di loop. Inoltre ogni funzione ha le sue variabili static, che permangono come quelle globali pur essendo locali (e quindi si possono usare nomi semplici senza prefissi/suffissi). Le uniche globali rimaste sono 'onPress' (che viene impostata a true nel momento in cui il pulsante viene premuto) e 'currentMillis' che all'inizio di ogni ciclo viene caricata con il tempo attuale e serve a tutte le altre funzioni. In questo programma ogni funzione è una "micromacchina" indipendente, con le proprie variabili di lavoro interne, che comunica con le altre tramite poche variabili globali indispensabili. Il loop è un semplice "scheduler" che attiva ciclicamente migliaia di volte al secondo ogni "macchina".
//----------------Collegamento pulsante
#define BUTTON_PIN 4
#define PRESS_LEVEL HIGH //livello pulsante premuto
#define DEBTIME 50
//-----------------Collegamento Rele'
#define RL1_PIN 12
#define RL2_PIN 11
#define RL_OFF HIGH //livello rele' spento
#define RL_ON LOW //livello rele' acceso
//----------------Tempi di lampeggio
#define RL1_BLINK 500
#define RL2_BLINK 1000
//----------------Variabili globali
bool onPress; //true per un ciclo quando viene premuto puls.
unsigned long currentMillis; //tempo attuale aggiornato ad ogni ciclo
//--------------------------------------------------------------------
void setup()
{
pinMode(BUTTON_PIN, INPUT);
pinMode(RL1_PIN, OUTPUT);
pinMode(RL2_PIN, OUTPUT);
digitalWrite(RL1_PIN, RL_OFF); //rele' spenti
digitalWrite(RL2_PIN, RL_OFF);
}
//--------------------------------------------------------------------
void loop()
{
currentMillis = millis();
readPuls();
updateRL1_process();
updateRL2_state();
}
//--------------------------------------------------------------------
void readPuls()
{
static byte prior_in = digitalRead(BUTTON_PIN);
static unsigned long t = currentMillis;
byte in = digitalRead(BUTTON_PIN);
onPress = false;
if (in == prior_in)
t = currentMillis;
else if (currentMillis - t >= DEBTIME)
{
prior_in = in;
onPress = in == PRESS_LEVEL;
}
}
//--------------------------------------------------------------------
void updateRL1_process()
{
static byte s = 0;
static byte cntr = 10;
static unsigned long t;
switch (s)
{
case 0:
if (onPress)
{
digitalWrite(RL1_PIN, RL_ON);
t = currentMillis;
s = 1;
}
break;
case 1:
if (currentMillis - t >= RL1_BLINK)
{
digitalWrite(RL1_PIN, RL_OFF);
t += RL1_BLINK;
s = 2;
}
break;
case 2:
if (currentMillis - t >= RL1_BLINK)
{
digitalWrite(RL1_PIN, RL_ON);
if (cntr-- > 0)
{
t += RL1_BLINK;
s = 1;
}
else
s = 3;
}
}
}
//--------------------------------------------------------------------
void updateRL2_state()
{
static byte rl_state = RL_OFF;
static unsigned long t = currentMillis;
if (currentMillis - t >= RL2_BLINK)
{
t += RL2_BLINK;
digitalWrite(RL2_PIN, rl_state = !rl_state);
}
}
//--------------------------------------------------------------------