Autor Tema: Problema con encoder óptico  (Leído 2668 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado noral

  • PIC10
  • *
  • Mensajes: 17
Problema con encoder óptico
« en: 23 de Octubre de 2014, 14:30:12 »
Hola compañeros,

Estoy desarrollando un pequeño proyectillo con un encoder óptico (Avago HEDS-9740-150) y un disco codificado. Para ello utilizo un PIC16F874 y el compilador CCS.

Me he construido una maqueta para que tanto el disco como el encoder estén siempre fijos (en el caso del disco lo que está fijo es el eje) y tener el mínimo error de lectura posible.

El problema radica en que el contador de pulsos tan solo incrementa (sentido del giro horario, por ejemplo) pero no decrementa cuando hago girar el disco en sentido contrario.

El código lo he extraído de un proyecto que encontré (https://sites.google.com/site/proyectosroboticos/encoder/encoder-por-software/encoder-con-un-16f876).

La conexión de los pines es la siguiente:

ENCODER          PIC
GND                  GND
CHA                   RB0/INT
+5v                   +5V
CHB                   RB1


Os dejo el código:

Código: [Seleccionar]
#include <16F874.h>
#device adc=10
#FUSES NOWDT                  //No Watch Dog Timer
#FUSES HS                    //High-speed OSC
#FUSES PUT                    //Power Up Timer
#FUSES NOPROTECT              //Code not protected from reading
#FUSES NOLVP                  //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                  //No EE protection
#FUSES NOWRT                  //Program memory not write protected
#FUSES NOBROWNOUT            //No brownout reset
#FUSES NODEBUG                //No Debug mode for ICD
#use delay(clock=8000000)

#Byte PortB = 0x06              // Dirección del puerto B

#include <flex_lcd.c>

// ------ Variable Global ------
signed int16   x = 0;
signed int16   y = 0;

// --------- Interrupción ---------
#Int_Ext                        // Interrupción Externa por RB0: Decodificación de Encoder.

void IntRB0()
{
   // CCS se encarga de desactiva automáticamente cualquier interrupción.
   // No hace falta guardar contextos de registros por que CCS se encarga de hacerlo por ti.

    if (bit_test(PortB,1)){      // Si RB0 se ha puesto a 1 (flanco de subida),
        ext_int_edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de bajada.
        if (bit_test(PortB,1)){  // Si RB1 está a 1,
            x++;                 // entonces incrementar una unidad el valor de X.
            y--;                 // entonces decrementar una unidad el valor de Y.
        }
    }
    else{                        // Si RB0 se ha puesto a 0 (flanco de bajada),
        ext_int_edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de subida.
        if (bit_test(PortB,1)){  // Si RB1 está 1,
            x--;                 // entonces decrementar una unidad el valor de X.
            y++;                 // entonces incrementar una unidad el valor de X.
        }
    }
   
    // Al finalizar la interrupción CCS se encarga de volver a poner automáticamente
    // la badera INTF = 0 ---> borra la interrupción para poder permitir la siguiente.
    // No hemos de hacer nada por nuestra parte.
}

void main()                     // Inicio y configuración.
{

   lcd_init();
   delay_ms(100);
   lcd_gotoxy(1,1);
   PORT_B_PULLUPS(FALSE);       // Configuración para el PIC 16F874A.
   setup_adc_ports(NO_ANALOGS); // Sin comparadores ni ADCs, todo digital, etc...
   setup_adc(ADC_CLOCK_DIV_2);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);

   ext_int_edge(L_TO_H);        // Inicialmente detectar interrupción por flanco de subida.
   enable_interrupts(INT_EXT);  // Activar Interrupción Externa.
   enable_interrupts(GLOBAL);   // Interrupciones Generales Activadas.

   set_tris_b(0b11111111);      // Puerto B todo entradas (sólo usamos las entradas RB0 y RB1).

   // ---------- Programa Principial ----------

   while (TRUE)
   {
        lcd_gotoxy(1,1);
        printf(lcd_putc,"x = %ld",x);            // El valor de X sale por la LCD
        printf(lcd_putc,"\ny = %ld",y);          // El valor de Y sale por la LCD
   }

}

Desconectado juanpi2908

  • PIC12
  • **
  • Mensajes: 54
Re: Problema con encoder óptico
« Respuesta #1 en: 23 de Octubre de 2014, 16:19:45 »
Hola par
"La gran sabiduría esta en sentirse satisfecho con poca cosa; quien aumenta sus riquezas aumenta sus cuidados; pero una mente contenta es un tesoro oculto a quien no alcanzan las calamidades"

Desconectado willynovi

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 546
Re: Problema con encoder óptico
« Respuesta #2 en: 23 de Octubre de 2014, 23:08:01 »
Hola, no estoy familiarizado con CCS, pero creo que el error lo tienes

Código: [Seleccionar]
if (bit_test(PortB,1)){      // Si RB0 se ha puesto a 1 (flanco de subida),
así chequeas el estado de RB1, y no RB0 como quieres

deberia ser
Código: [Seleccionar]
if (bit_test(PortB,0)){      // Si RB0 se ha puesto a 1 (flanco de subida),
lo demas creo que estaria bien.

slds.
Intento enseñarte a pescar, si solo quieres pescados, espera que un pescador te regale los suyos.

Desconectado noral

  • PIC10
  • *
  • Mensajes: 17
Re: Problema con encoder óptico
« Respuesta #3 en: 24 de Octubre de 2014, 12:30:38 »
Correcto willynovi  ((:-)) ((:-))

Fallo en la escritura que pasé por alto al repasarlo.


Ahora se me ocurre otra pregunta (seguramente pregunta de novato  :oops: ). Cuando hago girar el disco codificado muy rápido no le da tiempo a mi pic a contar todos los pulsos.

Hay alguna posibilidad de incrementar esta frecuencia de conteo? Tiene algo que ver el oscilador que utilizo (8 MHz) ?

Gracias de antemano.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Problema con encoder óptico
« Respuesta #4 en: 24 de Octubre de 2014, 12:48:15 »
Correcto willynovi  ((:-)) ((:-))

Fallo en la escritura que pasé por alto al repasarlo.


Ahora se me ocurre otra pregunta (seguramente pregunta de novato  :oops: ). Cuando hago girar el disco codificado muy rápido no le da tiempo a mi pic a contar todos los pulsos.

Hay alguna posibilidad de incrementar esta frecuencia de conteo? Tiene algo que ver el oscilador que utilizo (8 MHz) ?

Gracias de antemano.


Primero si tuviera un osciloscopio observaria si el encoder optico es capaz de seguir el disco,es decir que exista una salida del mismo al PIC, si tengo salida es tema del PIC.

Si es el PIC:
Solucion simple es aumentar el valor del cristal al maximo que pueda el PIC obviamente.
Si aun asi no llegas probaria usando la rutina de interrupcion con instrucciones en ASM (ya que es la unica parte de vital importancia en tiempo), de esa forma tardar lo menos posible ( y si es que agrega mucho codigo el C, sino no vale la pena )
De todas formas me parece mejor la del cristal a 20Mhz :)

// EDIT

Leyendo el datasheet del encoder:
Código: [Seleccionar]
Recommended Operating Conditions
Count Frequency: 40 kHz   (Velocity (rpm) x N) / 60

Count (N) = the number of bar and window pairs or Counts
Per Revolution (CPR) of the codewheel, or the number of
Lines Per Inch (LPI) of the codestrip

Probaria el encoder primero
« Última modificación: 24 de Octubre de 2014, 12:58:14 por KILLERJC »


 

anything