¿Cómo implementar la función de retraso en Keil ARM MDK que espera un tiempo determinado en microsegundos que se puede volver a compilar a cualquier velocidad de reloj razonable definida en la configuración del proyecto Keil? Y todo esto sin usar temporizadores.
En mi humilde opinión, el mejor enfoque es tener un temporizador de hardware que nunca se escribe, sino que simplemente se ejecuta libremente. Esto le permitirá a uno emular fácilmente un número arbitrario de temporizadores de sondeo para duraciones de hasta la mitad de la duración del temporizador de hardware. Para "iniciar" un temporizador, simplemente calcule el valor del temporizador de hardware cuando debe expirar. Para ver si un temporizador ya ha expirado, reste el tiempo de expiración esperado del tiempo actual (considerando ambas cantidades como sin firmar) y vea si el resultado (sin firmar) excede la mitad del valor máximo del temporizador. Si es así, el temporizador no ha expirado.
Alternativamente, si se desea un temporizador para medir el tiempo desde que ocurrió un determinado evento, se puede bloquear el valor del temporizador cuando ocurrió el evento y luego calcular la diferencia entre el valor bloqueado y el tiempo presente.
Tendrá que determinar la duración de un NOP y, a continuación, usar #Defines para que, en función de la velocidad del reloj, inserte el número correcto.
Específicamente, desea saber la cantidad exacta de ciclos de reloj que se necesitan para completar 1 bucle del estilo:
for(long i=0;i<NUMBER_OF_LOOPS_REQUIRED;i++)
{
__NOP();
}
Al hacer #define para el número de bucles requeridos, se reconfigura para que sea automático en función del retraso solicitado y la velocidad del reloj a la que se está ejecutando actualmente. Todo esto se puede envolver en una macro.
#if _Main_Crystal == 25000000
#define LOOP_DELAY 400
#elif _Main_Crystal == 16000000
#define LOOP_DELAY 256
#else
#error microsecond delay must be adjusted!
#endif
void usDelay( void )
{
for (int i = 0; i < LOOP_DELAY; i++)
{
SERVICE_WATCH_DOG();
}
}
donde SERVICE_WATCH_DOG()
hay una macro para dar servicio al temporizador de vigilancia. Esto también se puede reemplazar con un archivo NOP
.
Use una función de prueba para averiguar cuáles deben ser sus constantes LOOP_DELAY para cada frecuencia de reloj:
void TestDelay( void )
{
SetIOPin(); // Use a scope to start measuring elapsed time here.
usDelay();
ResetIOPin(); // use a scope to end measuring elapsed time here.
}
Se prefiere una referencia de temporizador de hardware porque un buen optimizador podría eliminar el bucle por completo o modificarlo en función de la configuración. El otro problema con los bucles de tiempo que no se menciona aquí es que si ocurre una interrupción durante su bucle de tiempo, podría llevar mucho más tiempo. Las interrupciones deben ser cortas de todos modos, pero no todos los sistemas siguen ese mantra.
leon heller
semaj
usuario1844
x4mer
x4mer
Kortuk
toby jaffey
chris stratton
Roh
chris stratton