Come funziona la funzione delayMicroseconds (). Da quello che ho capito il prescaler di timer0 è impostato a 64. Per un clock a 16MHz dà 4.0uS per conteggio. Sono un po confuso in matematica per arrivare allintervallo 1uS?
Commenti
Risposta
Il codice sorgente di 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 wiring.c. Fai lo sforzo di trovare il file e sfogliarlo. 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 sullottimizzazione del compilatore che è esattamente la stessa per te che per lo sviluppatore della libreria. Questo è un presupposto dellautore! Il numero di cicli della CPU “bruciati” da ciascuna istruzione è ben documentato nel documento sul set di istruzioni Atmel AVR .
Innanzitutto il valore del ritardo è controllato per essere uguale a 1, in quel caso solo di ritorno dalla routine già speso su un microsecondo di tempo CPU.
Quindi il valore del ritardo viene moltiplicato per quattro (<<=2
). Il __asm__
-loop viene compilato in un ciclo di 4 CPU. 4 cicli × 4 = 16 cicli. 16MHz / (4 × 4) = 1MHz, che richiede un tempo di ciclo di 1 us, la risoluzione che stiamo cercando.
Gli ultimi -2 microsecondi (prima che il loop venga avviato) è di nuovo una correzione sul compilatore introdotto in testa. La chiamata al __asm__
-code da C richiede alcune istruzioni aggiuntive per salvare i registri della CPU.
Per un normale Arduino a 16 MHz verrà compilato solo il codice seguente:
/* 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 ); }
BTW: Il codice compilato è abbastanza accurato, ma tieni presente quanto segue: su Arduino ci sono interrupt a tempo configurati che la maggior parte di loro non conosce. Quando viene ricevuto un interrupt durante lesecuzione di delayMicroseconds()
, la tempistica di delayMicroseconds()
sarà errata. Ovviamente puoi interrompere le interruzioni prima di chiamare delayMicroseconds()
e abilitarle in seguito, ma anche in questo caso la precisione dei tempi è influenzata dalla durata del codice compilato per labilitazione / disabilitazione.
Commenti
- Oppure, se non hai installato lIDE di Arduino, questo file è disponibile su github.com/arduino / Arduino / blob / master / hardware / arduino / cores / …
- It ' s spostato qui: github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/…
micros()
dice " Sulle schede Arduino a 16 MHz (ad es. Duemilanove e Nano), questa funzione ha una risoluzione di quattro microsecondi (ovvero il valore restituito è sempre un multiplo di quattro). "