Visualizacion en LCD del sentido de giro de un encoder

Buenas tardes, he estado trabajando en un proyecto de un pendulo invertido y estoy atorado en la parte del encoder; solo quiero que me visualice la direccion de movimiento del encoder (derecha o izquierda) en una pantalla lcd.
Estoy empleando programacion en CCS pero solo me detecta un sentido y en la otra direccion no me muestra nada. El encoder se encuentra acoplado a un motor y conectado tambien a un pic18f4550. ...

Les dejo el programa hecho en CCS.

Código:
#Include <18F4550.h>  //Declaracion para utilizar el PIC
#device HIGH_INTS=TRUE// CONFIGURACIÓN PARA LAS INTERRUPCIONES
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL2,CPUDIV1,VREGEN,NOPBADEN
#use Delay(Clock =4000000 )
#include <usb_bootloader.h> // Para activar la programación del microcontrolador
#include <lcd.c>//libreria para utilizar el LCD,

#Byte PortA = 0xF80  //Dirección del puerto A
#Byte PortB = 0xF81  //Dirección del puerto B 
#Byte PortC = 0xF82  //Dirección del puerto C 
#Byte PortD = 0xF83  //Dirección del puerto D
#Byte PortE = 0xF84  // Dirección del puerto E


#INT_EXT                      //Interrupcion externa por RB0

Void IntRB0()
{
  //disable_Interrupts(Int_Ext); 
  If (Bit_Test(PortB, 0))      //si RB0 se ha puesto a 1 (flanco de subida)
{  
      Ext_Int_Edge(H_TO_L);    //entonces activar la siguiente interrupcion por 
                              //flanco de bajada
      If (Bit_Test(PortB, 1))       //si RB1 esta a 1
      
      //Aca quiere decir que va en sentido de las agujas del reloj
{        
         printf(lcd_putc,"\fDerecha");
         }  
}
Else                          //si RB0 se ha puesto a 0 (Flanco de bajada)
{  
      //en este caso indica que el sentido es en contra de las agujas
      Ext_Int_Edge(L_TO_H);     //entonces activar la siguiente interrupcion por
                              //flanco de subida
      If (Bit_Test(PortB, 1))   //si RB1 esta a 1
      
    { 
           printf(lcd_putc,"\fizquierda");     
           }
    
   }
//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;

 } 
  Void Main()                     // Inicio y configuración.
{
   Port_B_Pullups(FALSE);       // Configuración para el PIC 18F4550.
   Setup_ADC_Ports(NO_ANALOGS); // Sin comparadores ni ADCs, todo digital
   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);
   Setup_comparator(NC_NC_NC_NC);
   Setup_vref(FALSE);
  
  Enable_Interrupts(Int_Ext);   //Activar Interrupción Externa a través de RB0
   Ext_Int_Edge(L_TO_H);   //Inicialmente detectar interrupción por flanco
                              //de subida.
   Enable_Interrupts(GLOBAL);   // Interrupciones Generales Activadas
   
   lcd_init();                //inicializar el lcd
   printf(lcd_putc,"Giro Encoder");
   delay_ms(3000);
   printf(lcd_putc,"\f");
  
   
   //Propgrama principal
   While (TRUE)
   
   {
    
   }
    
}
 
Última edición por un moderador:
las salidas que ofrece un encoder en ambos canales A y B son pulsos los cuales se encuentran desfasados 90 grados. El voltaje de cada pulso es de 4.2 V
 
Hola Amigo, bueno, lo que puedo apreciar en tu programa es que si el flanco de subida en Rb0 ocurre y luego sucede lo mismo en Rb1 pues gira en un sentido, ahora bien en la sig. parte de la condicion, condicionas a Rb0 en flanco de bajada, parece estar ahi el inconveniente.
Puedes realizar lo sig:
Si el flanco de subida ocurre en Rb0 antes que en Rb1?, entonces gira en un sentido.
Si el flanco de subida ocurre en Rb1 antes que en Rb0?, pues gira en sentido contrario.
 
Mas que detectar dos flancos que es mas trabajo, mejor se detecta un flanco, si en ese momento el otro pin =1 gira en un sentido y si =0 gira en sentido contrario.

Pseudocódigo

pinAold=0;
loop{
leer pin A
if (pinA==1 && pinAold==0){
if (pinB==0) derecha
if (pinB==1)iquierda
}
pinAold = pinA
}

Osea, solo se comprueba un flanco en uno se los pines (el de bajada o el de subida, al gusto) y en ese momento se mira el otro pin a ver como está, a ese no hay que gestionarle el flanco.

Si lo haces con interrupciones mejor, la interrupción será:
interrupción{
if (pinB==0) derecha
if (pinB==1)iquierda
}
Mas fácil no puede ser.
 
Última edición:
pues ya hice ajustes al programa y me sigue jalando igual, lo que si no te es que cuando compilo me aparecen 3 warnings y dicen lo siguiente:

Warning216 "Interrupts disabled during calling to prevent re-entrancy: (@delay_ms1)
Warning216 "Interrupts disabled during calling to prevent re-entrancy: (lcd_send_nibble)
Warning216 "Interrupts disabled during calling to prevent re-entrancy: (lcd_send_byte)

Me desabilita las interrupciones al inicio del programa ¿sera que esto afecte o sea causa de que no me represente bien los dos sentidos de giro? en el programa que puse al principio se ve claramente que mande instrucciones de que en el lcd se mostraran los sentidos de giro (derecha izquierda) dentro de la inrerrupcion.
 
Si lo hace con interrupciones sólo se podrá detectar un estado a la vez y únicamente en el momento del cambio de estado.
Es decir, si se configura la interrupción por cambio de estado L_TO_H, se podrá detectar cuando RB0 es 1.
Por lo tanto cuando RB0 sea 0 no se podrá detectar pues ya habrá ocurrido la interrupción por flanco ascendente.

Sin usar interrupciones una opción para detectar estados sería esta...
Código:
#include <18f4550.h>
#fuses   nofcmen,noieso,novregen
#use     delay(crystal = 4MHz)
#include <lcd.c>
#byte PORTB = getenv("SFR:PORTB")


void main() {
   setup_adc_ports(no_analogs);  // Conversores análogos como digitales.
   lcd_init();                   // Inicializar la pantalla.

while (true){                    // Bucle infinito.
   lcd_gotoxy(1,1);              // Ir la línea 1 posición 1 de la pantalla.
   if(bit_test(PORTB,0)){        // Verificar si el estado de RB0 es 1.
   lcd_putc("Motor Derecha  ");
   }
   else{                         // Caso contrario...
   lcd_putc("Motor Izquierda");
   }
   }
}
 
Última edición:
Hola D@rkbytes probe el programa que pusiste y pues solo oscila entre un estado y otro pero sin conectar el motor y el encoder, deberia detectar cuando empieza girar el motor hacia una direccion y mostramela, la duda que me surgio es que si tendra algo que ver con que escribi los printf dentro de la rutina de interrupcion por que me marcan los warnings que puse anteriormente.
 
Hola D@rkbytes probé el programa que pusiste y pues solo oscila entre un estado y otro pero sin conectar el motor y el encoder
Coloca una resistencia pull-down en el pin RB0 para mantener un estado bajo en ausencia de pulsos.
la duda que me surgió es que si tendrá algo que ver con que escribí los printf dentro de la rutina de interrupción por que me marcan los warnings que puse anteriormente.
Eso no tiene importancia y ocurre cuando se utilizan interrupciones conjuntamente con el uso de LCD.

Saludos.
 
El problema de los warning ya esta solucionado, y si detecta el sentido de giro en ambas direcciones.
El unico detalle es que al intentar hacer el cambio de izquierda a derecha no lo detecta de forma instantanea. Estoy alimentando con una misma fuente al encoder y al motor (el encoder a 5v y el motor a 12v) y el pic lo alimento mediante usb, que tambien es el enlace con la computadora para programar el pic. Mi duda es si tendra que ver que alimente con la misma fuente tanto el encoder como el motor ya que a veces cuando enciendo la fuente pero no conecto el motor me detecta un cambio de sentido de giro, lo cual no es deseable.

Gracias de antemano

Dejo igual el programa en ccs

#Include <18F4550.h> //Declaracion para utilizar el PIC

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL2,CPUDIV1,VREGEN,NOPBADEN

#use Delay(Clock =48000000 )
#include <usb_bootloader.h> // Para activar la programación del microcontrolador
#include <lcd.c>//libreria para utilizar el LCD,

#Byte PortA = 0xF80 //Dirección del puerto A
#Byte PortB = 0xF81 //Dirección del puerto B
#Byte PortC = 0xF82 //Dirección del puerto C
#Byte PortD = 0xF83 //Dirección del puerto D
#Byte PortE = 0xF84 // Dirección del puerto E

Int8 flag=0; //Declarar bandera para saber cuando va a derecha o izquierda

#INT_EXT //Interrupcion externa por RB0

Void IntRB0()
{
If (Bit_Test(PortB, 0)) //si RB0 se ha puesto a 1 (flanco de subida)
{
Ext_Int_Edge(H_TO_L); //entonces activar la siguiente interrupcion por
//flanco de bajada
If (Bit_Test(PortB, 1)) //si RB1 esta a 1

{
flag=1;
}
}
Else //si RB0 se ha puesto a 0 (Flanco de bajada)
{
//en este caso indica que el sentido es en contra de las agujas
Ext_Int_Edge(H_TO_L); //entonces activar la siguiente interrupcion por
//flanco de subida
If (Bit_Test(PortB, 1)) //si RB1 esta a 1

{
flag=2;
}
}
//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;

}
Void Main() // Inicio y configuración.
{
Port_B_Pullups(FALSE); // Configuración para el PIC 18F4550.
Setup_ADC_Ports(NO_ANALOGS); // Sin comparadores ni ADCs, todo digital
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);
Setup_comparator(NC_NC_NC_NC);
Setup_vref(FALSE);

Enable_Interrupts(Int_Ext); //Activar Interrupción Externa a través de RB0
Ext_Int_Edge(L_TO_H); //Inicialmente detectar interrupción por flanco
//de subida.
Enable_Interrupts(GLOBAL); // Interrupciones Generales Activadas
set_tris_b(0b11111111);

lcd_init(); //inicializar el lcd
delay_ms(100);
lcd_gotoxy(1,1);
printf(lcd_putc,"Giro Encoder");

//Propgrama principal
While (TRUE)

{
if(flag==1)
{
lcd_gotoxy(1,2);
printf(lcd_putc," Derecha");
}
if(flag==2)
{
lcd_gotoxy(1,2);
printf(lcd_putc,"Izquierda");
}
}
}
 
Atrás
Arriba