Rutina de configuración del temporizador de hardware ideal

1

Imagina que intentas escribir una rutina en C para un microcontrolador de 8 bits que convierte un intervalo de tiempo deseado (ya sean segundos, milisegundos, hercios, etc.). al valor de precarga del temporizador del hardware correspondiente (teniendo en cuenta la fuente del reloj y la frecuencia del temporizador). El objetivo es hacer que la función sea lo más fácil posible de usar, con la menor cantidad de argumentos posible. ¿Cómo sería esta función?

¿Pasaría en un uint32_t que representa los hercios deseados del temporizador (0 = 0Hz, 1000 = 1kHz, etc.):

void set_timer(uint32_t hz);

¿Preferirías usar un uint16_t que represente a kHz (0 = 0Hz, 1 = 1KHz, 10 = 10Khz)?

void set_timer(uint16_t khz);

¿O sería más deseable un argumento de punto fijo de 32 bits (para poder representar una fracción de hercios)?

void set_timer(q15_16_t hz);

¿O este valor de punto fijo representaría segundos en lugar de Hz?

void set_timer(q15_16_t sec);

O utilizarías un punto fijo de 16 bits en lugar de un punto fijo de 32 bits.

¿O incluso te atreverías a querer usar un punto flotante? O ¿qué pasa con un flotador de media precisión?

¿Qué piensas?

    
pregunta TRISAbits

3 respuestas

1

Primero sugeriría usar el tiempo en lugar de la frecuencia, ya que este último implica que el temporizador es de tipo continuo. El usuario a menudo está interesado en un cierto retraso "de una sola vez", cuando espera que algún tipo de hardware esté disponible.

Segundo, uint32_t es un gran NO en los microcontroladores de 8 bits. Tan pronto como use números de 32 bits, cada 8 amargo en el mercado creará una avalancha de códigos de máquina ineficientes, probablemente con llamadas a subrutinas internas. Los números de 16 bits son suficientemente malos. Aunque, por supuesto, hay casos en los que se necesita una precisión de alta resolución y es posible que deba utilizar tipos de enteros grandes a regañadientes.

En este caso, dudo mucho que su MCU de 8 bits tenga un periférico temporizador de 32 bits. El estándar de facto para los 8 bitters es tener temporizadores de hardware de 16 bits. No tiene sentido especificar una resolución que no corresponda con el hardware.

El uso de punto flotante es aún peor: si alguna vez necesita una precisión de punto flotante en una MCU de 8 bits, lo más probable es que haya elegido la MCU incorrecta para comenzar con su proyecto. (El argumento del costo de 8 bits frente a 32 bits ha quedado obsoleto para siempre).

Basado en el argumento anterior, sugeriría algo como:

void set_timer (uint16_t ms);

donde ms es el tiempo en milisegundos.

Sin embargo, el caso ideal es calcular el tiempo necesario en el preprocesador, luego mostrarlo en una constante, que luego se lee directamente en los registros del hardware del temporizador.

    
respondido por el Lundin
0

En general, uso los temporizadores de hardware de dos maneras:

  1. configuro el temporizador para que active un evento (interrupción) en una frecuencia particular, y luego lo dejo funcionando a esa frecuencia; si quiero hacer cosas a varios ritmos, realizaré algunas tareas cada tres interrupciones, algunas cada ocho, etc. Este es mi enfoque más común para manejar el tiempo cuando el sistema está "despierto".
  2. Para los temporizadores de baja velocidad que deben ejecutarse mientras la CPU está inactiva, prefiero usar un contador de ejecución libre que se ajusta en algún intervalo, y luego establecer un registro de comparación con el tiempo absoluto cuando el próximo evento de activación debe ocurrir

En algunas ocasiones, puedo usar un temporizador para generar una frecuencia de "pitido"; en la mayoría de los casos, adjuntaré el temporizador a un PWM de hardware. Cuando se genera un "pitido", es posible que desee especificar una frecuencia, aunque lo más común es que especifique un período o un índice en una tabla de frecuencias útiles mantenidas por la rutina que configura el pitido. p>

Para el primer estilo de uso, la API no es particularmente relevante, ya que está "configurada y olvidada". Para la aplicación de la señal acústica, el API del temporizador no es relevante, ya que la API de "pitido" a menudo combinará la configuración del temporizador con el código necesario para habilitar o deshabilitar el PWM. Solo con el segundo uso es una API particularmente relevante. Para eso, el estilo de API más útil probablemente sería "configurar la próxima activación para que se produzca a más tardar en el tiempo absoluto indicado, si no está programado antes", con un parámetro de 32 bits que representa un tiempo continuo (ajuste) , y combinado con una rutina que informa la hora actual en la misma escala de 32 bits. Si el hardware es por ejemplo solo un contador de 16 bits, las rutinas deben actuar adecuadamente (por ejemplo, la rutina de "tiempo de lectura", si se llama al menos una vez cada 65535 tics, debe devolver un valor de 32 bits en continuo aumento; si se usa la rutina "establecer alarma" para configurar una alarma en más de 32768 tics en el futuro, debe establecer la alarma 32768 tics en el futuro (si el tiempo solicitado era, por ejemplo, 65,538 tics en el futuro, la rutina debería notar que el tiempo es más de 65,536 tics en el futuro, en lugar de simplemente usar los 16 bits más bajos del tiempo y considerarlo como dos tics en el futuro).

    
respondido por el supercat
0

Yo personalmente uso:

// Returns actual timer rate in Hz
uint32_t set_timer(uint32_t hz);

Pero en el mundo de los sistemas restringidos, nunca le darás a todos exactamente lo que quieren. Así que haga una rutina que sea simple para casos simples, y no se moleste en tratar de hacer una rutina que cubra todos los posibles casos de uso: uno puede acceder directamente al hardware para eso.     

respondido por el Jim Paris

Lea otras preguntas en las etiquetas