Como funciona a função delayMicroseconds (). Pelo que entendi, o prescaler do timer0 está definido para 64. Para um clock de 16 MHz dá 4.0uS por contagem. Estou um pouco confuso com a matemática para chegar ao intervalo 1uS?
Comentários
Resposta
O código-fonte para esta função está bastante bem documentado e pode ser encontrado em / usr / share / arduino / hardware /arduino/cores/arduino/wiring.c em sistemas Linux. Os sistemas Windows terão um caminho semelhante para o arquivo wiring.c. Faça o esforço de encontrar o arquivo e navegar por ele. Por enquanto, concentre-se apenas nesta única função, ela não depende de nenhuma outra função.
Ao inspecionar o código, você perceberá que não se trata de temporizadores, mas de ciclos de instrução. O código depende muito da otimização do compilador, sendo exatamente o mesmo para você e para o desenvolvedor da biblioteca. Essa é uma suposição do autor! O número de ciclos de CPU “queimados” por cada instrução está bem documentado no documento de conjunto de instruções Atmel AVR .
Primeiro, o valor de atraso é verificado para ser igual a 1, nesse caso apenas retornando da rotina já gasto em um microssegundo de tempo de CPU.
Então o valor de atraso é multiplicado por quatro (<<=2
). O __asm__
-loop compila em um loop de 4 ciclos de CPU. 4 ciclos × 4 = 16 ciclos. 16 MHz / (4 × 4) = 1 MHz, o que leva 1 us de tempo de ciclo, a resolução que buscamos.
Os últimos -2 microssegundos (antes do loop ser iniciado) são novamente uma correção no compilador introduzido sobrecarga. Chamar __asm__
-code do C requer algumas instruções extras para salvar os registros da CPU.
Para um Arduino normal a 16 MHz, apenas o seguinte código será compilado:
/* 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: O código compilado é bastante preciso, mas esteja ciente do seguinte: No Arduino, há interrupções temporizadas configuradas que a maioria desconhece. Quando uma interrupção é recebida durante a execução de delayMicroseconds()
, o tempo de delayMicroseconds()
estará errado. É claro que você pode parar as interrupções antes de chamar delayMicroseconds()
e habilitá-las depois, mas isso novamente afeta a precisão do tempo pela duração do código compilado para habilitar / desabilitar.
Comentários
- Ou se você não tiver o IDE do Arduino instalado, este arquivo está disponível em github.com/arduino / Arduino / blob / master / hardware / arduino / cores / …
- É ' s movido aqui: github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/…
micros()
diz " Em placas Arduino de 16 MHz (por exemplo, Duemilanove e Nano), esta função tem uma resolução de quatro microssegundos (ou seja, o valor retornado é sempre um múltiplo de quatro). "