Funzione attachInterrupt bloccante.

Buona giornata a tutti,
sono allla mia seconda realizzazione di un listato Arduino e mi sono imbattuto in una situazione che non riesco a risolvere.
Avrei bisogno di creare un menu utente per la gestione dei parametri.
Se, per spostarmi nel menu, uso la lettura degli ingressi dei pulsanti tutto funziona regolarmente.
Il problema è che la lettura non puo essere costantemente controllata, il programma prevede diversi compiti (alcuni particolarmente sensibili), quindi gli spostamenti non sono "fluidi".
Ho provato con la funzione attachInterrupt, ma il programma si blocca. Dove sbaglio? o che soluzione adottare?
Grazie

#include <EEPROM.h>

// menu

char* nomeMenu [26]={
 //0123456789012345678901234567890123456789
  " 00-Uscita                              ",
  " 01-Setpoint zona0           ",
  " 02-Setpoint zona1           ",
  " 03-Setpoint zona2           ",
  " 04-Setpoint zona3           ",
  " 05-Setpoint zona4           ",
  " 06-Incremento pwm zona0     ",
  " 07-Incremento pwm zona1     ",
  " 08-Incremento pwm zona2     ",
  " 09-Incremento pwm zona3     ",
  " 10-Incremento pwm zona4     ",
  " 11-Valore minimo pwm        ",
  " 12-Dt puffer                ",
  " 13-Dt caldaia               ",
  " 14-Dt zone                  ",
  " 15-Dt spillamento           ",
  " 16-Dt start curva           ",  
  " 17-Temp. esterna stop       ",
  " 18-Temp. max impianto       ",
  " 19-Temp. min impianto       ",
  " 20-Incr. dt externo         ",
  " 21-Incr. dt interno         ",
  " 22-Tempo apertura spill     ",
  " 23-Tempo chiusura spill     ",
  " 24-Tempo pausa spill        ",
  " 25-Sonda riferimento        ",
};

volatile byte valMenu[26][5] = { //old, new, min, max, Eeprom
{},
{200, 200, 0, 255, 0}, // Setpoint zona0
{200, 200, 0, 255, 1}, // Setpoint zona1
{200, 200, 0, 255, 2}, // Setpoint zona2
{200, 200, 0, 255, 3}, // Setpoint zona3
{200, 200, 0, 255, 4}, // Setpoint zona4
{14, 14, 0, 100, 10},  // Incremento pwm zona0
{14, 14, 0, 100, 11},  // Incremento pwm zona1
{14, 14, 0, 100, 12},  // Incremento pwm zona2
{14, 14, 0, 100, 13},  // Incremento pwm zona3
{14, 14, 0, 100, 14},  // Incremento pwm zona4
{30, 30, 0, 100, 19},  // Valore minimo pwm
{2, 2, 1, 30, 20},     // Dt puffer
{5, 5, 1, 30, 21},     // Dt caldaia
{2, 2, 1, 10, 22},     // Dt zone
{5, 5, 1, 30, 23},     // Dt spillamento
{2, 2, 0, 30, 24},     // Dt start curva
{24, 24, 10, 30, 25},  // Temp. esterna stop
{45, 45, 1, 95, 26},   // Temp. massima impianto
{22, 22, 1, 95, 27},   // Temp. minima impianto
{7, 7, 1, 50, 30},     // Incremento dt externo
{25, 25, 1, 50, 31},   // Incremento dt interno
{7, 7, 1, 30, 32},     // Tempo apertura spill
{10, 10, 1, 30, 33},   // Tempo chiusura spill
{20, 20, 10, 50, 34},  // Tempo pausa spill
{0, 0, 0, 4, 35}};      // Sonda riferimento

volatile int statoMenu =0;    // 0=spento, 1=attivo, 2=modifica
volatile int posMenu = 0;     // riga del menu attiva
  byte inOk = 2;
  byte inUp = 3;
  byte inDn = 4;


void setup(){
  Serial.begin(9600);
  attachInterrupt(0, pulOk, FALLING); // su pressione pulsante ok pin 2
  attachInterrupt(1, pulUp , FALLING); // su pressione pulsante up pin 3
//  attachInterrupt(2, pulDn , FALLING); // su pressione pulsante dn pin 3
  pinMode(inOk,INPUT);
  pinMode(inUp,INPUT);
  pinMode(inDn,INPUT);
  digitalWrite(inOk,HIGH);  //abilito le resistenze interne di pull up
  digitalWrite(inUp,HIGH);
  digitalWrite(inDn,HIGH);
  
  
  for (int i = 1; i < 26; i++){       // carico i dati Eeprom sul menu
  valMenu[i][0] = EEPROM.read(int(valMenu[i][4]));
  valMenu[i][1] = valMenu[i][0];}

}


//***************************************************************************************************
void loop(){
/*  
if (millis() - pausaTasti > 300){ // intervallo minimo per la ripetizione dei tasti
    if (digitalRead(inOk)==LOW) pulOk();  // verifico se è stato premuto un tasto
    if (digitalRead(inUp)==LOW) upDn(1);
    if (digitalRead(inDn)==LOW) upDn(-1);  
    pausaTasti = millis();}
*/    

}

//***************************************************************************************************
void pulOk(){  // è stato premuto il tasto ok

  switch (statoMenu){
    
      case 0:  // il menu non è attivo, lo attivo sulla prima riga
      statoMenu = 1;
      posMenu = 1;
      aggiornaMenu();
      break;
      
    case 1:  // il menu è attivo
      if (posMenu > 0){  // il menu non è sulla riga uscita, abilito la modifica
      statoMenu = 2;
      Serial.println("modifica abilitata");}
      else {  // il menu è sulla riga di uscita, salvo i dati ed esco
        for (int i = 1; i < 26; i++){
          if (valMenu[i][0] != valMenu[i][1]){
          valMenu[i][0] = valMenu[i][1];}
          EEPROM.write(int(valMenu[i][4]),valMenu[i][0]);
}
        statoMenu = 0;
        Serial.println("uscito da menu, aggionamenti salvati.");}
      break;   
    case 2:  // il menu è in modalità modifica, la disabilito
      statoMenu = 1;
      Serial.println("modifica disabilitata");
      break;
}

//***************************************************************************************************
}

void upDn(int incr){  // è stato premuto il tasto Up
//Serial.print("Up stato: ");
//Serial.println(statoMenu);
  switch (statoMenu){
    
    case 0:    // il menu non è attivo, esco
    break;
    
    case 1:    // il menu è attivo, scorro di posizione
    posMenu = posMenu + incr;
    if (posMenu > 25)  posMenu = 0;
    if (posMenu < 0)  posMenu = 25;
    aggiornaMenu();
    break;
    
    case 2:   // il menu è in modifica, incremento valori //0=old, 1=new, 2=min, 3=max, 4=Eeprom
    if (valMenu[posMenu][1]==valMenu[posMenu][3] && incr == 1){
      valMenu[posMenu][1] = valMenu[posMenu][2];}
      else if (valMenu[posMenu][1]==valMenu[posMenu][2] && incr == -1){
        valMenu[posMenu][1] = valMenu[posMenu][3];}
        else {
          valMenu[posMenu][1] = valMenu[posMenu][1] + incr;}
    aggiornaMenu();
    break;
  }
}

//***************************************************************************************************
void aggiornaMenu(){  // aggiorno lo stato del menu

  String strMenu = nomeMenu[posMenu];
  
  if (posMenu == 0){
  Serial.println(strMenu);}
  
    else {
    String strOld = String(valMenu[posMenu][0]);
    if (strOld.length() == 1) strOld = "  " + strOld;
    if (strOld.length() == 2) strOld = " " + strOld;  
    String strNew = String(valMenu[posMenu][1]);
    if (strNew.length() == 1) strNew = "  " + strNew;
    if (strNew.length() == 2) strNew = " " + strNew;  
    Serial.println( strMenu + "(" + strOld + ") > " + strNew);}
}

//***************************************************************************************************

void pulUp(){  // test interrupt
  upDn(1);
}

//***************************************************************************************************

void pulDn(){  // test interrupt
  upDn(-1);
}

Naturale che si blocchi: dentro all'interrupt ci hai messo un richiamo ad una funzione che ne richiama un'altra con dentro la creazione di oggetti String e stampe su seriale.
Nelle routine dell'interrupt devi mettere solo l'incremento o il decremento dell'indice.
Sarà nel loop che ciclicamente controlli il menu da visualizzare e le varie operazioni per visualizzarlo.

PaoloP:
Nelle routine dell'interrupt devi mettere solo l'incremento o il decremento dell'indice.
Sarà nel loop che ciclicamente controlli il menu da visualizzare e le varie operazioni per visualizzarlo.

... che si può anche riassumere in : "nelle ISR devi tassativamente fare il minimo indispensabile" XD

Guglielmo

Capisco e ringrazio.
Buon proseguo

Per la gestione dei menu e dei parametri c'è la libreria MENWIZ a cui ho dato uno sguardo al codice di recente, e devo dire che è molto flessibile e solo in rarissimi casi si deve fare ricorso ad una gestione dei menu dedicata.
Con la MENWIZ puoi decidere il tipo di parametro e il range ammesso e il numero di incrementi per ogni pressione del pulsante. Un parametro può essere di tipo lista, Bool ecc.

Ciao.