Stai prendendo il codice nel modo giusto...cioè come "spunto" e un "punto di partenza" per un approfondimento e una tua personale personalizzazione (non voleva essere un codice pronto all'uso).
Fai bene a usare il timer2, in modalità CTC. Per il valore del contatore basta usare TCNT2, dato che è un registro a 8 bit.
Per il resto segui il consiglio di Lesto riguardante la "bibbia" dell'ATMega328.
se non erro puoi invece impostare il valore di overflow: questa tecnica è più pulita. Mettiamo il caso in cui perdi un interrupt dal timer perchè facevi altro, dato che non risetti il valore di partenza, che ripartirà da 0, non solo avrai perso un interrupt ma anche il prossimo verrà generato in modo erroneo
Si, a lui conviene usare la modalità CTC che è facilmente ottenibile cambiando leggermente i registri del timer e praticamente non cambia il principio di funzionamento del sistema. Indubbiamente rende la tecnica più pulita in quanto non si deve ripristinare il valore iniziale. Sul "perdi un interrupt", invece, avrei quache perplessità, dato che solitamente è l'interrupt che interrompe qualcosa e non viceversa, e in un tipo di sistema come quello in oggetto sarà difficile che ci siano altri interrupt concorrenti.
mamma mia, mi usate i registri per impostare l'interrupt (quando attachInterrupt anadava più che bene)...
Che ti devo dire...volendo sorvolare sui quasi 200byte che l'istruzione attachInterrupt si "mangia" allegramente, usando direttamente il port mapping per settare il timer mi sembrava quasi una "stonatura" usare un'istruzione wiring...ma queste sono fissazioni mie
Si l'idea del timer2 in CTC mi sembrava migliore. Ho già la bibbia e mi sto documentando ma ad esempio provando a scrivere il codice con timer2 posso generare un pwm in uscita sul pin11 ma non riesco a far partire il timer quando voglio e a fermarlo quando voglio.
dalubar:
. Sul "perdi un interrupt", invece, avrei quache perplessità, dato che solitamente è l'interrupt che interrompe qualcosa e non viceversa, e in un tipo di sistema come quello in oggetto sarà difficile che ci siano altri interrupt concorrenti.
difficile ma non impossibile, sopratutto se fai funzioni ISR troppo lunghe, o hai interrupt con frequenze troppo alte, o parli spesso via seriale (funziona ad interrupt), o usi PWM, o il timer1 che aggiorna la micros (e quindi la millis), etc.. non è così impossibile perdere un interrupt per concorrenza
Il problema è che cambiando il valore di OCR2A non cambia la durata della forma d'onda. e poi comunque vorrei che una volta raggiunto il valore, dentro ISR(TIMER2_COMPA_vect) si generi il segnale di uscita e si fermi il timer per poi riprendere all'arrivo di un nuovo fronte del segnale d'ingresso con il nuovo delay settato. Ma in OCR2A il valore caricato cosa è un intero? cosa rappresenta?
difficile ma non impossibile, sopratutto se fai funzioni ISR troppo lunghe...
Si, Lesto, mi trovi d'accordissimo in tutto ciò che hai detto...solo che io mi riferivo specificamente al "suo" caso, cioè non credo che la sua applicazione contempli dialoghi con la seriale. Ovvio che dovendo performare il tutto per lo scopo prefissato si prenderanno tutte le (normali) precauzioni che si hanno quando si scrivono handler interrupt: ovvero poche istruzioni, uso minimo di registri, etc.
Per il millis, in verità ero convinto che Arduino gestisse uno stack interrupt...ma forse ricordo male io. Anzi se hai qualche notizia certa in merito ti sono grato
Nella modalità CTC il timer viene azzerato ogni volta che il valore del contatore TCNT2 raggiunge un particolare registro denominato, appunto, OCR2A.
E' come se l'hw del micro eseguisse una istruzione del tipo: if (TCNT2 == OCR2A) ISR(TIMER2_COMPA_vect)
OCR2A, quindi, definisce il valore TOP per il contatore (0xFF).
Ok chiaro, ma nel codice che ho postato non mi cambia il duty cycle della forma d'onda cambiando il valore di quel registro, perchè?
E comunque se volessi fare che una volta raggiunto il conteggio, nella chiamata alla ISR addetta volessi stoppare la ripartenza del conteggio?
Perchè lui poi riparte da zero, invece io voglio che riparta solamente quando glielo dico io.
Nel codice che ho postato quindi come faccio ad impostare il flag?
il flag di compare che si attiva quando il conteggio è finito è OCF2A e sulla bibbia c'è scritto che per resettarlo si può fare manualmente impostando un bit di I/O ad 1, altrimenti di default viene resettato automaticamente.
Non ho capito se questo flag va a 1 o a 0 una volta raggiunto il conteggio. Ma se si resetta automaticamente comunque come posso farlo io solamente quando voglio far riprendere il conteggio da zero?
Qual'è la soluzione migliore quindi tra l'overflow variabile e il CTC?
Intendevo usare il timer2 perchè avendo 8 bit ottengo valori più piccoli di conteggio, il timer0 invece andrebbe ad incasinare le funzioni tipo millis che uso nel loop o no?
Un contatore vale l'altro in questo caso credo.
Potete abozzare una copia di codice perchè possa capire meglio??
Nel mentre ho provato anche l'ultima soluzione di dalubar: sul pin 2 ho messo una onda quadra dal generatore di funzioni, così ad ogni fronte di salita il timer 1 parte. nella funzione di gestione dell'interrupt di overflow faccio una digitalwrite sul pin13 in modo da portare alto il segnale d'uscita e subito dopo scrivo uno zero, solo per provare con l'oscilloscopio. il comportamento è questo: avendo settato i CSxx per avere un prescaler di 64, e quindi step di 4us, se voglio far contare al timer 100us di delay, fino a che non va in overflow occorre che parta dal 65486, in hex FFCE, che carico nei registri.
Il risultato è che non ho nessun delay, o meglio circa 12us ma ci sarebbero comunque dovuti ai ritardi del micro.
Perchè?
Effettivamente l'impulso viene generato ogni fronte di salita del pin2 ma non viene ritardato di 100us come voglio.
non puoi ferare un timer. come ti ho detto devi usare un flag, ovvero una variabile booleana. quanto il timer va in overflow e la flag è falsa non fai nulla. Quindi quando leggi un fronte di salita azzeri il timer e metti la flag a true.
Scusa ma sono un elettronico cocciuto!
Stai parlando del codice di dalubar o di quello con il timer 2?
Non capisco il tuo ragionamento.
Questo è il codice di dalubar rivisto, dato che uso già il pin3 come interrupt per generare un impulso ritardato di 100us dal primo fronte di salita.
il contatore parte da 65536-200 in hex FF38, però il ritardo non è generato.
Cosa sbaglio?
scusami, io non sono ferrato sui timer, e magari sbaglio ma...
se hai 16.000.000 clock al secondo, e ogni clock è un +1 sul registro timer, 200clock/16.000.000clock/sec = 0,0000125 sec pari a 0,0125 millisecondi, pari a 12,5 microsecondi, non 100 come li vuoi tu. per averne 100 devi attendere circa 2000clock (F830)
Ho provato come dici tu ma non cambia nulla, ho sempre quei 15us di delay fissi.
Io ho seguito la guida di dalubar che dice:
prescaler=8 -> 16000000/8=2000000 Hz
periodo richiesto = 100us -> 100us/1/2000000=200
16Bit risoluzione timer1 -> 65536-200=65336 -> valore iniziale di conteggio del timer per arrivare in overflow dopo 100us e generare questo benedetto delay.
O sbaglio qualcosa nel codice oppure ci deve essere un trucco.
Fatemi sapere, grazie.
Per ridurre la frequenza di aggiornamento del contatore si usa il prescaler, altrimenti con un registro ad 8 bit ed un clock a 16 MHz si va da poche parti