Hvordan fungerer funksjonen delayMicroseconds (). Etter det jeg forsto er prescaler av timer0 satt til 64. For en 16MHz klokke gir 4.0uS per telling. Jeg er litt forvirret i matematikken for å komme til 1uS-intervall?
Kommentarer
Svar
Kildekoden for denne funksjonen er ganske godt dokumentert og finnes i / usr / share / arduino / hardware /arduino/cores/arduino/wiring.c på Linux-systemer. Windows-systemer vil ha en lignende bane til filen wiring.c. Bruk arbeidet for å finne filen og bla gjennom den. For nå er det bare å fokusere på denne enkeltfunksjonen, den stoler ikke på noen andre funksjoner.
Ved å inspisere koden vil du legge merke til at det ikke handler om tidtakere, det handler om instruksjonssykluser. Koden er sterkt avhengig av at kompilatoroptimalisering er nøyaktig den samme for deg som for utvikleren av biblioteket. Det er en antagelse fra forfatteren! Antall CPU-sykluser «brent» av hver instruksjon er godt dokumentert i Atmel AVR instruksjonsdokument .
Først er forsinkelsesverdien sjekket for å være lik 1, i så fall bare å returnere fra rutinen som allerede er brukt over en mikrosekund CPU-tid.
Da blir forsinkelsesverdien multiplisert med fire (<<=2
). __asm__
-løkken kompileres til en 4 CPU-syklusløkke. 4 sykluser × 4 = 16 sykluser. 16MHz / (4 × 4) = 1MHz, som tar 1 us syklustid, oppløsningen vi er ute etter.
De siste -2 mikrosekundene (før sløyfen blir sparket av) er igjen en korreksjon på kompilatoren introduserte overhead. Å ringe __asm__
-kode fra C krever noen ekstra instruksjoner for å lagre CPU-registre.
For en vanlig Arduino @ 16MHz vil bare følgende kode bli samlet:
/* 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: Den kompilerte koden er ganske nøyaktig, men vær oppmerksom på følgende: På Arduino er det konfigurerte tidsintervaller som de fleste ikke er klar over. Når et avbrudd mottas under utførelsen av delayMicroseconds()
, vil tidspunktet for delayMicroseconds()
være feil. Du kan selvfølgelig stoppe avbrudd før du ringer til delayMicroseconds()
og aktivere dem etterpå, men det har igjen innvirkning på tidsnøyaktigheten av varigheten av den kompilerte koden for aktivering / deaktivering. Kommentarer
- Eller hvis du ikke har Arduino IDE installert, er denne filen tilgjengelig på github.com/arduino / Arduino / blob / master / hardware / arduino / cores / …
- Det ' s flyttet hit: github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/…
micros()
sier " På 16 MHz Arduino-kort (f.eks. Duemilanove og Nano) har denne funksjonen en oppløsning på fire mikrosekunder (dvs. verdien som returneres er alltid et multiplum av fire). "