¿Puede medir la frecuencia a través de interrupciones cuando los pines son utilizados por un codificador? SMT32F4

2

Para calcular la velocidad actual, una opción es leer la posición actual cada 20 ms. La velocidad promedio es position_old minus position_current. Esto funciona bien si hay muchos pulsos por 20 ms pero a velocidades bajas, la precisión disminuye. Una vez que obtengas velocidad = 0, luego velocidad = 2 y luego velocidad = 0 nuevamente.

El mejor enfoque sería medir el tiempo entre flancos ascendentes. Esto le proporciona la hora exacta, por lo tanto, la velocidad.

  • ¿Pero puedes tener dos temporizadores activos en los mismos pines? Entonces, Input Capture sería el camino a seguir.
  • ¿Puede configurar un ISR para disparar en el flanco ascendente mientras el temporizador se utiliza como codificador? Entonces puedo usar los systicks para derivar la velocidad.

Estoy usando TIM5 CH1 & 2 en PA0 & 1.

(Obviamente podría conectar el pin de entrada a otro pin de MCU y hacer la medición allí, pero no me gusta esa solución).

enlace

    
pregunta Werner Daehn

1 respuesta

1

Hice algunas más pruebas y lecturas y encontré la solución:

  1. En lugar de HAL_TIM_Encoder_Start (), use HAL_TIM_Encoder_Start _IT (). Ambos ejecutan el mismo código, excepto que este último también se prepara para las interrupciones.
  2. Habilita la interrupción: HAL_NVIC_SetPriority (TIM5_IRQn, 0, 1); HAL_NVIC_EnableIRQ (TIM5_IRQn);
  3. Implementar el void TIM5_IRQHandler (void) {HAL_TIM_IRQHandler (& htim5); } para que haya un controlador de interrupciones que reenvíe la interrupción a la capa HAL.
  4. Implemente (o amplíe) la función de devolución de llamada HAL_TIM_IC_CaptureCallback (TIM_HandleTypeDef * htim) y agregue su código.

En mi caso, el código es

if (htim->Instance == TIM5)
  {
    last_possensortick = HAL_GetTick();
    possensorduration = last_possensortick - possensortick_old;
    possensortick_old = last_possensortick;
  }

Así que almaceno el tiempo entre dos interrupciones y la velocidad = 1 / tiempo. Casi. Solo casi porque la interrupción se dispara en un solo pin y el tiempo debe ser entre eventos idénticos, por lo tanto, se dispara solo en un flanco ascendente.

Por otra parte, el codificador está configurado como codificador X4 (sConfig.EncoderMode = TIM_ENCODERMODE_TI12;), por lo que la posición se actualiza en ambos flancos y en ambos canales. vea la página 29 en AN4013

Por lo tanto, la velocidad = 4 / tiempo en lugar de 1 / tiempo.

Y se necesita algo de lógica adicional si el tiempo = 0 y si la interrupción no se dispara porque la rueda no se mueve en absoluto. Esa es la razón por la que almaceno tanto la duración como la última marca. Si lasttick > 2000 entonces velocidad = 0;

La lógica anterior funciona solo para bajas velocidades. A altas velocidades, la resolución de milisegundos y el tiempo de ejecución de la interrupción crean más y más errores. Por lo tanto, usaré ambas entradas de velocidad, the speed = old_pos-current_pos; y la velocidad = 4 / duración;

    
respondido por el Werner Daehn

Lea otras preguntas en las etiquetas