PIC Encoder con un 16F628A.

El funcionamiento de este lector de encoder es extremadamente sencillo. Un bucle se encarga de comprobar el estado de las entrada RA0 y RA1 (A y B respectivamente en el gráfico de abajo) en el menor tiempo posible. En condiciones normales la velocidad de lectura suele rondar unas 25.000 veces por segundo para un cristal de 4MHz dependiendo de la longitud del programa. Esto es más que suficiente para poner el encoder directo al eje de la mayoría de los motores, para un máximo de 12 pulsos por vuelta del motor que es hasta donde yo he probado. Aunque con 4MHz funciona perfecto, aumentando la frecuencia del cristal conseguirás incrementar la velocidad de lectura. Siempre y cuando el PIC permita frecuencias mayores, con 8MHz doblarás la velocidad de lectura, con 12MHz la triplicarás (...), con 20MHz la quintuplicarás. Cada aumento de 4MHz incrementas una vez el factor de multiplicación y esto es debido a que una instrucción en ensamblador necesita 4 ciclos de reloj para ejecutarse.

Como puedes ver en la imagen, hemos de detectar cuándo hay un flanco de subida o de bajada en la entrada 'A' (un cambio de estado) siempre que 'B' esté a '1'. Si A es el bit bajo (LSB) y B es el bit alto (MSB), al considerar los dos bits como un número tenemos que si hubo un cambio de 2 (10 en binario) a 3 (11 en binario), se ha producido un flanco de subida, por tanto hemos de incrementar el contador. Y al revés, cuando el PIC detectar que en las entradas hubo un 3 (11 en binario) y pasa a 2 (10 en binario), es decir, un flaco de bajada, ha de decrementar el contador. En el programa para el PIC el valor 'anterior' se almacena en la variable AUX, y el valor 'actual' se almacena en la variable ENC; la variable que hace de contador se llama X.

A continuación tienes los programas en CCS C y en Pronton IDE. Haciendo clic aquí verás el código para un 16F84A en Proton IDE; el esquema sigue siendo el mismo porque ambos PICs son idénticos, aunque el 16F628A tiene más funciones internas.

Programa PIC Encoder con 16F628A en CCS:

The translation could modify the code. Use the code without translating.
#include <16F628A.h>
#FUSES NOWDT, XT, PUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD
#use delay(clock=4000000)
#byte porta = 0x05        // Asignamos PortA.
#byte portb = 0x06        // Asignamos PortB.
// ---------- Programa Principial ----------
void main()
{
   port_b_pullups(FALSE);                   // Sin resistencias pullups a las salidas del puerto B.
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // Al no usar el TIMER configuramos lo más básico. 
   setup_comparator(NC_NC_NC_NC);           // Sin comparadores.
   setup_vref(FALSE);                       // Al no usar comparadores no necesitamos Vref.  
   
   //---- Fin de la configuración del 16F628A ----
   int8   x;    // Declaramos el valor de X como byte, se corresponderá con los 8 LEDs de salida.
   int8   enc;  // Se almacenará el valor actual de RA0 y RA1, hasta la siguiente comparación.
   int8   aux;  // Se almacenará el valor anterior de RA0 y RA1, hasta la siguiente comparación.
   set_tris_a(0b11111);     // Puerto A como entradas. Sólo usamos RA0 y RA1.
   set_tris_b(0b00000000);  // Puerto B como salidas, para los 8 LEDs.
   
   portb=0;   // Inicialmente ponemos a cero el puerto B.
   x=0;       // Inicialmente ponemos a cero la variable que se usa para contar.
   enc=0;     // Inicialmente ponemos a cero la variable que tomará los valores de RA0 y RA1.
   
   while (true)
   {
          aux=enc;               // Igualamos 'AUX' y 'ENC' para luego comparar cuando cambie 'ENC'.
          enc=porta & 3;         // Aislamos RA0 y RA1 como un número de 2 bits y se carga en la
                                    variable 'ENC'.
          
          if ((aux==2)&&(enc==3))// Si en la comparación hay flanco de subida,
          {  
              x++;               // entonces incrementar una unidad el valor de X.
          }
          
          if ((aux==3)&&(enc==2))// Si en la comparación hay flanco de bajada,
          {  
              x--;               // entonces decrementar una unidad el valor de X.
          }
          
          portb = x;             // El valor de X sale por el puerto B, los 8 LED de salida.
   }
              
}

Programa PIC Encoder con 16F628A en Proton IDE:

The translation could modify the code. Use the code without translating.
Device=16F628A
REMINDERS = False
Config XT_OSC, PWRTE_ON, CP_OFF, WDT_OFF, BODEN_OFF, LVP_OFF
REMINDERS = True
ALL_DIGITAL = True ' Entradas/Salidas todas digitales.
TRISA = %11111     ' Puerto A como entradas. Sólo usamos RA0 y RA1.
TRISB = %00000000  ' Puerto B como salidas, para los 8 LEDs.
PORTB=0            ' Inicialmente ponemos a cero el puerto B.
Dim x As Byte      ' Declaramos el valor de X como byte, se corresponderá con los 8 LEDs de salida.
Dim Aux As Byte    ' Se almacenará el valor anterior de RA0 y RA1, hasta la siguiente comparación.
Dim Enc As Byte    ' Se almacenará el valor actual de RA0 y RA1, hasta la siguiente comparación.
x=0                ' Ponemos todas las variables a cero.
Aux=0 
Enc=0 

While 1=1          ' Bucle infinito. 
  Aux = Enc     ' Igualamos 'AUX' y 'ENC' para luego comparar cuando cambie 'ENC'.
  Enc = (PORTA & 3) ' Aislamos RA0 y RA1 como un número de 2 bits y se carga en la variable 'ENC'.
  If Aux = 2 And Enc = 3 Then Inc x ' Si en la comparación hay flanco de subida, incrementamos X. 
  If Aux = 3 And Enc = 2 Then Dec x ' Si en la comparación hay flanco de bajada, decrementamos X.
  PORTB = x         ' El valor de X sale por el puerto B, los 8 LED de salida.
Wend
End

Buscando la sencillez para comprender mejor el funcionamiento del programa, el lector de encoder está limitado a una resolución de 8 bits. Si añades unas pocas líneas de programación podrás aumentar la resolución hasta 11 bits (para el 16F628A y el 16F84A, en otros PICs podría ser más) aprovechando las patillas que no se usan como bits de salidas.

Este programa te permite aumentar la resolución del lector de encoder hasta un factor de por cuatro (x4). Para ver cómo se hace cliquea aquí.

Si usas sensores Hall digitales no te hará falta el acondicionador y podrás inyectar las señales del encoder directamente al PIC.

Y los encoders mecánicos, en principio lo puedes colocar directamente y sin el acondicionador de las señales.

Para cualquier tipo de duda sobre la construcción o utilización de un encoder, haz clic aquí.