Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos
Foros Registrarse ¿Olvidaste tu contraseña?

Temas similares

27/03/2014 #1


Programacion de Odometro
Buenos dias compañeros del foro, pues ahora estoy realizando un proyecto que consiste en que por medio de un encoder rotacional(COM-10596)pueda medir distancias, el problema con el que me enfrento actualmente es que al momento que obtengo mis salidas de señal del encoder( que son dos, A y B) no me se me ocurre como programar en mi pic(16f877a) para que se de cuenta que voy avanzando o retrociendo el encoder, vi en la pagina del fabricante un programa para arduino mas sin embargo no entiendo muchas cosas, ya que nunca he manejado arduino.
Use un flip flop tipo D, pero no tuve mucho exito. Espero puedan ayudarme a resolver este problema. Ademas anexo mi codigo para que lo vean.
27/03/2014 #2
Moderador general

Avatar de Fogonazo

ThaConectted dijo: Ver Mensaje
Buenos dias compañeros del foro, pues ahora estoy realizando un proyecto que consiste en que por medio de un encoder rotacional(COM-10596)pueda medir distancias, el problema con el que me enfrento actualmente es que al momento que obtengo mis salidas de señal del encoder( que son dos, A y B) no me se me ocurre como programar en mi pic(16f877a) para que se de cuenta que voy avanzando o retrociendo el encoder, vi en la pagina del fabricante un programa para arduino mas sin embargo no entiendo muchas cosas, ya que nunca he manejado arduino.
Use un flip flop tipo D, pero no tuve mucho exito. Espero puedan ayudarme a resolver este problema. Ademas anexo mi codigo para que lo vean.
Justamente, las 2 salidas por su diferencia de "Fase" permiten interpretar el sentido de avance o retroceso.
27/03/2014 #3


Si exacto, entiendo eso. Pero a lo que voy es esto, van desfasadas, pero una se activa mientras la otra aún tiene un pulso alto, mientras A esta en 5v a la mitad de su ciclo, se activa B. Entonces ahí mi duda es, debido a que no se activa una primero y después la otra si no a la mitad, entonces como podría decirle yo a mi pic, si A se activa primero y B después incrementa, de lo contrario disminuye. Por eso comentaba que pensé en un usar un flip flop tipo D pero no me funciono para así predecir el próximo estado. Y por so preguntaba acerca de esa duda.ImageUploadedByTapatalk1395929640.645396.jpg
A manera ilustrativa coloco una imagen a ver si pueden entender el problema que tengo.
27/03/2014 #4


Mira con atención el dibujo y verás que cuando va en sentido horario los flancos de B siempre preceden a los de A y en sentido antihorario es al revés. Entonces sólo es cuestión de revisar cuál cambió de estado primero y eso te dice en qué sentido está girando.

Supongamos que está en reposo y B está en alto y A en bajo, si en la siguiente lectura A está en alto entonces está girando en sentido horario porque B precedió a A.
27/03/2014 #5


Entonces una posible solución podría ser leer los dos canales analógicos al mismo tiempo? Y en base al que se mueva primero indicar la dirección?
27/03/2014 #6


Sería más fácil leer el estado lógico y comparar la secuencia binaria del encoder. Por ejemplo si asignamos el bit 0 a la salida A y el bit 1 a la salida B la secuencia sería 2, 3, 1, 0 en sentido horario y al revés en sentido antihorario.
28/03/2014 #7


El encoder entrega 0 o 5 volts, entonces como podía hacer la asignación que me comentas?
28/03/2014 #8


Hola ThaConectted

Mirando la imagen en tu mensaje #3 se puede determinar que si se genera primero B por el PIN 3 del encoder es que éste ha sido girado en el sentido de las manecillas del reloj (CW).
Por el contrario, si se genera primero A por el PIN 2 del encoder es que éste ha sido girado en el sentido contrario a las manecillas del reloj (CCW).

Entonces: la terminal 1 del encoder se conectaría al Vcc.
La terminal 2 se conectaría a un puerto del PIC y la terminal 3 a otro puerto del PIC.

Y:
Si 3 = 1
contar + 1

si 2 = 1
contar –1

Pero si no llega ninguno es que no se ha movido.

Cada que 3 = 1 se debe contar +1.
Cada que 2 = 1 se debe contar –1.

saludos
a sus ordenes
Imágenes Adjuntas
Tipo de Archivo: jpg Encoder.jpg (53,5 KB (Kilobytes), 15 visitas)
Tipo de Archivo: jpg Flow Diagram.jpg (41,5 KB (Kilobytes), 18 visitas)
28/03/2014 #9
Moderador general

Avatar de Fogonazo

En el esquema que publique puedes ver como se detecta el sentido de giro empleando un Flip-Flop


La salida del Flip-Flop la mandas al PIC, una da los pulsos de conteo y la otra el sentido de giro CW o CCW

El odometro de los automóviles siempre cuanta ascendente, NO descuenta, aunque vaya hacia atrás
28/03/2014 #10


Muchas gracias, ya hize el contador, mas sin embargo me hace los cambios muy lentamente. A lo que voy es que cuando regreso hasta la segunda o tercera vuelta me regresa el contador,como podria hacer para que ese contador detecte el cambio mas rapido? y como podria traducir eso a una distancia?
Archivos Adjuntos
Tipo de Archivo: txt OdometroA.txt (880 Bytes, 25 visitas)
28/03/2014 #11


Hola ThaConectted

Analiza la imagen que adjuntaste en tu mensaje #3. notarás que ese encoder hace un cambio cada 90° de giro.

Eso quiere decir que no tiene mucha resolución. Sería mejor un encoder que te diera un cambio de estado en sus salidas cada 5° de giro.

saludos
a sus ordenes.
28/03/2014 #12


si tienes mucha razon,creo que es un problema, tratare de buscar uno mejor. Una pregunta mas, quiero seguir tratando de acomodar este, y por eso dentro de la programacion estoy colocando el contador pero este sigue avanzando siempre! hay alguna forma de que avanze y se quede esperando, y ya despues sume o reste dependiendo del estado?
29/03/2014 #13


Hola ThaConectted

Lo que ocurre con tu programa:

set_adc_channel(0);
delay_us(20);
A=read_adc(); NO debes leerlo como ANALOGO sino como Digital 1 o 0.
set_adc_channel(1);
B=read_adc(); NO debes leerlo como ANALOGO sino como Digital 1 o 0.
delay_us(20);
setup_adc(adc_off);

if(A>=220) Aquí debería ser: if(A=1)
{
contador=contador+1;
}

if(B>=220) Aquí debería ser: if(B=1)
{
contador=contador-1;
}

printf(lcd_putc,"%02.1f",contador);
delay_ms(1000);

además, antes de entrar a este bucle, debes declarar esos puertos como Digitales, o sea NO análogos.
O utilizar otros puertos que solo sean digitales.
Es probable que con eso se solucione el problema.

Otra cosa, me parece que estás tomando A y B en el otro sentido.
Ya que si A = 1 debe contar –1 y si B = 1 debe contar +1.

Pero te advierto yo casi no se de programación.

No se si se pudiera hacer por medio de interrupciones: si interrumpe A cuenta –1, si interrumpe B cuenta +1.
Dale una visitada a este enlace, tal vez tenga algo que te sirve:
http://www.forosdeelectronica.com/f24/maneja-encoder-pic-19542/

saludos
a sus ordenes
29/03/2014 #14

Avatar de Gudino Roberto duberlin

Hola, viendo el programa, puede que no funcione cómo uno lo espera.
Si analizamos las sig. líneas vemos que:

if(A>=220) Aquí debería ser: if(A=1)
{
contador=contador+1;
}

if(B>=220) Aquí debería ser: if(B=1)
{
contador=contador-1;
}

Cuando A es 1 incrementa contador, luego cuando B es 1 decrementa, verdad?
Pues si vemos la gráfica, del encoder podemos ver, cómo ocurren las señales, y es así:
Por cada avance ocurren dos flancos ascendentes, uno por parte de A y el otro en B.
Entonces el contador se incrementa y decrementa sin poder moverse más allá de ese valor
entonces debemos condicionar la sentencia if, algo así:

if(A==1 && B==0 ) contador=contador+1;

if(A==1 && B==1) contador=contador-1;

Porque esto?, pues en un sentido cada vez que ocurre un flanco ascendente en A, B valdrá 1 por ejem. y siempre será así. Pero en el sentido opuesto, cuando ocurre el flanco ascendente en A, B vale 0. De ésta manera se determina el sentido de giro y la acumulación de la variable "contador".
Debe tenerse en cuenta los posibles desbordes de dicha variable, es decir, si contador=0 no podemos continuar decrementando y lo mismo ocurre si alcanza su max. valor, no podemos continuar incrementando.
En éste caso como leemos valores digitales, no tiene sentido utilizar el ADC para determinar un nivel y considerarlo cómo L o H. Sólo lee el valor del puerto.
29/03/2014 #15


Ok, creo que tienes razón déjame probarlo y te informo que obtuve

---------- Actualizado después de 21 minutos ----------

Acabo de probarlo si inicia el contador más sin embargo no logró detener el contador, ya que se sigue avanzando,ya sea hacia adelante o atrás.
29/03/2014 #16

Avatar de Gudino Roberto duberlin

Bueno eso sucede porque detectas nivel en lugar de flanco, piensa cómo puede hacerse para que una vez que se realice una cuenta no vuelva a contar hasta que el flanco se produzca otra vez.
29/03/2014 #17


Pues una opción es la que ponía fogonazo arriba conectarlo al flip flop, pero lo conecto y sigue detectando nivel. Lo estoy tratando de hacer programado todo por medio de software pero no se bien como implementarlo. He leído que por interrupciones pero no tengo un ejemplo claro de como usarlas, podrían apoyarme con algún buen ejemplo, para entender?

Listo, como no pude acomodar por medio de hardware mi encoder decidi empezar a hacerlo por medio de software, junto con los links que estuve viendo, aunque ahora me surge una duda en el codigo que anexo estoy obteniendo una salida de 8 bits de que forma podria manipularla para colocarla a un LCD y que me muestre el avanze y retroceso?

Código:
#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.  
   }
              
}
29/03/2014 #18


Vas muy bien con tu programa, pero le faltan más comparaciones:

Código:
#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'.

//acuérdate que la secuencia de valores es 0, 2, 3, 1 cw y 0, 1, 3, 2 ccw

     if(aux==0){
               if (enc==2){x++;}
               else if (enc==1){x--;}
     }
     else if(aux==1){
               if (enc==0){x++;}
               else if (enc==3){x--;}
     }
     else if(aux==2){
               if (enc==3){x++;}
               else if (enc==0){x--;}
     }
     else if(aux==3){
               if (enc==1){x++;}
               else if (enc==0){x--;}
     }

portb = x; // El valor de X sale por el puerto B, los 8 LED de salida.
}
}
O se podría hacer de la siguiente manera usando el operador xor ^ lo que se te haga más conveniente. Nota que si el xor da como resultado 0 significa que el encoder no ha cambiado de estado.

Código:
if ((aux==0)||(aux==3)){
     aux=aux^enc;
     if(aux==2){
          x++;
     }
     else if(aux==1){
          x--;
     }
}
else{
     aux=aux^enc;
     if(aux==2){
          x--;
     }
     else if(aux==1){
          x++;
     }
}
29/03/2014 #19


Muchas gracias eso que me dices no lo sabia, oye pero una pregunta sabes como puedo hacer para que esos bits en vez de que los muestre como leds, pueda procesarlos para que aparescan en el LCD?
29/03/2014 #20


Pero cómo no, déjame te lo busco =)
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.