Hice algunas más pruebas y lecturas y encontré la solución:
- 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.
- Habilita la interrupción: HAL_NVIC_SetPriority (TIM5_IRQn, 0, 1); HAL_NVIC_EnableIRQ (TIM5_IRQn);
- 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.
- 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;