Pregunta

Tengo problemas para que un codificador rotatorio funcione correctamente con los microcontroladores AVR.El codificador es mecánico. Codificador ALPS, y estoy usando Atmega168.

Aclaración

Intenté usar una interrupción externa para escuchar los pines, pero parece que es demasiado lento.Cuando el Pin A sube, el procedimiento de interrupción comienza y luego verifica si el Pin B está alto.La idea es que si el Pin B está alto en el momento en que el Pin A subió, entonces gira en el sentido contrario a las agujas del reloj.Si el Pin B está bajo, entonces gira en el sentido de las agujas del reloj.Pero parece que el AVR tarda demasiado en comprobar el Pin B, por lo que siempre se lee como alto.

También intenté crear un programa que simplemente se bloquee hasta que cambie el Pin B o el Pin A.Pero puede ser que haya demasiado ruido al girar el codificador, porque esto tampoco funciona.Mi último intento fue tener un temporizador que almacene los últimos 8 valores en un búfer y verifique si va de menor a mayor.Esto no funcionó bien.

Intenté determinar el alcance del codificador y parece usar entre 2 y 4 ms desde el primer cambio de Pin hasta que cambia el otro Pin.

¿Fue útil?

Solución

tengo una pagina web sobre Codificadores rotativos y cómo usarlos., que puede resultarle útil.

Lamentablemente, sin más información no puedo solucionar su problema particular.

¿Qué pines del microcontrolador están conectados al codificador y cuál es el código que estás usando actualmente para decodificar los pulsos?

Ok, estás lidiando con algunos problemas diferentes, el primer problema es que se trata de un codificador mecánico, por lo que tienes que lidiar con el ruido del interruptor (rebote, vibración).El ficha de datos indica que las piezas pueden tardar hasta 3 ms en dejar de rebotar y crear resultados falsos.

Necesitas crear una rutina antirrebote.La más sencilla es comprobar continuamente si A sube.Si es así, inicie un cronómetro y compruébelo nuevamente en 3 ms.Si todavía está alto, entonces puede marcar B; si no está alto, entonces ignora el pulso espurio y continúa buscando A alto.Cuando marca B, lo mira, inicia un temporizador durante 3 ms y luego mira B nuevamente.Si fue el mismo ambas veces, entonces puede usar ese valor; si cambia en 3 ms, deberá hacerlo nuevamente (lea B, espere 3 ms, luego léalo nuevamente y vea si coincide).

Atmega es lo suficientemente rápido como para que no tengas que preocuparte de que estas comprobaciones vayan lentamente, a menos que también estés ejecutando una velocidad de reloj lenta.

Una vez que lidia con el ruido mecánico, entonces desea ver una rutina de código gris adecuada: el algoritmo que está siguiendo no funcionará a menos que también disminuya si A es alto cuando B baja.Generalmente, las personas almacenan el último valor de las dos entradas y luego lo comparan con el nuevo valor de las dos entradas y usan una pequeña función para incrementar o disminuir en función de eso.(Consulte el título "lectura de alta resolución" en el sitio web que mencioné anteriormente para ver la tabla).Combino las dos lecturas en un número de cuatro bits y uso una matriz simple para indicarme si incremento o disminuyo el contador, pero hay soluciones que son aún más avanzadas y optimizan el tamaño del código, la velocidad o la facilidad de mantenimiento del código.

Otros consejos

Agregar un filtro de paso bajo analógico mejora enormemente la señal.Con el filtro de paso bajo, el código del AVR era realmente simple.

       _________
        |         |
        | Encoder |
        |_________|
          |  |  |
          |  |  |
     100n |  O  | 100n  
 GND O-||-+ GND +-||-O GND
          |     | 
          \     /
      3K3 /     \ 3K3
          \     /
          |     |    
VCC O-/\/-+     +-\/\-O VCC
     15K  |     |  15K
          |     |
          O     O
          A     B

Ah, las maravillas del arte ASCII :p

Aquí está el programa del AVR.Conecte A y B para ingresar PORTB en el avr:

#include <avr/io.h>

#define PIN_A (PINB&1)
#define PIN_B ((PINB>>1)&1)

int main(void){
    uint8_t st0 = 0;
    uint8_t st1 = 0;
    uint8_t dir = 0;
    uint8_t temp = 0;
    uint8_t counter = 0;
    DDRD = 0xFF;
    DDRB = 0;
    while(1){   
    if(dir == 0){
        if(PIN_A & (!PIN_B)){
            dir = 2;
        }else if(PIN_B & (!PIN_A)){
            dir = 4;
        }else{
            dir = 0;
        }
    }else if(dir == 2){
        if(PIN_A & (!PIN_B)){
            dir = 2;
        }else if((!PIN_A) & (!PIN_B)){
            counter--;
            dir = 0;
        }else{
            dir = 0;
        }
    }else if(dir == 4){
        if(PIN_B & (!PIN_A)){
            dir = 4;
        }else if((!PIN_A) & (!PIN_B)){
            counter++;
            dir = 0;
        }else{
            dir = 0;
        }
    }else if(PIN_B & PIN_A){
        dir = 0;
    }
        PORTD = ~counter;
    }
    return 0;
}

Este código funciona a menos que gires el codificador muy rápido.Entonces podría perder uno o dos pasos, pero eso no es importante, ya que la persona que usa el codificador no sabrá cuántos pasos lo ha girado.

La velocidad no debería ser un problema.La mayoría de los interruptores mecánicos necesitan rutinas antirrebote.Si desea hacer esto con interrupciones, apague la interrupción cuando se active, inicie un temporizador que la volverá a encender después de un par de ms.Mantendrá su programa libre de encuestas >:)

¿Con qué tienes problemas exactamente?Supongo que ha podido conectar los pines del codificador a su PIC según las especificaciones técnicas vinculadas en la página de Farnell que proporcionó, entonces, ¿el problema es la lectura de los datos?¿No obtienes ningún dato del codificador?¿No sabes cómo interpretar los datos que estás recibiendo?

/* into 0 service rutine */
if(CHB)
{
  if(flagB)
   Count++;
  FlagB=0;
}
else
{
  if(FlagB)
   count--:
  FlagB=0:
}

/* into 1 service rutine */
FlagB=1;

/* make this give to you a windows time of 1/4 of T of the encoder resolution
   that is in angle term: 360/ (4*resolution)
 */
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top