arduino: microsegundos de retraso ()

¿Cómo funciona la función delayMicroseconds()? Por lo que entendí, el preescalador del temporizador 0 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.

La documentación dice: "Esta función funciona con mucha precisión en el rango de 3 microsegundos y más. No podemos asegurar que los microsegundos de retraso funcionen con precisión para tiempos de retraso más pequeños". Los documentos para micros()dice "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)".

Respuestas (1)

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. Tómese el esfuerzo de encontrar el archivo y examinarlo. Por ahora, solo concéntrese en esta única función, no se basa en 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 igual para usted que para el desarrollador de la biblioteca. Que 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 de Atmel AVR .

Primero, se verifica que el valor de retraso sea igual a 1, en ese caso, simplemente regresando de la rutina que ya pasó más de un microsegundo de tiempo de CPU.

Luego, el valor del retardo se multiplica por cuatro ( <<=2). El __asm__bucle se compila en un bucle de 4 ciclos de CPU. 4 ciclos × 4 = 16 ciclos. 16 MHz/(4×4) = 1 MHz, lo que nos lleva 1 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 la sobrecarga introducida por el compilador. Llamar __asm__a -code desde C requiere algunas instrucciones adicionales para guardar los registros de la CPU.

Para un Arduino normal @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 cronometradas configuradas que la mayoría desconoce. Cuando se recibe una interrupción durante la ejecución de delayMicroseconds(), el tiempo de delayMicroseconds()será incorrecto. Por supuesto, puede detener las interrupciones antes de llamar 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.

O si no tiene instalado el IDE de Arduino, este archivo está disponible en github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…