arduino: delaymicroseconds ()


8

Come funziona la funzione delayMicroseconds (). Da quello che ho capito, il prescaler di timer0 è impostato su 64. Per un orologio a 16 MHz fornisce 4,0 uS per conteggio. Sono un po 'confuso in matematica per arrivare all'intervallo 1uS?


4
La documentazione dice "Questa funzione funziona in modo molto accurato nell'intervallo da 3 microsecondi in su. Non possiamo garantire che delayMicroseconds funzionerà esattamente per tempi di ritardo minori". La documentazione per micros()dice "Su schede Arduino a 16 MHz (ad esempio Duemilanove e Nano), questa funzione ha una risoluzione di quattro microsecondi (ovvero il valore restituito è sempre un multiplo di quattro)".
RedGrittyBrick

Risposte:


9

Il codice sorgente per questa funzione è abbastanza ben documentato e può essere trovato in /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c su sistemi Linux. I sistemi Windows avranno un percorso simile al file cablaggio.c. Sforzati di trovare il file e di esplorarlo. Per ora concentrati solo su questa singola funzione, non si basa su altre funzioni.

Ispezionando il codice noterai che non si tratta di timer, ma di cicli di istruzioni. Il codice si basa fortemente sull'ottimizzazione del compilatore che è esattamente la stessa per te per lo sviluppatore della libreria. Che presupposto dell'autore! Il numero di cicli CPU "bruciati" da ciascuna istruzione è ben documentato nel documento del set di istruzioni AVR Atmel .

Innanzitutto viene verificato che il valore del ritardo sia uguale a 1, in quel caso appena tornato dalla routine già trascorsa in un microsecondo di tempo della CPU.

Quindi il valore del ritardo viene moltiplicato per quattro ( <<=2). I __asm__-loop compila in un loop ciclo 4 CPU. 4 cicli × 4 = 16 cicli. 16MHz / (4 × 4) = 1MHz, che richiede 1 tempo di ciclo us, la risoluzione che stiamo cercando.

Gli ultimi -2 microsecondi (prima che il loop venga avviato) è di nuovo una correzione sul sovraccarico introdotto dal compilatore. La chiamata di __asm__-code da C richiede alcune istruzioni aggiuntive per salvare i registri della CPU.

Per un normale Arduino @ 16MHz verrà compilato solo il seguente codice:

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
        // calling avrlib's delay_us() function with low values (e.g. 1 or
        // 2 microseconds) gives delays longer than desired.
        //delay_us(us);
        // for the 16 MHz clock on most Arduino boards

        // for a one-microsecond delay, simply return.  the overhead
        // of the function call yields a delay of approximately 1 1/8 us.
        if (--us == 0)
                return;

        // the following loop takes a quarter of a microsecond (4 cycles)
        // per iteration, so execute it four times for each microsecond of
        // delay requested.
        us <<= 2;

        // account for the time taken in the preceeding commands.
        us -= 2;

        // busy wait
        __asm__ __volatile__ (
                "1: sbiw %0,1" "\n\t" // 2 cycles
                "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
        );
}

A proposito: il codice compilato è piuttosto accurato, ma tieni presente quanto segue: Su Arduino ci sono interrupt a tempo configurati che la maggior parte non è a conoscenza. Quando viene ricevuto un interrupt durante l'esecuzione di delayMicroseconds(), il tempismo di delayMicroseconds()sarà errato. Naturalmente è possibile interrompere gli interrupt prima di chiamare delayMicroseconds()e abilitarli in seguito, ma ciò influisce nuovamente sull'accuratezza dei tempi in base alla durata del codice compilato per l'abilitazione / disabilitazione.


O se non hai installato l'IDE Arduino, questo file è disponibile su github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…
microtherion

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.