¿Cómo funciona la función delayMicroseconds ()? Por lo que entendí, el prescaler de timer0 se establece en 64. Para un reloj de 16MHz se obtienen 4.0uS por conteo. Estoy un poco confundido en los cálculos para llegar al intervalo 1uS?
¿Cómo funciona la función delayMicroseconds ()? Por lo que entendí, el prescaler de timer0 se establece en 64. Para un reloj de 16MHz se obtienen 4.0uS por conteo. Estoy un poco confundido en los cálculos para llegar al intervalo 1uS?
El código fuente de esta función está bastante bien documentado y se puede encontrar en /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c en sistemas Linux. Los sistemas Windows tendrán una ruta similar al archivo wiring.c. Tome el esfuerzo de encontrar el archivo y hojearlo. Por ahora, solo concéntrate en esta función única, no se basa en ninguna otra función.
Al inspeccionar el código, notará que no se trata de temporizadores, sino de ciclos de instrucción. El código depende en gran medida de que la optimización del compilador sea exactamente la misma para usted que para el desarrollador de la biblioteca. Que una asunción del autor! El número de ciclos de CPU "quemados" por cada instrucción está bien documentado en el documento del conjunto de instrucciones AVR de Atmel .
Primero se verifica que el valor del retardo sea igual a 1, en ese caso, simplemente regresa de la rutina que ya se gastó en un microsegundo de tiempo de CPU.
Luego, el valor del retardo se multiplica por cuatro ( <<=2
). El __asm__
-loop se compila en un ciclo de ciclo de 4 CPU. 4 ciclos × 4 = 16 ciclos. 16MHz / (4 × 4) = 1MHz, que nos lleva 1 ciclo de tiempo, la resolución que buscamos.
Los últimos -2 microsegundos (antes de que se inicie el ciclo) son de nuevo una corrección en la sobrecarga introducida por el compilador. Llamar a __asm__
-code desde C requiere algunas instrucciones adicionales para guardar los registros de la CPU.
Para un Arduino normal a 16MHz solo se compilará el siguiente código:
/* 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: El código compilado es bastante preciso, pero tenga en cuenta lo siguiente: En Arduino, hay interrupciones temporizadas configuradas que la mayoría desconoce. Cuando se recibe una interrupción durante la ejecución de delayMicroseconds()
, la sincronización de delayMicroseconds()
será incorrecta. Por supuesto, puede detener las interrupciones antes de llamar a delayMicroseconds()
y habilitarlas después, pero eso nuevamente afecta la precisión de la temporización por la duración del código compilado para habilitar / deshabilitar.