Ottenere un indice basato sullo tempo senza stato dal timer che trabocca

0

Attualmente sto lavorando a un progetto Arduino in cui devo tenere traccia delle voci per un certo periodo di tempo, in questo caso, 30 giorni. La nostra azienda tenterà di vendere questo prodotto a città e governi. Quindi deve davvero funzionare, il che mi fa venire voglia di astenersi dall'allocare dinamicamente memoria.

Le voci sono veramente piccole, esse (al momento) consistono in un singolo char , ma potrebbero diventare più grandi prima della fine di questo progetto. Verrà generata una voce ogni intervallo specifico, per ora presumo che sia una volta ogni 5 minuti.

La mia idea era di allocare una serie di voci, con la dimensione della quantità massima di voci. Per leggere o scrivere una voce, stavo pensando di afferrare il tempo in millisecondi dall'inizio e dividendolo per la quantità di millisecondi tra ogni voce. Alcuni pseudo-codice: (I valori nelle definizioni non corrispondono alla realtà descritta, io uso i valori semplici per rendere l'esempio il più chiaro possibile)

#define TOTAL_ENTRIES_TO_KEEP 5000
#define MILLISECONDS_PER_ENTRY 50

Entry[] entries = new Entry[TOTAL_ENTRIES_TO_KEEP];

Entry getCurrentEntry(){
    return entries[(millis()/MILLISECONDS_PER_ENTRY)%TOTAL_ENTRIES_TO_KEEP];
}

L'ho implementato, testato e funziona perfettamente. Il mio problema mi è stato presentato da Arduino.cc : (enfasi mia)

Returns the number of milliseconds since the Arduino board began running the current program. This number will overflow (go back to zero), after approximately 50 days.

Questo prodotto deve continuare a funzionare per più di 50 giorni consecutivi, dovrebbe essere in grado di resistere per un paio d'anni con il minimo indispensabile per la manutenzione. Quindi dovrò fare i conti con questo overflow. Se il timer dovesse oltrepassare, diciamo, esattamente TOTAL_ENTRIES_TO_KEEP * MILLISECONDS_PER_ENTRY , questo non sarebbe un problema, poiché in tal caso verrebbe superato dalla voce 4999 a 0, che è quello che faccio con %TOTAL_ENTRIES_TO_KEEP comunque. Il punto è che non funziona, e fare casino con le librerie interne per far sì che non sembrerebbe la migliore idea per me.

Non mi interessa una leggera deviazione nell'intervallo tra le voci, né nella quantità totale di voci da conservare. Questo sistema deve mostrare una media di voci su un periodo mensile, che è già ambiguo, quindi se un mese al sistema dura 30, 31, 32 o 30.94836 giorni non ha importanza per il risultato finale.

Come posso proteggere questo sistema dagli effetti di questo overflow? Grazie in anticipo per il tuo contributo.

    
posta Daniël van den Berg 20.07.2016 - 15:17
fonte

2 risposte

1

Se si insiste sull'uso di millis () per indicizzare l'array, è necessario rendere la dimensione dell'array un fattore del valore massimo millis () oppure è necessario ripristinare il valore millis () su zero quando l'array avvolge. Ma queste sembrano idee sbagliate e non capisco perché stai usando millis () per indicizzare l'array.

Pensa all'array come a un buffer circolare (ad anello). Creare una variabile che rappresenti il valore dell'indice corrente nell'array. L'indice corrente viene incrementato ogni volta che viene memorizzata una voce. Quando l'array è pieno, il valore dell'indice viene spostato a zero. Utilizzare questa variabile indice per indicizzare la matrice anziché millis (). Puoi ancora memorizzare le voci alla stessa velocità, ma ora hai dissociato il valore millis () dall'indice dell'array.

    
risposta data 20.07.2016 - 16:56
fonte
0

La chiave per questo è estendere l'intervallo del contatore che stai utilizzando per tracciare il tempo.

Mantieni un contatore a 32 bit "numero di overflow" che incrementerai ogni volta che il valore millis () si estende, e usa il tuo contatore e il valore millis () per formare un contatore a 64 bit - che ti darà un involucro tempo di 50 * 2 ^ 32 (o circa 200 miliardi) giorni - probabilmente più lungo di quanto ci si possa aspettare che il dispositivo continui a funzionare.

È possibile rilevare l'overflow tenendo traccia dell'ultimo valore di millis () ottenuto e, se il valore corrente è inferiore, si incrementa il contatore del "numero di overflow".

Dovrai essere sicuro di chiamare questa routine almeno una volta ogni periodo di wrap.

Qualcosa come:

uint64_t long_term_millis() 
{
static uint32_t last_millis = 0;
static uint32_t wrap_count = 0;
uint32_t current_millis = millis();

    if (current_millis < last_millis) wrap_count++;

    last_millis = current_millis;

    return (((uint64_t)wrap_count)<<32) + current_millis;
}
    
risposta data 21.07.2016 - 21:41
fonte

Leggi altre domande sui tag