¿Cómo funciona la función delayMicroseconds ()? Por lo que entendí, el preescalador de timer0 está configurado en 64. Para un reloj de 16MHz da 4.0uS por conteo. ¿Estoy un poco confundido con las matemáticas para llegar al intervalo de 1uS?
Comentarios
Respuesta
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 cableado.c. Haga el esfuerzo de encontrar el archivo y examinarlo. Por ahora, céntrese en esta única función, no depende de ninguna otra función.
Al inspeccionar el código, notará que no se trata de temporizadores, se trata 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. ¡Eso es una suposició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 Atmel AVR .
Primero, el valor de retardo es comprobado que sea igual a 1, en ese caso, simplemente regresando de la rutina ya gastada durante un microsegundo de tiempo de CPU.
Luego, el valor de retraso se multiplica por cuatro (<<=2
). El __asm__
-loop se compila en un ciclo de 4 ciclos de CPU. 4 ciclos × 4 = 16 ciclos. 16MHz / (4 × 4) = 1MHz, que toma 1 us de tiempo de ciclo, la resolución que buscamos.
Los últimos -2 microsegundos (antes de que se inicie el ciclo) son nuevamente una corrección en el compilador introducido arriba. Llamar __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 ); }
Por cierto: el código compilado es bastante preciso, pero tenga en cuenta lo siguiente: En Arduino hay interrupciones programadas 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 del tiempo por la duración del código compilado para habilitar / deshabilitar.
Comentarios
- O si no tiene el IDE de Arduino instalado, este archivo está disponible en github.com/arduino / Arduino / blob / master / hardware / arduino / cores / …
- Es ' s movido aquí: github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/…
micros()
dicen " En placas Arduino de 16 MHz (por ejemplo, Duemilanove y Nano), esta función tiene una resolución de cuatro microsegundos (es decir, el valor devuelto es siempre un múltiplo de cuatro). "