Vai al contenuto
PLC Forum


Timer_0 Non Rispetta Il Tempo


Giorgio Demurtas

Messaggi consigliati

Giorgio Demurtas

Ho un display sul quale mostro la variabile velox, che vorrei vedere incrementata ogni secondo. Il problema è che il tempo non viene giusto, ma almeno 5 volte più veloce. Trattasi di un pic16f84.

Ho un quarzo da 4 MHz, quindi con prescaler a 8 dovrei ottenere 1000000/8=125000 Hz.

Se faccio partire il registro del timer da 131, ci vogliono 125 incrementi per mandarlo in overflow (131+125=256), e quindi eseguire l'interrupt ogni millisecondo.

Conto 1000 millisecondi e incremento velox.

#int_RTCC
RTCC_isr()  //Interrupt Service Routine
     {
     set_timer0(131); //131 così ci vogliono 125 incrementi per l'overflow
     millisecondi++;
     
     if (millisecondi>999) {
      millisecondi=0;
      velox++; 
      }
     
     }

funziona...ma va più veloce del previsto! senzasperanza.gif

Link al commento
Condividi su altri siti


Forse ti sto dicendo una cosa ovvia...

ma sei sicuro di averlo impostato in Timer Mode e non in Counter Mode?

Magari hai qualcosa sul pin del timer che ti crea degli eventi per far scattare il contatore.

Boh è un'idea.

Ciao

Link al commento
Condividi su altri siti

Giorgio Demurtas

Non lo so, come si imposta?

Comunque la sorgente dei tempi è interna.

void main() {         //inizio programma principale

set_tris_a(0x11); //ra4 ed ra0 ingressi, tutto il resto uscite
set_tris_b(0x00);

setup_timer_0 (RTCC_DIV_8|RTCC_INTERNAL); //imposto il prescaler 
enable_interrupts(int_rtcc); //abilito l'interrupt da tmr0
enable_interrupts(global);   //abilito tutti gli interrupts
setup_wdt(WDT_2304MS);

//impostazioni iniziali
velox=0;
millisecondi=0;
cifra_on=1;

while(1) //ciclo continuo-------------------------------------------------
   {
....
....

Un amico mi suggeriva X= (4*Prescaler*256)/(FOSCinHz)

X= (4*8*256)/(4000000) = 0.002048 seconds

Nel mio caso faccio (4*8*125)/4000000 = 0.001 secondi

e il registro lo faccio partire da 131

Link al commento
Condividi su altri siti

Non uso ne conosco molto i PIC faccio alcune osservazioni

(chiedo perdono in anticipo se sono banali)

1.- pag.20 datasheet T0IF dev'essere cancellato dalla proc di interrupt

non si cancella automaticamente. Se non lo fai hai interrupt continui

ma te ne accorgeresti perchè il micro andrebbe "a rilento"

2.- Sempre pagina 20 guardando il ddiagramma a blocchi ci sono poche possibilità o non hai settato il prescaler e allora dovresti vedere interrupt a F/4 oppure sospetto che la chiamata a setup_wdt ti riconfiguri il prescaler. La doc dice che è condiviso tra timer e wdt leggi a inzio paragrafo 5.2 dove chiarisce la cosa.

Link al commento
Condividi su altri siti

In effetti adesso è più chiaro smile.gif , mancava una parte iniziale.....

Come dice accacca credo sia colpa del wdt, se decidi di usare il prescaler per il timer non puoi usarlo per il WDT.

Link al commento
Condividi su altri siti

Giorgio Demurtas

eh si è proprio il WDT!

Ci ero appena arrivato da solo, perchè ho fatto un programma per cambiare un uscita ad ogni interrupt, e ci ho collegato il frequenzimetro, che mi segnava sempre la stessa cosa cambiando prescaler.

Allora ho cominciato a spogliare il programma lasciando solo le funzioni principali, e la prima cosa che ho tolto era proprio il WDT.

Ho anche corretto il valore di partenza a 132, perchè così diventano 125 intervalli compreso quello 256>0.

Comunque potrebbe andare meglio: In un minuto resta indietro di 1-2s rispetto al pc... unsure.gif

mah, ci penserò domani!

grazie per ora a tutti

Link al commento
Condividi su altri siti

Giorgio Demurtas

Per accelerare un pò, in modo da leggere 0.50 kHz nel frequenzimetro, faccio partire da set_timer0(135); invece che 132 teorico.

Ora resta indietro 3 s in 15 minuti. Ma dovendo fare un orologio c'è modo di risolvere o questi sono i limiti di accuratezza di un pic???

Mah, mi aspettavo una cosa molto più precisa, eppure il quarzo è da 4.000 MHz.

Link al commento
Condividi su altri siti

Tanto per incominciare i tuo 4MHz possono essere 3.9 o anche meno. Dipende dal quarzo e dalle capacità; potresti provare a variare il valore delle due capacità verso massa.

Poi c'è un problema legato, credo, al micro. Se non hai un timer a 16 bits gli errori dovuti ai tempi di altenza dell'interrupt aquella frequenza sono più pesanti. Con un timer a 16 bit puoi aumentare il periodo a qualche decina di ms, così i tempi di servizio pesano meno.

Metti la ricarica del timer subito nella prima istruzione di servizio all'interrupt.

Poi se nonostante tutto questo il ritardo o l'anticipo hanno valori pressochè costanti, puoi sempre cambiare la temporizzazione per compensare l'errore

Link al commento
Condividi su altri siti

il pic è innocente dovrebbe dipende dal quarzo ma anche avesse 100ppm dovresti vedere +/-1sec ogni 2,7ore (se non ho sbagliato i conti...)

come avviene il meccanismo di ricarica del counter va in overflow e riparte dal preset o devi ricaricare tu il valore?

se per caricare il timer ci metti 10us e lo fai ogni millisecondo

ti ritrovi un ritardo di 10ms ogni secondo ciè 600ms ogni minuto

che significa 3sec ogni 5min

Tu hai 1sec ogni 5min quindi il delay di ricarica ogni millisecondo potrebbe essere 3us bisognerbbe vedere delay per servire isr e che istruzioni asm fa realmente per calcolare il ritardo essatto fino alla ricarica del preset.

Modificato: da accacca
Link al commento
Condividi su altri siti

Non è questione di precisione del quarzo, è questione dell'equivalente capacitivo dell'intero oscillatore.

100 parti per milione totali, per un quarzo comune, con un oscillatore a saturazione come quelli dei dispositivi numerici, senza nessuna compensazione per temperatura, è già una bella precisione. Nello specifico sarebbero solo 400Hz di errore massimo.

In gioventù progettavo apparati per telcomunicazioni e avionica, una certa esperienza, con questi dispositivi, me la sono fatta. Bastano pochi pF in più o meno per avere spostamenti di frequenza anche maggiori.

Con qurzo a 4MHz dovrebbe essere necessario 1us, perchè necessita uan sola istruzione. Dipende se è la prima istruzione della routine o meno. Se il timer fosse un 16bit come, ad esempio, quello che si usa per i 16f877, il ritardo va ad influenzare uan base tempi di almeno un ordine di grandezza maggiore, quindi l'imprecisione totale diminuisce.

Modificato: da Livio Orsini
Link al commento
Condividi su altri siti

Giorgio Demurtas

Ah, ok, è normale, mi consolo. smile.gif

Nella routine di interrupt la prima cosa che faccio è ricaricare il timer.

Il TMR0 del 16F84 è a 8 bit.

Di fatto ho fatto così. Lascio un uscita sulla quale leggere la frequenza di interrupt, e risistemo il valore da caricare nel registro del timer.

Girovagando per la rete ho trovato che un Real time clock, che visto il prezzo (~2€) è fenomenale!

The DS1307 serial real-time clock (RTC) is a low-power, full binary-coded decimal (BCD) clock/calendar plus 56 bytes of NV SRAM. Address and data are transferred serially through an I²C, bidirectional bus. The clock/calendar provides seconds, minutes, hours, day, date, month, and year information. The end of the month date is automatically adjusted for months with fewer than 31 days, including corrections for leap year. The clock operates in either the 24-hour or 12-hour format with AM/PM indicator. The DS1307 has a built-in power-sense circuit that detects power failures and automatically switches to the backup supply. Timekeeping operation continues while the part operates from the backup supply.

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...