Go Down

Topic: timer, interrupt e passo d'acquisizione (Read 5950 times) previous topic - next topic

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?

Michele Menniti

Ciao dado, ora c'è una specifica sezione software (nella pagina in alto) per queste problematiche. Potresti gentilmente aprire il Topic lì ed eliminare questo (in basso a sinistra "remove Topic")? Grazie.
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

MauroTec



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.






Code: [Select]


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.
AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Go Up