timer, interrupt e passo d'acquisizione

dado:
salve a tutti! sto cercando di usare arduino come scheda d'acquisizione, la velocità ora è buona, ma non riesco a regolarizzare il passo di campionamento. ho provato a misurare, ad ogni loop, il tempo passato dall'inizio del programma (con millis) e a svolgere tutte le funzioni necessarie solo quando il numero di millisecondi passati è variato, ma non funziona, perché ogni 41-42 ms perde 1 ms. inoltre al professore non piace questo sistema.
l'ideale sarebbe avere un timer interno che genera un interrupt ogni millisecondo, per poi svolgere tutte le funzioni necessarie; ma non riesco a trovare una funzione che faccia da timer! come si fa?

Arduino non mette a disposizione una funzione simile, ma nel playground si trovano librerie di funzioni/classi che possono fare forse al caso tuo.

Se invece vuoi usare il metodo diretto devi leggerti il datasheet del microcontroller che stai usando, in più nella sezione generale cerca la libreria di le72 leOS. In quei post trovi la spiegazione dell'interrupt TIMERX_OVF_vect, come configurare il registri ecc.

Sotto vedi la ISR (Interrupt Service Routine) che viene eseguita quando il contatore del timer2 va in overflow. Imostando i registri come si vede nella funzione init(), la ISR viene eseguita appunto ogni millesimo di secondo. Io uso una struttura (__sys_tick) per contenere le variabili "ms" e "seconds", e altro non riportato qui.

static struct  {
    uint16_t ms;
    unsigned long seconds;
} __sys_tick;

// inizializza registri timer2 per overflow ogni ms. (vale solo per ATmega328 a 16MHz) 
void init() 
{

    //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);

//the following code sets the prescaler depending on the system clock
// prescaler set to 64
     TCCR2B |= (1<<CS22);
     TCCR2B &= ~((1<<CS21) | (1<<CS20));
     TCNT2 = 256 - (int)((float)F_CPU * 0.001 / 64);
     TIMSK2 |= (1<<TOIE2);
}

ISR(TIMER2_OVF_vect) {
    __sys_tick->ms++;
    if (__sys_tick->ms > 999) {
        __sys_tick->ms = 0;
        __sys_tick->seconds++;
    }

}

Occhi che prima che il micro salta alla prima istruzione contenuta nella ISR, viene disabilitato
l'interrupt globalmente, questo per evitare che un'altro interrupt avvenga quando ancora si sta eseguendo codice interno alla ISR, altrimenti c'è il rischio di stack overflow. Tradotto in altri
termini nella isr tutti gli interrupt sono disabilitati.

Ciao.