Dubbio su effetto delay e millis su escuzione codice

...smanettando sul codice del cronografo balistico realizzato tempo fa ho notato che, nella porzione di codice che allego, se sostituisco il delay con la funzione millis vengono generati degli errori nell'esecuzione del codice. Vorreicapire ilperchè
Altra domanda qual'è la differenza tra un void di questo tipo "void nome (void)" fuori dal setup e loop e gli stess void(setup) e void(loop)?

void clearAndEnable(void)
{
  t1 = 0;
  t2 = 0;
  delay(500); // REM inserendo il millis causa problemi lettura entrata
  /*
    {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis1 > interval1)
    {
      previousMillis1 = currentMillis;
    }
    }
  */
  EIFR |= bit(INTF0);  // EIFR: External Interrupt Flag Register)
  EIFR |= bit(INTF1);
  EIMSK |= bit(INT0);
  EIMSK |= bit(INT1);
}

Non ti è chiaro qual è la differenza tra il realizzare un delay con millis() e l'istruzione delay().

Dal nome della funzione direi che viene eseguita una tantum per ripristinare un qualcosa e quel delay() probabilmente ha lo scopo di "filtrare" il segnale o qualcosa del genere.
Se metti un millis() in quel modo è come se elimini del tutto il delay() perché la prima volta che chiami la funzione l'if è falso, ma dopo la funzione non viene chiamata (fino a quando non serve resettare di nuovo).

Poi per favore basta con ' sto void per riferirsi ad una funzione. void rappresenta solo il tipo di dato che la funzione restituisce (o accetta come parametro) ovvero nulla.

Grazie. L aprima parte della risposta mi ha chiarito il dubbio.
La seconda parte no. Non credo di essermi riferito al void come funzione. Io non ho ben chiaro, tra le tante cose, "come funziona" l'utilizzo degli altri "void"...oltre quelli canonici "setup" e "loop". Ovvero a cosa serve un "void" esterno al setup ed al loop?...immagino venga invocato dal citarlo nel codice del loop...ma perchè non è interno al loop?

@vince59 devi fare chiarezza su che cosa sono le funzioni in C++

Nel mondo Arduino tutti hanno familiarità con le funzioni setup() e loop(), ma queste non sono altro che funzioni (appunto!) come le altre.

La prima ha la particolarità di venire eseguita una volta sola, l'altra viene richiamata continuamente.

In C/C++ una funzione si definisce con la sintassi

<tipo dati valore restituito in uscita> nomeFunzione( <tipo dati parametro1>, <tipo dati parametro2>... etc etc )

Quindi definendo la funzione void setup(void) stiamo dichiarando una funzione che vuole un parametro void (vuoto) in ingresso e restituisce un valore void in uscita, ovvero nulla e nulla.
L'analogia è quella delle routine() usate con altri linguaggi che però in C NON esistono (ci sono solo le funzioni).

Se invece dichiaro

int getMax(int n1, int n2) {
  int max = max(n1, n2);
  return max;
}

ho definito una funzione che accetta due int in ingresso e restituisce un valore int in uscita

Come detto però, una breve risposta su un forum non può essere esaustiva.
Il mio consiglio è quindi quello di affrontare l'argomento in modo un po' più strutturato e magari con l'aiuto di un buon manuale C/C++... poi capirai perché tutte le volte che leggo
voglio mettere un void qua, voglio fare un void che fa quello mi viene l'orticaria :stuck_out_tongue_winking_eye:

E' il principio della "riusabilità" del codice.
Quando hai un codice ripetitivo puoi semplicemente definire una funzione dove metti tutte le istruzioni che si ripetono e poi richiami enne volte la funzione dove serve senza riscrivere tutto il papocchio.

Ne risulta un codice più snello, più leggibile e più efficiente.

Grazie per la risposta dalla quale ho imparato qualcosa e che rileggeroò attentamente per comprendere!
Capisco benisssimo la motivazione della tua orticaria...ma io, smanettone entrato nel mondo della programmazione direttamente con Arduino, pur avendo fatto bei passi (a mio dire e con le cazziate di Gug), ho spesso dei limiti oggettivi proprio per la mancanza di uno studio strutturato che non credo di poter recuperare facilmente.
Mi metto di fronte il codice e cerco di capirne struttura, logica ed interazione...grazie ancora.

A parte l'uso del termine void (immagina di sostituire la parola void con vuoto, e vedi come le tue frasi risultano "comiche"), la decomposizione funzionale, cioè creare diverse funzioni invece di un unico codice lunghissimo, ti permette oltre al riutilizzo/invocazione da diversi punti del programma, anche un grandissimo ordine: puoi "nascondere" un insieme di operazioni da svolgere dietro un nome più comodo, così dove serve puoi dire: "fare_la_pastasciutta();" e poi descrivi in un altro punto tutti dettagli relativi alla sua preparazione. In pratica tantissime parti "di controllo" possono essere scritte in italiano: "leggi_ingressi(); elabora(); stampa_risultati();" ottenendo un programma non solo più leggibile ma anche formato da sezioni brevi, con pochi livelli di annidamento/indentazione e quindi a loro volta molto più leggibili.

perchè non è interno al loop?

In C non è neppure ammesso sintatticamente, mentre in altri linguaggi è possibile, ma ha senso solo per cose particolari visto che entra in gioco il concetto di ambito di visibilità (dove le cose sono visibili/modificabili e dove no).

Bene ora è chiaro. Dopo la risposta di cotestatnt ho riletto il codice ed in effetti ha assunto una logica ed i miei comici (è vero) richiami ai void sono spariti! Ora li ho chiamati tutti FUNZIONI!
Quindi è una parte di codice che posso mettere dove opportuno per richiamarlo quando serve. In effeti nel mio codice la gestione delle schermate del LCD sono tutte gestite tranmite specifiche funzioni richiamate quando necessario. Quello che mi aveva destabilizzato è il fatto che queste fossero fuori dal setup e loop. ma dopo la risposta di Claudio_FF è tutto chiaro. Thanks!!!

In effetti, se non si conosce a priori il linguaggio di programmazione (C/C++), l'ambiente "Arduino", nel tentativo di semplificare le cose, può creare un po' di confusione.
Per definizione, quando si lancia un programma scritto in C o C++ quella che viene eseguita per prima è una funzione che si chiama main(), che esiste anche per Arduino, solo che non si vede mai nel codice che andiamo a scrivere, e viene aggiunta dall'IDE durante la compilazione. La main() di Arduino è questa:

int main(void)
{
        init();

        initVariant();

#if defined(USBCON)
        USBDevice.attach();
#endif

        setup();

        for (;;) {
                loop();
                if (serialEventRun) serialEventRun();
        }
        
        return 0;
}

Come puoi vedere, dopo aver inizializzato l'hardware, viene richiamato una volta sola il setup() ed all'ifinito il loop().

Non so se sia servito a chiarirti le idee o a crearti più confusione di prima, comunque è così che le cose funzionano.

Ciao, Ale.

1 Like

Ciao,...ora si che tutto ha senso! Risposta davvero utile ed assolutamemte chiara.
Ineccepibile la premessa, tenendo anche conto che l'hobbista che smanetta di tanto in tanto con la programmazione, difficilmente mirerà a diventare un esperto di C o C++ ma piuttosto al ragiungimento del proprio obiettivo.