Dubbio, cicli di temporizzazione paralleli ?

Prima di tutto, non sparate se la domanda sembra stupida ... grazie :stuck_out_tongue:

Stavo pensando ad una possibile applicazione che richiede cicli di temporizzazione paralleli anche lunghi, e leggendo sulle guide ho trovato riferimenti a delay e millis ... ma la descrizione del delay dice che arresta l'esecuzione del programma, mentre la descrizione del contatore millis dice che resetta dopo circa 9 ore ... ora, se ad esempio avessi 2 pulsanti che attivano 2 uscite con tempi differenti (e' solo un'esempio teorico, il primo che mi e' venuto in mente), e sempre ad esempio il primo attiva l'uscita 1 per 10 ore, ed il secondo per 5 ore, per come l'ho capita dalle guide, se usassi delay, il secondo pulsante in teoria non dovrebbe funzionare, dato che se il programma e' arrestato durante il ciclo di delay causato dal primo, non sarebbe in grado di leggere il secondo ... mentre se uso millis, ed il suo valore si resetta dopo circa 9 ore, non potrei contarci un ritardo di 10 ... fin qui, ho capito correttamente o ho fatto casino ?

Quindi, se volessi creare 2 (o 3, o 5, o vattelapesca) cicli di temporizzazione, attivabili sia da eventi interni che esterni, indipendenti fra loro e molto lunghi, facendo in modo che nel frattempo il programma continui a funzionare ed eseguire tutto il resto delle funzioni, quale sistema sarebbe meglio utilizzare ? (intendo a parte costruirmi dei timer hardware, nel rispetto della Prima Legge dell'Elettronica :stuck_out_tongue: :D)

Esistono funzioni di count o di timer utilizzabili per questo scopo, indipendenti da quelle limitazioni ? ... oppure sarebbe meglio usare un contatore indipendente (tipo ad esempio un RTC, o la libreria swRTC di leo di cui ho letto qualcosa qui in giro), e basare i vari conteggi dei cicli di ritardo su queste ?

Etemenanki:
mentre la descrizione del contatore millis dice che resetta dopo circa 9 ore ... ora,

La millis va in overflow dopo 1193 ore, poco più di 49 giorni, dall'accensione di Arduino, questo perché è un contatore a 32bit e devono passare 2^32 millisecondi prima dell'overflow.
La millis può essere resettata a piacere dal proprio codice oppure si può verificare se c'è stato un overflow nel caso di temporizzazioni lunghissime o applicazioni che lavorano 24/7.

Sempre di Leo, ti possono essere utili le sue librerie: LeOS e Looper.
Le trovi nel suo sito web.

Grazie, oggi gli do un'occhiata :smiley:

astrobeed: non potrei resettarla, perche' potrebbero essere in esecuzione altri cicli.

C'è un modo per aggirare il problema dell'overflow, impostando il controllo su millis in un determinato modo.
Ho scritto un articolo a proposito.

Grazie leo, ho dato un'occhiata all'articolo, anche se e' un po piu complesso del mio livello :P, E' comunque interessante ... e mi ha fatto venire in mente una possibile soluzione alternativa, ma serve sapere se e' fattibile ... mettiamo che io ogni 24 ore decida di resettare il contatore millis, dovrei farlo a condizione che nessun ciclo sia attivo al momento ... esiste un modo per "interrogare" lo stato delle uscite, o dei cicli ?

Mi spiego, se ad esempio io impostassi che ogni 24 ore resetta il millis, c'e' un modo per dirgli "resetta solo se non ci sono cicli attivi di temporizzazione, altrimenti riprova fra 10 minuti" o simile ?

Eten oltre a confermare la bonta' dei lavori di Leo (su questo campo ha dato il meglio di se) sottolineo, anche per capire piu' a fondo la problematica, proprio il discorso che semplicemente usando la millis cosi' come e' usata nel blinkwithoutdelay, non hai problemi di overflow, quindi non devi nemmeno mai resettare nulla
Questa scoperta e' a nome Leo/Lesto ed e' quanto di piu' importante e' stato scoperto nel 2012 :slight_smile:

Quindi come prima cosa usa l'esempio ufficiale inserito nell'ide Blink Without Delay, e come compendio leggi l'articolo che ti ha linkato Leo

Testato:
Questa scoperta e' a nome Leo/Lesto ed e' quanto di piu' importante e' stato scoperto nel 2012 :slight_smile:

Infatti gli è valsa la nomination al ArduNobel 2012 :grin:

Provero' a controllare anche quello.

Grazie a tutti :wink:

Scremando le battute, confermo quanto detto da Testato :wink:
Se il controllo lo fai nella forma

MILLIS - TEMPO_PRECEDENTE > INTERVALLO

non incorrerai mai nell'overflow di millis perché il risultato di (millis - vecchioMillis) sarà sempre un numero uguale o maggiore di zero anche se millis si fosse resettato.

leo72:
... perché il risultato di (millis - vecchioMillis) sarà sempre un numero uguale o maggiore di zero anche se millis si fosse resettato.

E' la parte che sto cercando di capire, perche' a logica non mi tornava. (scusa, lo so che per te magari e' semplice, ma io sono un'hardwarista, non un programmatore ... dammi qualsiasi cosa hardware e te la smonto, ribalto e rimonto, ma capire la programmazione ci sto arrivando solo adesso, e poco alla volta)

Dove ad esempio nell'articolo dici:

MILLIS - TEMPO_PRECEDENTE > INTERVALLO
In questo modo la differenza fra il valore fornito da millis() e la precedente registrazione sarà sempre un numero compreso fra 0 ed intervallo. Facciamo un esempio....

Quello che intendo e' che se millis e' 100 e vecchiomillis e' 80, e' logico che 20 sia maggiore di zero, ma se millis (resettato) e' 100 e vecchiomillis (prima del reset) era 120, il risultato "dovrebbe" essere per logica -20 ... tu parli di variabili unsigned che non ammettono numeri negativi, suppongo che il "trucco" sia nel modo in cui queste variabili restituiscono il numero quando nell'operazione interviene un risultato negativo ... devo riuscire a capire un po meglio questa parte, credo ... ci studiero' su, magari con un martello prima o poi mi entra in testa :P.

Guarda io l'ho letto mi sembra anche di averlo capito, poi l'ho dimenticato :slight_smile:
L importante è che funzioni.
Non è una cosa banane questa scoperta, io frequento il sito da quando era ancora sul vecchio forum e la uno non era ancora uscita, ebbene nonostante le domande come le tue sul millis appaiono ogni giorno, nessuno incluso il team ufficiale, si era accorto di questo comportamento.

E' che voi pensate che un numero negativo sia un qualche cosa diverso da ... un numero :slight_smile:

Un numero è rappresentato da una serie di bit ... per convenzione noi, nel caso vogliamo trattare numeri segnati, diciamo che "un certo bit" rappresenta il segno (... non è esattamente così, ma una semplificazione) ...

Esempio : prendiamo un CHAR = 8 bit ...

... nel caso lo vogliamo trattare come SEGNATO sappiamo che esso può assumere valori da -128 a +127, mentre, se lo trattiamo come NON SEGNATO esso assume valori da 0 a 255 eppure ... sempre gli stessi bit stiamo utilizzando.

Quindi, a seconda di come interpretiamo i bit lo stesso numero 0xFF può assumere il valore -1 (signed) oppure +255 (unsigned) ... il trucco è questo ... NON considerare il bit del segno e vedere il risultato di quella "differenza" NON come un numero segnato, ma interpretare TUTTI i bit semplicemente secondo il loro valore binario (unsigned) :wink:

Spero sia un po' più chiaro ...
... fate un po' di prove e vederete che la tecnica di Leo è basata proprio su questo :slight_smile:

Guglielmo

P.S. : In realtà vi ho semplificato un po' le cose ... se volete una descrizione molto più rigorosa e corretta (... complemento a due) potete trovarla qui : http://www.micro.dibe.unige.it/maurizio_valle/Elettronica_Industriale_1/Capitolo%208.pdf :wink:

Per quanto riguarda il test di millis, etemenanki devi considerare questo: il compilatore gestisce i numeri in base al loro "contenitore". La differenza fra signed e unsigned ve l'ha data Guglielmo, aggiungo che il bit del segno è solo un modo per avvisare di come deve essere memorizzato il numero nel "contenitore".

Ammettiamo che la differenza fra l'attuale millis ed il suo valore precedente sia -20. In realtà il numero non diventa 20 perché un valore signed memorizzato in un unsigned non perde semplicemente il suo segno.
I numeri negativi sono memorizzati nel loro complemento a 2 (ogni bit invertito) per cui -20 in realtà è memorizzato come (2^32-20).
Ecco perché la differenza torna ad essere compresa nell'intervallo 0-INTERVALLO.

Ti invito a rileggere il mio articolo dove, nella prima parte, dà la spiegazione dei numeri in complemento a 2 e dell'esempio finale:

Ammettiamo che tempo_precedente valga 4.294.967.000 e che intervallo valga 1000. Ad un certo punto millis() va in overflow e riparte da zero. Il confronto diventa:

0 - 4294967000 > 1000

Si tenderebbe a pensare che il confronto diventi:

-4294967000 > 1000

ma usando interi di tipo unsigned la sottrazione in realtà restituisce come valore 296. Questo perché un unsigned non può trattare numeri negativi per cui il risultato è in realtà dato dal massimo valore contenibile, 232 ossia 4.294.967.296, meno 4.294.967.000, per cui 296. A questo punto il confronto è diventato:

296 > 1000

che ovviamente è falso. Solo quando millis supera il valore di 704 il confronto diventa vero, perché:

705 - 4294967000 = -4294966295
-4294966295 => 1001
1001 > 1000 = TRUE

:roll_eyes: ... mi era completamente sfuggita la parte del complemento a due ... :sweat_smile:

(dov'e' la faccina che si nasconde per la vergogna, quando serve ? ... :P)