Go Down

Topic: istruzione che viene eseguita una sola volta (Read 10392 times) previous topic - next topic

Ulixxes

Buongiorno a tutti,

ho un problema simile......

devo fare eseguire del codice SOLAMENTE all'accensione di Arduino e mai più anche se richiamo
un soft_restart();

Ma va bene anche se venisse rieseguito con la pressione del pulsante di reset della scheda
ma NON QUANDO ESEGUO UN RESET SOFTWERE.

Grazie
Ciao,
alcuni micro permettono di detectarlo scrivendo un valore su un registro. Non so se è il caso dell'AVR.
Un metodo per farlo (senza dover scartabellare il datasheet del micro) potrebbe essere scrivere un valore particolare in EEPROM quando fai il SW reset e poi leggerlo all'avvio per capire se devi eseguire o meno il codice

gpb01

#16
Oct 23, 2015, 02:21 pm Last Edit: Oct 23, 2015, 02:21 pm by gpb01
C'è un registro che ti permette di risalire alla causa dell'ultimo reset. Ora non ricordo quale sia, ma dovresti poterlo leggere e comportarti di conseguenza (Sempre che sia lasciato intatto dal bootloader...). Dai un'occhiata al datasheet.
Esatto ...
... le informazioni si trovano nel registro MCUSR (bit 0..3) documentato a pag. 54 del datasheet (10/2014).

Purtroppo NON sono sicuro che il registro non venga alterato dal "core" di Arduino (... rammento che setup() e loop() vengono chiamate DOPO tutta un'altra serie di funzioni del "core" all'avvio del programma).

Guglielmo
Search is Your friend ... or I am Your enemy !

SukkoPera

#17
Oct 23, 2015, 02:41 pm Last Edit: Oct 23, 2015, 02:46 pm by SukkoPera
Purtroppo il registro è sicuramente "sporcato" già dal bootloader. Tuttavia, ho trovato qualcosa di interessante: se usi un Arduino con Optiboot (il che credo succeda nel 99% dei casi), c'è uno sketch di esempio che fa proprio quel che ti serve:

https://github.com/Optiboot/optiboot/blob/master/optiboot/examples/test_reset/test_reset.ino
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

gpb01

#18
Oct 23, 2015, 02:58 pm Last Edit: Oct 23, 2015, 03:00 pm by gpb01
@SukkoPera

Anche io ho provato una tecnica simile e ci sono esempi forniti da Atmel stessa ma ...
... c'è un problemino, almeno sino al rilascio del IDE 1.6.6 che, con il nuovo "builder", dovrebbe comportarsi correttamente. L'IDE dichiara COMUNQUE lui i "prototipi" di qualsiasi funzione (ANCHE se già li hai dichiarati) e, a seconda di come lo fa, può vanificare i vari "__attribute__ ((section(".noinit")));" e così via ... :(

Guglielmo

P.S. : Ovviamente la cosa funziona se usi Atmel Studio ed hai tu il controllo del tuo sorgente ;)
Search is Your friend ... or I am Your enemy !

gpb01

... per inciso, il metodo suggerito da Atmel è :


Code: [Select]
uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
...
...
void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
...
...
void get_mcusr(void)
{
   mcusr_mirror = MCUSR;
   MCUSR = 0;
   wdt_disable();
}


... e ti trovi in mcusr_mirror il valore del registro MCUSR.

Guglielmo
Search is Your friend ... or I am Your enemy !

SukkoPera

#20
Oct 23, 2015, 03:16 pm Last Edit: Oct 23, 2015, 03:30 pm by SukkoPera
@SukkoPera

Anche io ho provato una tecnica simile e ci sono esempi forniti da Atmel stessa ma ...
... c'è un problemino, almeno sino al rilascio del IDE 1.6.6 che, con il nuovo "builder", dovrebbe comportarsi correttamente. L'IDE dichiara COMUNQUE lui i "prototipi" di qualsiasi funzione (ANCHE se già li hai dichiarati) e, a seconda di come lo fa, può vanificare i vari "__attribute__ ((section(".noinit")));" e così via ... :(

Guglielmo

P.S. : Ovviamente la cosa funziona se usi Atmel Studio ed hai tu il controllo del tuo sorgente ;)
Sì, capisco, ma il fatto che l'esempio che ho linkato sia stato espressamente scritto per Arduino (come desumibile dall'estensione .ino) mi fa ben sperare. Al momento non ho modo di provarlo, ma magari stasera... ::)
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

gpb01

#21
Oct 23, 2015, 03:57 pm Last Edit: Oct 23, 2015, 03:57 pm by gpb01
Sì, capisco, ma il fatto che l'esempio che ho linkato sia stato espressamente scritto per Arduino (come desumibile dall'estensione .ino) mi fa ben sperare. Al momento non ho modo di provarlo, ma magari stasera... ::)
Non dubito che magari vada ...
... i problema è se la tecnica è SEMPRE utilizzabile o meno ... ::)

Per avere una cosa affidabile occorre attendere la 1.6.6 (... dove i prototipi dichiarati NON dovrebbero venir nuovamente dichiarati dall'IDE) ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

pilotinocarter

salve,

grazie per le risposte...
sono comunque ancora un po' nebulose per me,

ma da questo:

/*
   * test_reset
   * May 2015 by Bill Westfield (WestfW)
   * Released to the public domain.
   *
   * This sketch demonstrates retrival of the Reset Cause register (MCUSR) of the AVR.
   * Normally, MCUSR itself is destroyed by the use of a bootloader, but Optiboot v4.6
   * and later save the contents in register r2, where it can be accessed by an
   * application.
   */
   #include <avr/wdt.h>
   
   /*
   * First, we need a variable to hold the reset cause that can be written before
   * early sketch initialization (that might change r2), and won't be reset by the
   * various initialization code.
   * avr-gcc provides for this via the ".noinit" section.
   */
   uint8_t resetFlags __attribute__ ((section(".noinit")));
   
   /*
   * Next, we need to put some code to save reset cause from the bootload (in r2)
   * to the variable. Again, avr-gcc provides special code sections for this.
   */
   void resetFlagsInit(void) __attribute__ ((naked))
   __attribute__ ((section (".init0")));
   void resetFlagsInit(void)
   {
   /*
   * save the reset flags passed from the bootloader
   * This is a "simple" matter of storing (STS) r2 in the special variable
   * that we have created. We use assembler to access the right variable.
   */
   __asm__ __volatile__ ("sts %0, r2\n" : "=m" (resetFlags) :);
   }
   
   void setup() {
   Serial.begin(9600); // Initialize serial port
   }
   
   void loop() {
   Serial.println("Reset flag test");
   while (Serial.read() < 0)
   ; // wait for some type-in
   
   Serial.print("Have reset flag value 0x");
   Serial.print(resetFlags, HEX);
   /*
   * check for the usual bits. Note that the symnbols defined in wdt.h are
   * bit numbers, so they have to be shifted before comparison.
   */
   switch (resetFlags) {
   case 1<<WDRF:
   Serial.println(" (Watchdog)\n");
   break;
   case 1<<BORF:
   Serial.println(" (Brownout)\n");
   break;
   case 1<<EXTRF:
   Serial.println(" (External Reset)\n");
   break;
   case 1<<PORF:
   case ((1<<PORF) | (1<<BORF)):
   // A poweron can frequently result in both PORF and BORF being set, as the
   // power switch bounces or the voltage rises slowly.
   Serial.println(" (PowerOn)\n");
   break;
   default:
   // Multiple bits can be set under various circumstances. For example, the
   // "hold down reset while powering up" trick used to recover from certain
   // problems can leave both PORF and EXTRF set.
   Serial.println(" (Unknown)\n");
   break;
   }
   /*
   * Now we'll let the Watchdog reset the chip, and see if that cause is reported
   * correctly. Older versions of optiboot could not easily distinguish between
   * WDRF and EXTRF resets, since the WDT was used inside the bootloader.
   */
   wdt_enable(WDTO_1S);
   }

dove è che devo mettere il mio codice che va eseguito solamente all'accensione ?

Grazie

Si.
Puoi dichiarare una variabile globale, ad esempio:
Code: [Select]

bool onetime = true;


poi nel case metti:
Code: [Select]

case X:
 if (onetime) {
 // codice che vuoi eseguire
 onetime = false;
 }
 break;


in questo modo onetime è vera all'avvio di Arduino.
Appena viene richiamato il caso X viene eseguito l'if e quindi le tue istruzioni. infine viene posto onetime = false.
Al successivo richiamo del caso X, onetime è falso e quindi l'if non viene eseguito.
ma il
Code: [Select]
break;
 è necessario?
Arduino UNO starter kit.

pilotinocarter

Se resetti ritorna tutto come all'inizio.

SukkoPera

#25
Oct 23, 2015, 09:17 pm Last Edit: Oct 23, 2015, 09:17 pm by SukkoPera
Devi concentarti sullo switch, trasformandolo in qualcosa del genere:

Code: [Select]
switch (resetFlags) {
  case 1<<PORF:
  case ((1<<PORF) | (1<<BORF)):
    // IL CODICE INSERITO QUA VIENE ESEGUITO SOLO ALL'ACCENSIONE
    break;
  default:
    // IL CODICE INSERITO QUA VIENE ESEGUITO SOLO DOPO UN RESET
    break;
}
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

pilotinocarter

Ho provato...
il codice che inserisco sia per l'accensione che per il solo reset
non viene MAI eseguito. :smiley-confuse:

Nessuno dei due.

SukkoPera

"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

pilotinocarter


SukkoPera

#29
Oct 26, 2015, 02:48 pm Last Edit: Oct 26, 2015, 02:50 pm by SukkoPera
Nano? Leonardo? 2009? Mega? Pro Micro? Io ho tutte queste, e non tutte usano l'OptiBoot, per cui non tutte sono adatte. Se ti si fa una domanda, un motivo ci sarà...

Comunque se ti può consolare, anche i miei test sono stati fallimentari. A sto punto mi sa che ha ragione gbp01, aspettiamo la 1.6.6 e il suo nuovo builder.

Oppure, se ci spieghi perché volevi fare questo, magari possiamo proporti un'alternativa.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

Go Up