Registri di sistema

zinim:
Grazie per le risposte,

quello che mi piacerebbe però, è essere in grado di modificare e accedere io stesso direttamente a queste cose per creare io stesso librerie od hoc per quello che devo fare; comunque darò sicuramente un'occhiata alle librerie di Leo per prendere spunto.

Grazie

Non ti ho infatti detto: "scarica e copia", ti ho detto "scarica e vedi" :wink:
Intanto ti devi armare di datasheet, lì ci sono riportati tutti i registri relativi ai timer e come impostarli.
Una volta che hai queste cose, guardi ai settaggi che ti servono per regolare una certa cosa e ti muovi di conseguenza.
Ad esempio, se vuoi usare un timer come semplice contatore, lo attiverai in modalità CTR, se invece vuoi generare un segnale su un pin dovrai scegliere la modalità: Fast PWM, Phase Correct PWM, Phase and Frequency Correct PWM ecc..
Dopo dovrai stabilire prescaler, valore iniziale del contatore, eventuale valore per registro OCRxA/B, che tipo di interrupt generare ecc...

Per incrementare una variabile, attivi il timer in modalità contatore (così non altera i segnali sui pin esterni), poi imposti il prescaler in base alla frequenza con cui vuoi che la tua variabile sia aggiornata, e poi attacchi una routine ISR per fare materialmente il lavoro di incremento.

Ti estraggo il codice relativo alla manipolazione del timer 2 del leOS per un Atmega328 che imposta il timer in modo che generi 1 overflow ogni millisecondo:

//halt all the interrupts
SREG &= ~(1<<SREG_I);
//during setup, disable all the interrupts based on timer
TIMSK2 &= ~((1<<TOIE2) | (1<<OCIE2A) | (1<<OCIE2B));
//prescaler source clock set to internal Atmega clock (asynch mode)
ASSR &= ~(1<<AS2);
//this sets the timer to increment the counter until overflow
TCCR2A &= ~((1<<WGM21) | (1<<WGM20)); 
TCCR2B &= ~(1<<WGM22);
//prescaler set to /64
TCCR2B |= (1<<CS22);
TCCR2B &= ~((1<<CS21) | (1<<CS20));
prescaler = 64.0;
//set the initial value of the counter depending on the prescaler
_starter = 256 - (int)((float)F_CPU * 0.001 / prescaler); //for 16 MHz: 6
TCNT2 = _starter;
TIMSK2 |= (1<<TOIE2);

E poi crei la ISR per gestire l'interrupt:

ISR(TIMER2_OVF_vect) {
  TCNT2 = _starter;
  .....
}

Qui ci sono tante cose che magari puoi non capire ma i commenti sono esplicativi.
Devi però (ripeto: "DEVI") lavorare col datasheet alla mano altrimenti non vai da nessuna parte, non puoi ricordarti tutti i registri a mente :stuck_out_tongue_closed_eyes:

PS:
l'ultima formula che vedi serve per ottenere un incremento preciso al millisecondo. Diversamente, l'incremento del contatore sarebbe stato leggermente più lento perché avrebbe eseguito 256 overflow ogni millisecondo invece di 250.
La formula per ottenere la frequenza di aggiornamento è:
Freq/Prescaler/(max_valore_registro)
Ora, avendo Freq = 16 MHz, Prescaler = 64 e max_valore_registro = 256 (dato che è il timer 2 è ad 8 bit), si avrebbe
16000000/64/256=976,5625 Hz

Ma così ho 976 overflow ogni millisecondo.
Se risolvo solo la prima divisione della formula precedente ottengo:
16000000/64=250000
Capisci che per ottenere 1000 overflow al secondo devo avere un contatore che abbia un valore massimo di:
250000/1000=250
Questo lo si ottiene semplicemente mettendo come valore di partenza del contatore (256-250)=6.