Reset_AVR(); sembra scattare arbitrariamente ma comunque non fa il reset

Buonasera a tutti,

d’accordo che sono niubbio sia di C/C++ che di Arduino, ma questa proprio non la capisco.

E’ ancora lo schetch dell’orologio tuttofare di qualche giorno fa, nel tempo libero continuo la cura dimagrante per la prova costume dell’ATtiny85 e oggi ho cercato di fare un reset via software invece di azzerare una per una tutte le singole variabili.

Ho trovato il reset tramite WhatchDog, fighissimo.
L’ho implementato, provato (SOLO QUELLO :frowning: ) e sono andato avanti, ma a distanza di ore quando dopo altri interventi ho usato i pulsanti per impostare la data all’uscita del “setting” si blocca(va) tutto.

Segue uno spezzone del codice coinvolto con un minimo di commenti per capirrne il senso.
La parte incriminata è la #define all’inizio insieme alle tre righe marcate con *****

...
// --- Thanks https://forum.arduino.cc/index.php?topic=35155.msg256412#msg256412
#include <avr/io.h>
#include <avr/wdt.h>
#define Reset_AVR() wdt_enable(WDTO_30MS); while(1) {} 

...

// --- Questa si occupa di mostrare e far impostare i sotto-elementi del menu principale
// --- ad esempio anno, mese, giorno quando si setta la data
// --- Nella prima parte (MenuPos) uso/avanzo gli elementi corrispondenti alla funzione
// --- nella seconda
// --- I "Conta" nei commenti fanno riferimento a un array che tiene il valore e lo gestisce entro minimi e massimi
// --- Finiti gli elementi, o se ce n'è solo uno, "Elemento" va a -1 e si attiva la parte successiva
void NextElemento()
	{
	// --- Prima parte, scorro gli elementi
	if ( MenuPos == 1 ) // --- Setting DATA
		Elemento = Elemento < 2 ? Elemento+1 : -1 ; // --- Conta Elementi 0/1/2 (aaaa/mm/gg) e poi torna a -1
	...

	if ( MenuPos == 10 ) // --- Full Reset
		Elemento = -1 ; // --- Conta solo Elemento 20 - Si/No e va subito a -1

	// ---- Seconda parte, conferma e scrittura
	if ( Elemento == -1 ) // --- Se ho modificato tutto scrivo le modifiche ed esco dal SETTING
		{
		if ( MenuPos == 1 ) // --- Set DATA
		...
		if ( MenuPos == 10 ) // --- Conferma il Reset	//	*****
			if ( D2Set[20] == 1 )			//	*****
				Reset_AVR();			//	*****
		...
		}
	}

Dov’è il problema.
Teoricamente mi aspetto che Reset_AVR(); scatti solo se ho scelto l’opzione 10 del menu e se D2Set[20] ha valore 1.
Invece anche se ho modificato una qualsiasi voce di MenuPos (tutte: dalla 1 alla 10 compresa) sia che per la 10 (Reset/D2Set[20]) abbia lasciato/scelto “No” (quindi 0) l’Arduino UNO si blocca come se venisse eseguita while(1) {}

Se commento le tre righe ***** o se invece di Reset_AVR(); invoco direttamente wdt_enable(WDTO_30MS); tutto funziona regolarmente.

Non mi spiego proprio la cosa; lasciare la sola wdt_enable(WDTO_30MS); mi sta benissimo, ma spero in un vostro aiuto almeno per capire.

Lo schetch, anche scevro dai commenti, è abbondantemente oltre i 9k accettati dal forum; se necessario non ho riserve ad allegarlo.

Grazie fin d’ora.

e... se elimini solo il while?

Siamo sicuri che puoi mettere dei spazi davanti al while nel #define?

Ciao Uwe

Metti le graffe ai tuoi if o cambia la #define in maniera opportuna, vedi:

Buongiorno,

in effetti ho copiato pedissequamente dal topic linkato nel codice ( https://forum.arduino.cc/index.php?topic=35155.msg256412#msg256412 ) e mi è sembrato strano che il while() non fosse in qualche modo racchiuso “all’interno” della funzione.
Provo a giocarci di nuovo più tardi.
Grazie SukkoPera per il link su github, ad una prima occhiata veloce è molto interessante.

È solo una riga da sostituire alla tua... Il resto non c'entra niente.

SukkoPera:
È solo una riga da sostituire alla tua... Il resto non c'entra niente.

No, ma è comunque moooolto istruttivo, anche se parecchio "avanti" rispetto alle mie conoscenze :slight_smile:

Vi chiedo un chiarimento su questa #define (che sto usando, grazie!)

#define softReset() do {wdt_enable (WDTO_30MS); while(1) {}} while (0)

Mi è chiaro il while(1) interno (blocca in un ciclo infinito finché non scatta il Whatchdog), ma perché racchiuso nel do {...} while (0) esterno visto che se lo tolgo mi sembra che tutto funzioni regolarmente?

#define softReset() {wdt_enable (WDTO_30MS); while(1) {}}

Funziona perché lasci le graffe. Quel do{}while(0) è un costrutto particolare per far sì che quella macro possa apparire ovunque come se fosse una normale istruzione ed evitare cose come quella che è successa a te. Probabilmente è un po' "esagerato" in questo contesto ma fa quel che deve.

SukkoPera:
Funziona perché lasci le graffe. Quel do{}while(0) è un costrutto particolare per far sì che quella macro possa apparire ovunque come se fosse una normale istruzione ed evitare cose come quella che è successa a te. Probabilmente è un po' "esagerato" in questo contesto ma fa quel che deve.

In effetti mi sembrava strano che non ci fossero le graffe nel primo codice che usavo; nel pomeriggio provo, ma a logica direi che ci sarebbero dovute essere pure li, giusto?

A me però succedeva una cosa ben più strana: freezava tutto non solo quando sceglievo di fare il reset, ma anche quando confermavo da altre voci di menu, cioè quando la if ( MenuPos == 10 ) NON avrebbe dovuto consentire le due istruzioni successive.

Se non dico una castroneria troppo grossa (che però ci sta nella sequenzialità senza graffe che racchiudono) è come se le tre righe che riporto qui venissero:
1.- la prima valutata e deciso di non eseguire la successiva
2.- la seconda valutata (percorsa?) comunque anche se non eseguita
3.- la terza idem, valutata e non eseguita
E poi a ruota la chiamata a Reset_AVR(); faceva "percorrerre" anche wdt_enable(WDTO_30MS); ma la sequenzialità di istruzioni non eseguite per la 1.- si interrompeva e il successivo while (1) {} bloccava il tutto.

if ( MenuPos == 10 ) // --- Conferma il Reset // *****
 if ( D2Set[20] == 1 ) // *****
 Reset_AVR(); // *****

Non mi torna dalla parte in rosso in poi.
Se ho ragionato bene fin li, la sequenzialità degli if() senza le graffe dovrebbe interrompersi e proseguire alla riga successiva alla 3.-
Perché verrebbe "percorsa" anche la riga nel #define?

La tua #define contiene due istruzioni. Se non metti le graffe all'if, questo condiziona solo la singola istruzione immediatamente successiva. Il while rimane lì, fuori da tutto e non condizionato a niente, per cui viene sempre eseguito.

Se metti le graffe o usi il mio costrutto, di fatto il #define conta come un'istruzione sola.

Oppure fai una bella function void e ti togli il pensiero :slight_smile:

void Reset_AVR() { wdt_enable(WDTO_30MS); while(1); }

nid69ita:
Oppure fai una bella function void e ti togli il pensiero :slight_smile:

void Reset_AVR() { wdt_enable(WDTO_30MS); while(1); }

E così è andata a finire! :slight_smile:
Visto che avevo trovato il WDT usato quasi ovunque in quel modo, avevo pensato fosse necessario strutturare la cosa con #define invece ho imparato 2 cose: il WDT e il #define :smiley: :smiley: :smiley:

Senza contare la bella ripassata (sui ceci! Ahi!) che "l'istruzione successiva" non sempre coincide con la riga successiva dell'editor :frowning: