arduino: delaymicroseconds ()

Hoe werkt de functie delayMicroseconds (). Van wat ik begreep, is de voorschrijver van timer0 ingesteld op 64. Voor een 16 MHz klok geeft 4,0uS per telling. Ik ben een beetje in de war over de wiskunde om bij het 1uS-interval te komen?

Opmerkingen

  • De documentatie zegt " Deze functie werkt zeer nauwkeurig in het bereik van 3 microseconden en hoger. We kunnen niet garanderen dat delayMicroseconds precies zal werken voor kleinere vertragingstijden. " De documenten voor micros() zeggen " Op 16 MHz Arduino-kaarten (bijv. Duemilanove en Nano) heeft deze functie een resolutie van vier microseconden (dwz de geretourneerde waarde is altijd een veelvoud van vier). "
  • Zie ook electronics.stackexchange.com/q/22584/2191

Answer

De broncode voor deze functie is redelijk goed gedocumenteerd en kan worden gevonden in / usr / share / arduino / hardware /arduino/cores/arduino/wiring.c op Linux-systemen. Windows-systemen hebben een soortgelijk pad naar het bedrading.c-bestand. Neem de moeite om het bestand te vinden en er doorheen te bladeren. Concentreer je voorlopig gewoon op deze enkele functie, het is niet “afhankelijk van andere functies.

Door de code te inspecteren zul je merken dat het niet om timers gaat, maar om instructiecycli. De code is sterk afhankelijk van het feit dat de optimalisatie van de compiler voor u precies hetzelfde is als voor de ontwikkelaar van de bibliotheek. Dat is een aanname van de auteur! Het aantal CPU-cycli dat door elke instructie wordt “gebrand”, wordt goed gedocumenteerd in het Atmel AVR-instructieset-document .

Eerst is de vertragingswaarde gecontroleerd op gelijk aan 1, in dat geval terugkerend van de routine die al meer dan een microseconde CPU-tijd heeft doorgebracht.

Vervolgens wordt de vertragingswaarde vermenigvuldigd met vier (<<=2). De __asm__ -loop compileert in een lus van 4 CPUs. 4 cycli × 4 = 16 cycli. 16 MHz / (4 × 4) = 1 MHz, wat 1 ons cyclustijd kost, de resolutie waar we naar op zoek zijn.

De laatste -2 microseconden (voordat de lus wordt afgetrapt) is opnieuw een correctie op de compiler geïntroduceerd overhead. Het aanroepen van __asm__ -code vanuit C vereist wat extra instructies om CPU-registers op te slaan.

Voor een normale Arduino @ 16MHz wordt alleen de volgende code gecompileerd:

/* 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: De gecompileerde code is redelijk nauwkeurig, maar let op het volgende: Op Arduino zijn er getimede interrupts geconfigureerd waarvan de meeste niet op de hoogte zijn. Als een interrupt wordt ontvangen tijdens de uitvoering van de delayMicroseconds(), zal de timing van delayMicroseconds() verkeerd zijn. Je kunt interrupts natuurlijk stoppen voordat je delayMicroseconds() aanroept en ze daarna inschakelen, maar dat heeft weer invloed op de nauwkeurigheid van de timing door de duur van de gecompileerde code voor het inschakelen / uitschakelen.

Opmerkingen

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *