istruzione che viene eseguita una sola volta

peppe123:
Appena posso sperimento tutto.

Vi ringrazio.. sempre gentili e disponibili.

Saluti
Giuseppe

si però il mettere il while true blocca di fatto l'arduino in un ciclo infinito ed il ciclo loop di fatto non viene più eseguito... mentre il case postato prima va contro la richiesta di peppe:

esiste una funzione che non contenga if, variabili o altre condizioni...

@qsecofr (questo nick mi ricorda troppo il mondo AS400 :P)
il

while(true);

di fatto blocca l'esecuzione del codice, in quanto si tratta di loop infinito - e questo l'ho detto nel mio post.

A questo punto, la domanda è:
l'esecuzione del codice deve essere bloccata (ovvero, dopo il case non eseguire più nulla), o la domanda di peppe123 era di fatto mooolto più semplice?

Ovvero: ad una determinata condizione, suona il buzzer N volte, poi smetti. MA se risuccede l'evento, suona nuovamente il buzzer N volte etc etc etc?
Perchè in questo ultimo caso nessuna delle ipotesi di cui si è discusso fin'ora è idonea...

/**
  * Esegue il codice contenuto nel blocco una sola volta
  * example: new_one_shot(only_one) {
  *             your code here...
  *             ....
  *          }
  * Questa macro è utile se usata all'interno di un loop.
  * Nota che only_one è il nome di una variabile e quindi
  * si dovrà usare un nome diverso in ogni uso di
  * new_one_shot(var_name)

  *
  */
#define new_one_shot(shot_name) static uint8_t shot_name = 1;\
                for ( ; shot_name > 0; shot_name-- )

Esegue solo una volta il codice contenuto nel blocco delimitato dalle graffe, ma se shot_name vale 2 lo esegue 2 volte.

Dopo la prima esecuzione puoi stabilire quante volte vuoi che il codice venga eseuito.

while (true) {
    uint8_t alarm_count = 0;
    new_one_shot(cica_alarm) {
        alarm_bip();
        alarm_led();
        alarm_count++;
       // ecc.
    }

    if (alarm_count > 3)
       cica_alarm = 3; // new_one_shot girerà 3 volte
}

Se si vuole si può parametrizzare, al fine di decidere subito quante volte dovrà essere esguito il ciclo, es n_repeat(my_loop, 5)
In questo modo verrà eseguito solo 5 volte e mai più a meno che non si reimposti la variabile my_loop = 5 o altro valore.

Ciao.

esempio:

switch (x)
{
case 0:
{suona il buzzer 2 volte} // questa istruzione voglio che venga eseguita in concomitanza con l'accesso al case
// per una sola volta,anche se effettuo altri accessi allo stesso case non voglio che si ripeta
// chiedevo appunto se ci fosse un codice che non utilizza variabili

istruzioni... // queste istruzioni devono essere eseguite fino a che non si esce dal case
istruzioni...
istruzioni...

break;
}

sper di essere stato piu chiaro :slight_smile:

grazie

Che io sappia non è possibile mantenere un valore senza fare uso di variabili, quindi non conosco un modo per far fare al micro ciò che ti serve.

Occhio che potresti trovare una funzione o macro che fa quello che vuoi ma sotto sotto una variabile ci sarà sempre.

Ciao.

peppe123:
esiste una funzione che non contenga if, variabili o altre condizioni e che in un ciclo loop o in uno switch case esegue delle istruzioni una sola volta all'avvio?

Quindi, per i motivi su esposti, la risposta è: no.
Ma perché non vuoi usare variabili?

leo72:

peppe123:
esiste una funzione che non contenga if, variabili o altre condizioni e che in un ciclo loop o in uno switch case esegue delle istruzioni una sola volta all'avvio?

Quindi, per i motivi su esposti, la risposta è: no.
Ma perché non vuoi usare variabili?

non avrei problemi ad utilizzare variabili, pensavo ci fosse la possibilità di utilizzare un codice semplice che non utilizza variabili, tutto qui.
a questo punto direi che il modo piu snello e semplice per gestire la cosa è una variabile booleana come suggerito da PaoloP

PaoloP:
Si.
Puoi dichiarare una variabile globale, ad esempio:

bool onetime = true;

poi nel case metti:

case X:

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

Grazie a tutti..

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

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.

Ma per curiosità, perché devi fare ciò?

pilotinocarter:
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

SukkoPera:
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

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

@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 ... :frowning:

Guglielmo

P.S. : Ovviamente la cosa funziona se usi Atmel Studio ed hai tu il controllo del tuo sorgente :wink:

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

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

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 ... :frowning:

Guglielmo

P.S. : Ovviamente la cosa funziona se usi Atmel Studio ed hai tu il controllo del tuo sorgente :wink:

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... ::slight_smile:

SukkoPera:
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... ::slight_smile:

Non dubito che magari vada ...
... i problema è se la tecnica è SEMPRE utilizzabile o meno ... ::slight_smile:

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

Guglielmo

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

PaoloP:
Si.
Puoi dichiarare una variabile globale, ad esempio:

bool onetime = true;

poi nel case metti:

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

break;

è necessario?

Se resetti ritorna tutto come all'inizio.

Devi concentarti sullo switch, trasformandolo in qualcosa del genere:

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;
}