Pages: 1 [2] 3 4   Go Down
Author Topic: Nuova libreria secTimer  (Read 3101 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

nono, in pratica la libreria farebbe da layer tra utente e millis(), gestendo in automatico gli if di overflow... o meglio se intercettasse l'interrupt, perchè così siamo slegati dal fatto che l'utente debba chiamare la libreria almeno una volta ogni 40 giorni
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

nono, in pratica la libreria farebbe da layer tra utente e millis(), gestendo in automatico gli if di overflow... o meglio se intercettasse l'interrupt, perchè così siamo slegati dal fatto che l'utente debba chiamare la libreria almeno una volta ogni 40 giorni
Ho capito cosa vuoi fare ma non hai capito il mio appunto.
Prendi il classico:

tempo=millis()+10000; //qui millis valeva 500 unità sotto all'overflow (4294966795), quindi tempo va in overflow e contiene 9500
...
if (millis()>tempo) { //qui è 4294966795>9500? quindi è vero anche se in realtà è falso
  ....
}

In questo caso come gestisci il problema?
Logged


0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

non capisco, l'idea non è di fornire all'utente una millis() "allungata" ma la seconds. quindi

Code:
tempo=millis()+10000

nella libreria sarebbe

Code:
tempo=millis()/1000+SecondiPerOverflow*NumeroOverflow
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ora sono io che non capisco. Se non modifichi il codice della millis(), la millis() soffre sempre dell'overflow, che devi comunque tamponare in qualche modo. O sacrifichi un altro timer, come ho fatto io, e metti una funzione che soffrirà di questo problema quando nessuno potrà prendersela con l'autore della secTimer (perché passato a miglior vita) oppure riscrivi la millis().

Ad esser sinceri, avevo pensato anche a questa opzione...  smiley-twist
Logged


0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

non puoi intercettare l'overflow della millis SENZA riscriverla?

anche se la millis soffre gli overflow, se tu conti il numero di overflow.... sai quanti millisecondi sono passati, anche se non puoi conteggiarli usando una long, hai spezzato l'informazione in più variabili.

edit: mi hai fatto venire in mente un'idea fantastica per una libreria, da far includere tra quelle standard.
In pratica una libreria che si occupa di intercettare TUTTE le fonti di interrupt, e di gestire un array di puntatori a funzione (passati dall'utente) per ogni interrupt: quindi esattamente come l'attachInterrupt, solo che permette di attaccare più funzioni in coda.

però rimango nel dubbio per quanto riguarda come gestire prescaler e roba del genere, dovrei usare il minimo sempre, e poi simulare le richieste dell'utente
« Last Edit: April 19, 2012, 08:16:50 am by lesto » Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

non puoi intercettare l'overflow della millis SENZA riscriverla?
Aspetta. Millis è una funzione di Arduino che restituisce il valore di una variabile unsigned long che internamente viene incrementata ad ogni overflow del contatore TIMER0, 1 volta ogni 1/1000s. Quando tu invochi millis() altro non fai che chiedere il valore di questo contatore interno.

Quote
anche se la millis soffre gli overflow, se tu conti il numero di overflow.... sai quanti millisecondi sono passati, anche se non puoi conteggiarli usando una long, hai spezzato l'informazione in più variabili.
OK. Forse capisco. Si tratta di integrare il codice inserendo nel core di Arduino la gestione di un contatore di secondi che scorra parallelamente al contatore dei millisecondi.
In questo modo si può fare tutto usando il TIMER0, però devo creare un nuovo file da sostituire a quello del core dell'Arduino. Stasera ci metto mano, ora non ce la faccio tra poco devo uscire.

EDIT:
però non è così semplice come sembra. Intanto si perde la portabilità di secTimer, e poi ogni volta che viene reinstallato/aggiornato il core la modifica si perde. E va visto se tale intervento invasivo da noia poi ad altre componenti del core.
« Last Edit: April 19, 2012, 08:19:28 am by leo72 » Logged


0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

non serve che sia parallelo (a meno che non vuoi usarlo anche come la libreria metro)
basta che intercetti gli interrupt di overflo del timer0, che usa per conteggiare il numero di overflow.
poi quando vuoi sapere i secondi trascorsi effettivamente, usa la formula che ho postato prima, che come vedi si basa su millis() per sapere lo stato dei secondi dall'ultimo overflow, ma poi somma il valore dei secondi causati dagli overflow, superando cosi il limite dell'overflow.
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ho studiato un po' il codice della funzione millis() dell'Arduino..... è un codice un po' particolare.
Vi spiego. Nella mia swRTC quando ho messo l'ISR per gestire l'overflow del timer ed incrementare il contatore dei millisecondi che poi usavo per aggiornare i secondi e tutti gli altri registri temporali in cascata (ore, minuti, giorni ecc...) avevo impostato il timer in modo tale che gli overflow avvenissero esattamente 1 ogni 1000mo di secondo. Ciò è possibile dando un valore iniziale al contatore interno del timer. Siccome il contatore è a 8 bit, quindi i valori possibili sono 256, tramite calcoli (la faccio breve) per 16 MHz si imposta un prescaler di 64 e si usa un valore iniziale che dev'essere di 6. In questo modo si ha 16000000/64/250=1000. Quindi 1000 overflow al secondo o, viceversa, 1 secondo ogni 1000 overflow.

Sull'Arduino la cosa è più complicata. Siccome appunto il timer 0 è usato anche per generare il segnale PWM sui pin 5 e 6, non potevano impostare il calcolo come ho fatto io perché se davano un valore di partenza al contatore alteravano anche il segnale PWM. Allora hanno adottato una soluzione via software per limare quella differenza di 6. Inoltre usano anche un altro calcolo per tener conto dei microsecondi.

Per allineare l'aggiornamento all'effettiva frequenza di overflow del timer devo tener conto del fatto che stiamo andando ad un clock leggermente diverso per cui devo calcolare 976 overflow al secondo invece che 1000.

Dopo aver capito come funzionava il tutto, sono riuscito a creare questi 2 file. Sono versioni che vanno sostituite ai file wiring.c e wiring.h dell'Arduino IDE 002x (per la 1.0 ancora non ho fatto nulla) nella cartella /hardware/arduino/cores/arduino.

Adesso c'è la nuova funzione seconds() che restituisce i secondi dall'avvio dello sketch, restando sempre funzionanti sia millis, delay e delaymicroseconds di Arduino e non consumando nessun interrupt o timer aggiuntivo.
Ah, questa modifica è compatibile anche con la secTimer per via del fatto che usa 2 timer differenti ma lo sketch secTimerLed non è più compilabile perché lì usavo una variabile denominata seconds, che invece ora è una parola riservata del core dell'Arduino.

Ah, altra cosa. C'è anche un nuovo file keywords.txt che dovete sostituire a quello che avete in /lib per avere l'evidenziazione del codice.

Resta da provare se la funzione continua a... funzionare attivando il PWM. Sicuramente sì (altrimenti non andrebbe neanche la millis) ma non ho materialmente avuto il tempo di provarla.

Allegato c'è uno sketch di prova, una specie di BlinkWithoutDelay che usa seconds() al posto di millis().

Resta inteso che funziona SOLO per l'Arduino e per gli Atmega168/328 e 1280/2560 dato che è una modifica al core dell'Arduino e non una libreria a sé stante.

* seconds2.zip (6.57 KB - downloaded 8 times.)
« Last Edit: April 19, 2012, 04:22:15 pm by leo72 » Logged


Rovereto
Offline Offline
Full Member
***
Karma: 0
Posts: 152
La luce e' piu' veloce del suono. Per questo motivo alcune persone sembrano brillanti fino a quando non parlano.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bravo! Poche righe di codice ma ben piazzate.

Ciao
QP
Logged

BG (I)
Offline Offline
Full Member
***
Karma: 0
Posts: 202
Usus plura docet
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ottimo  smiley-grin
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ho aggiornato i file wiring modificati, difatti ora vedete nel precedente post uno zip denominato seconds2.
Ed ho modificato anche il post stesso.... nel casino della mia IDE non mi ero accorto di aver selezionato per i test un 328 a 8 MHz per cui avevo per forza il lampeggio ogni 2 secondi usando 1000 overflow al secondo.... smiley-red

Inoltre ripensando un po' ai calcoli, ho trovato che la giusta frequenza per aggiornare il contasecondi è di incrementarlo ogni 976 overflow, perché il timer è impostato per una frequenza di 976,5625 Hz. Si perde circa mezzo ms ogni secondo ma, vista l'imprecisione congenita del risonatore ceramico dell'Arduino UNO questo valore è ampiamente nella norma. Se volete maggior precisione potete modificare il codice e mettere lo scalo di 9 ms ogni 16 secondi,  dato che 0,5625*16 = 9.
Logged


0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ho dato un'occhiata al wiring.h (arduino 0022) e ho tirato fuori questa soluzione (NON testata):

Code:
int secondsBecauseOverflow=0;
static int SECONDS_PER_TIMER0_OVERFLOW = MICROSECONDS_PER_TIMER0_OVERFLOW / 1000000; //defined in wiring.c
void setup(){
}

void loop(){
}

ISR(TIMER1_OVF_vect){
  secondsBecauseOverflow += SECONDS_PER_TIMER0_OVERFLOW;
}

unsigned long getSeconds(){
  return millis()/1000 + secondsBecauseOverflow;
}

ora, il bello che wiring.h possiede già la variabile "secondsBecauseOverflow" che si chiama "timer0_overflow_count", quindi basterebbe che alla wiring.h aggiungessero la riga

Code:
unsigned long seconds(){
    return millis()/1000 + (MICROSECONDS_PER_TIMER0_OVERFLOW/1000000) * timer0_overflow_count;
}

ed il gioco sarebbe già fatto di base!
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ma tu intercetti l'overflow del timer 1....
Code:
ISR(TIMER1_OVF_vect){
  secondsBecauseOverflow += SECONDS_PER_TIMER0_OVERFLOW;
}

Inoltre ho notato anch'io la variabile timer0_overflow_count, ma non è come dici. Se noti è contenuta nella routine di intercettazione dell'overflow del timer 0 e che viene aggiornato con la stessa frequenza con cui viene aggiornato il contatore dei millisecondi. Quella variabile la riusano per estrarre il numero di microsecondi.
Logged


Cagliari, Italy
Offline Offline
Tesla Member
***
Karma: 110
Posts: 6984
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

x iscrizione
Logged

Code fast. Code easy. Codebender --> http://codebender.cc/?referrer=PaoloP

Cagliari, Italy
Offline Offline
Tesla Member
***
Karma: 110
Posts: 6984
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ciao Leo, ti segnalo la soluzione di questo altro utente che ha creato una funzione "millis" a 64 bit.
--> http://arduino.cc/forum/index.php/topic,93959.msg705701.html#msg705701
Logged

Code fast. Code easy. Codebender --> http://codebender.cc/?referrer=PaoloP

Pages: 1 [2] 3 4   Go Up
Jump to: