Ciao!
Nel codice a cui sto lavorando sto facendo uso della struttura switch case per gestire una macchina a stati.
Il problema che mi si presenta è il seguente: uno stato fa delle cose, aggiorna lo stato successivo e ... non funziona nulla.
Quello che non funziona è il fatto che il microcontrollore pare non riesca a entrare nello stato successivo.
Posto le parti salienti del codice: qui definisco con dei nomi gli stati della macchina a stati e imposto lo stato iniziale.
// Definizioni per macchina a stati
#define INIZIALIZZAZIONE 0
#define LETTURA_ANTENNA 1
#define LETTURA_SENSORE 2
#define SCRITTURA 3
#define LOWPOWER 4
#define AZIONI 5
#define SHUTDOWN 6
int stato = INIZIALIZZAZIONE;
Qui metto i due stati che mi danno il problema (sono dentro al loop):
case AZIONI:
setSyncProvider(RTC.get);
int adesso = second();
if(adesso < tempo){
tempo = adesso + 60;
} else {
tempo = adesso;
}
Serial.print("tempo-prev ");
Serial.println(tempo-prev);
if(tempo-prev < 15){
displayorario();
tempo_risveglio = adesso;
Serial.print("tempo_risveglio ");
Serial.println(tempo_risveglio);
if(tempo_risveglio >= 55){
tempo_risveglio = tempo_risveglio - 55;
} else {
tempo_risveglio = tempo_risveglio + 5;
}
Serial.print("tempo_risveglio dopo incremento ");
Serial.println(tempo_risveglio);
stato = SHUTDOWN;
} else {
digitalWrite(SETPIN, LOW);
delay(40);
HC12.write("AT");
delay(50);
digitalWrite(SETPIN, HIGH);
while(HC12.available()) byte pulizia = HC12.read();
delay(200);
stato = LETTURA_ANTENNA;
}
break;
case SHUTDOWN:
RTC.setAlarm(ALM1_MATCH_SECONDS, tempo_risveglio, 0, 0, 0);
RTC.alarm(ALARM_1);
RTC.squareWave(SQWAVE_NONE);
RTC.alarmInterrupt(ALARM_1, true);
Serial.println("DORMO");
system_sleep();
Serial.println("SVEGLIO");
RTC.alarm(ALARM_1);
RTC.alarmInterrupt(ALARM_1, false);
stato = AZIONI;
break;
Faccio un esempio: nello stato AZIONI (stato=5) è verificato che tempo-prev<15 allora entra nell'if (e infatti lo ho verificato con delle print) poi sempre con delle print vedo il valore della variabile tempo_risveglio (e me lo mostra, anche dopo l'incremento), poi assegno a stato SHUTDOWN (stato=6).
Ora mi aspetterei che il sistema entri in SHUTDOWN (ho messo una print subito dopo al loop(), ma quello che vedo è un continuo mostrare stato=6 quando invece in SHUTDOWN dovrebbe addormentarsi arduino e poi tornare allo stato AZIONI... Invece le print che ho messo in SHUTDOWN non vengono mai mostrate e rimane così bloccato in stato=6 senza tuttavia entrarci!
Ho provato anche a dargli un numero diverso, ma il problema persiste.
Per curiosità prova a cambiare nome a SHUTDOWN, alle volte ci sono conflitti con nomi predefiniti o usati altrove nelle librerie.
Io uso una K_ davanti alle mie define costanti
K_AZIONI, K_SHUTDOWN, etc.
Tra l'altro le buone regole di programmazione consigliano di scrivere sempre in inglese, ma questo invece è un caso in cui scrivere i nomi in italiano aiuta a non incorrere in "errori occulti" (sempre che il problema sia quello).
Ok, ho fatto le seguenti prove:
- ho modificato il nome di SHUTDOWN in SPEGNIMENTO, ma nulla è cambiato
- ho messo una K_ davanti a tutti gli stati, ma il risultato è lo stesso
- ho provato a scambiare il numero dello stato K_SPEGNIMENTO (ex SHUTDOWN, stato=6) con quello di K_AZIONI (ex AZIONI, stato=5) ma ora si blocca nello stato=5 (sempre prima di entrare in K_SPEGNIMENTO)!!!!
Inoltre ho messo delle nuove print per essere assolutamente sicuro che esca dal break precedente e NON entri nel case successivo.
Detto questo, sono un pò a corto di idee!
PS.: tempo fa, quanto il numero di stati era limitato a 5 (quindi andava da 0 a 4) ebbi l'idea per risparmiare memoria di usare la variabile byte per salvare gli stati. Supponevo che quindi io potessi memorizzare 8 stati in tutto (da 0 a 7) ma quando aggiunsi un sesto stato, ecco che il codice non ci entrava più! Quindi mi accorsi che con la variabile int invece tutto funzionava bene.
Edit: ho fatto al volo una prova con una struttura switch case ripulita da tutto (ho tolto tutte le istruzioni aggiuntive), semplicemente va da uno stato all'altro con un ritardo di 1 secondo. Funziona tutto.
Una cosa che non ho detto è che il codice (quello completo) gira su un Arduino Nano e usa il 74% dello spazio disponibile per i programmi. Non so se centri qualcosa..
Tutto il contenuto del case incriminato, tra 'case' e 'break' prova a racchiuderlo tra graffe, questo crea un diverso contesto di visibilità locale delle variabili.
Se quello che ipotizzo è vero il problema è la dichiarazione interna al case: int adesso = second();
il numero di stati era limitato a 5 (quindi andava da 0 a 4) ebbi l'idea per risparmiare memoria di usare la variabile byte per salvare gli stati.
Infatti la variabile byte va benissimo fino a 255, c'è un problema di livello inferiore alla logica del programma.
Ho fatto così (mi perdonerete se ho tolto K_):
case AZIONI: {
..
..
ISTRUZIONI VARIE
..
..
}break;
e stessa cosa la ho fatta in SPEGNIMENTO.
Ora infatti entra!
Putroppo non credo di aver ben capito questa tua frase
Se quello che ipotizzo è vero il problema è la dichiarazione interna al case: int adesso = second();
e temo di non aver compreso l'errore che sto commettendo.
electronics_project:
temo di non aver compreso l'errore che sto commettendo.
Nessun errore di logica, ma di implementazione sottostante del funzionamento dello switch: c++ - Why can't variables be declared in a switch statement? - Stack Overflow
In effetti hai ragione, mi è bastato dichiare la variabile in modo globale e tutto si è risolto, grazie!
Inoltre la variabile stato ho provato a dichiararla di nuovo byte e funziona (si vede che anche in passato avevo sbagliato qualche cosa).