Codificador rotatorio STM32 con interrupciones de hardware

3

Estoy tratando de obtener un codificador rotatorio trabajando en mi STM32.

  1. Tengo el canal A & B se elevó a 3V y se lanzó con condensadores 1uF.
  2. La placa tiene un canal A y amp; B conectado a PA11 y amp; PA10 respectivamente y han configurado interrupciones de hardware para ambos
  3. He probado varios algoritmos diferentes para decodificar la dirección de rotación, pero no importa lo que haga, no puedo obtener interrupciones alternas consistentes (es decir, ABABAB)
  4. Intenté disparar en ambos bordes, solo caí, solo subí y no importa de qué recibo, las interrupciones se activan de forma aleatoria.

¿Hay algo que estoy haciendo mal? ¿Las interrupciones no son suficientes para mantener la velocidad del codificador? ¿No es suficiente el debouncing (se ve bien en un alcance, pero tal vez las interrupciones son más sensibles)? ¿Hay una mejor manera de hacer esto en general? He estado atrapado en esto por un tiempo, así que cualquier ayuda sería genial. Déjame saber si es necesaria más información.

* Código editado para reflejar cambios (algoritmo de trabajo)

MANEJADOR DE INTERRUPCIÓN

static int8_t states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
uint8_t RotaryCurrentState = 0x00;
uint8_t RotaryTransition = 0;
int8_t RotaryPosition = 0;

/*Rotary Encoder Interrupt Handler
Channel A (IRQ11) & B (IRQ10)

              CW --->
 A (IRQ11)  ¯|___|¯¯¯¯|___|¯¯¯¯
 Interrupts  ^   ^    ^   ^
 B (IRQ 10) ¯¯¯|___|¯¯¯¯¯|___|¯
 Interrupts    ^   ^     ^   ^
                  CCW <---

void EXTI4_15_IRQHandler(void)
{ 
  RotaryCurrentState = (Read_IO(ROTARY_A) << 1) | Read_IO(ROTARY_B);
  RotaryTransition = (RotaryTransition <<2 ) | RotaryCurrentState;
  RotaryPosition = RotaryPosition + states[RotaryTransition & 0x0F];

  EXTI_ClearITPendingBit(EXTI_Line10);  //Clear Channel B
  EXTI_ClearITPendingBit(EXTI_Line11);  //Clear Channel A
}

MAIN.C

//Initialize 
RotaryTransition = Read_IO(ROTARY_A) << 3 | Read_IO(ROTARY_B) << 2 | \
                   Read_IO(ROTARY_A) << 1 | Read_IO(ROTARY_B);

while(1)
{
  //CW Transition
  if (RotaryPosition == 4)
  {
    STM_EVAL_LEDToggle(LED4);
    RotaryPosition = 0;
  }
  //CCW Transition
  else if (RotaryPosition == -4)
  {
    STM_EVAL_LEDToggle(LED3);
    RotaryPosition = 0;
  }
}
    
pregunta spizzak

1 respuesta

6

Eso no es un gran algoritmo en tu controlador. Usted debe tener cero sis. No hay decisiones.

Almacene su estado AB, es decir, 00 o 01, luego agregue su próximo estado, es decir, 0001 significa que AB pasó de 00 a 01, por lo que B cambió de 0 a 1. Haga de esto un +1. Si comienza desde 00, y cambia a 10, llame a esto un -1. Cree una matriz de 16 elementos de todas las transiciones posibles que contengan el número que debe agregarse a su conteo si ocurre, observando que algunas son ilegales y deben ser manejadas.

0000       0    0  no transition


0001       1   +1

0010       2   -1

0011       3    0   Illegal, two transitions,  and so on.

Indexe esta matriz en cada transición, observe los eventos ilegales y trate con ellos como mejor le parezca. Agregue el resultado al conteo. Cambie los valores nuevos al punto de valor anterior en el número de índice y repita para siempre

En Pseudocódigo

 signed int8 add_subt[16] = { 0, 1 ,-1 ,  ....};
 unsigned int8 idx;
 signed int32 pos_count;

main() {
% initialize idx
idx = readA <<3 + readB<<2 + readA<<1 + readB;
while(1){}
}

interrupt_on_any_change(){
idx=idx<<2 & 0x0F + readA<<1 + readB;
pos_count=pos_count+add_subt[idx];
}

Puedes mantener err_idx para ayudarte a marcar las transiciones erróneas

¿No parece eso un pelo más simple?

    
respondido por el Scott Seidman

Lea otras preguntas en las etiquetas