CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

2 rotary encoders interrupt problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

2 rotary encoders interrupt problem
PostPosted: Sun Jun 17, 2012 4:04 pm     Reply with quote

Hello!
I try to connect 4 buttons in rb1, rb2, rb3, rb4 and all anded to rb0 and works well, but when i try to use 2 encoders program count bad pulses...
I think is ext_int_edge, but i dont know... encoder are with common to gnd and pins pulled up to vcc (later pass trough low pass filter).
I use #INT_RB with this definition:
Code:
#define ENC_A     PIN_B2
#define ENC_B     PIN_B4
#define ENC_C     PIN_B3
#define ENC_D     PIN_B5

The only pins that throws interrupt was ENC_A (pin 1 from encoder 1), and ENC_C (pin 1 from encoder 2).
Only one pin from each encoder, same as use with one encoder: only one pin throws interrupt in RB0.
Is there any solution?

Thanx!
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Jun 17, 2012 4:36 pm     Reply with quote

Give us a few more clues.

Compiler, PIC, schematic, short complete compilable code etc.

Mike
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

PostPosted: Sun Jun 17, 2012 5:20 pm     Reply with quote

hello, i use PIC 16f872, CCS 4.120
interrupt code are
Code:

#INT_RB
void IntRB0()
{
     //disable_interrupts(int_ext);
     if (INPUT(ENC_A))      // Si RB0 se ha puesto a 1 (flanco de subida),
     { 
         //disable_interrupts(int_ext);
         ext_int_edge(H_TO_L);   // entonces activar la siguiente interrupción por flanco de bajada.
         if (INPUT(ENC_B))  // Si RB1 está 1,
         {
             x++;                // entonces incrementar el contador X.

         }
     }
     else if (!INPUT(ENC_A))        // Si RB0 se ha puesto a 0 (flanco de bajada),
     { 
         //disable_interrupts(int_ext);
         ext_int_edge(L_TO_H);   // entonces activar la siguiente interrupción por flanco de subida.
         if (INPUT(ENC_B))  // Si RB1 está 1,
         {
             
          x--;                // entonces decrementar el contador X.

         }
         
     }

It was code for only 1 encoder, i double this code with ENC_C and ENC_D
like this (i change code every second...)

Code:

#INT_RB
void IntRB0()
{
     //disable_interrupts(int_ext);
     if (INPUT(ENC_A))      // Si RB0 se ha puesto a 1 (flanco de subida),
     { 
         //disable_interrupts(int_ext);
         ext_int_edge(H_TO_L);   // entonces activar la siguiente interrupción por flanco de bajada.
         if (INPUT(ENC_B))  // Si RB1 está 1,
         {
             x++;                // entonces incrementar el contador X.

         }
     }
     else if (!INPUT(ENC_A))        // Si RB0 se ha puesto a 0 (flanco de bajada),
     { 
         //disable_interrupts(int_ext);
         ext_int_edge(L_TO_H);   // entonces activar la siguiente interrupción por flanco de subida.
         if (INPUT(ENC_B))  // Si RB1 está 1,
         {
             
          x--;                // entonces decrementar el contador X.

         }
          if (INPUT(ENC_C))      // Si RB0 se ha puesto a 1 (flanco de subida),
     { 
         //disable_interrupts(int_ext);
         ext_int_edge(H_TO_L);   // entonces activar la siguiente interrupción por flanco de bajada.
         if (INPUT(ENC_D))  // Si RB1 está 1,
         {
             x++;                // entonces incrementar el contador X.

         }
     }
     else if (!INPUT(ENC_C))        // Si RB0 se ha puesto a 0 (flanco de bajada),
     { 
         //disable_interrupts(int_ext);
         ext_int_edge(L_TO_H);   // entonces activar la siguiente interrupción por flanco de subida.
         if (INPUT(ENC_D))  // Si RB1 está 1,
         {
             
          x--;                // entonces decrementar el contador X.

         }
     }

_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)
necati



Joined: 12 Sep 2003
Posts: 37
Location: istanbul

View user's profile Send private message

rotary encoder
PostPosted: Sun Jun 17, 2012 6:35 pm     Reply with quote

http://320volt.com/pic16f628-74hc595-sayici-ccs-c/
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

Re: rotary encoder
PostPosted: Mon Jun 18, 2012 9:36 am     Reply with quote

necati wrote:
http://320volt.com/pic16f628-74hc595-sayici-ccs-c/

this circuit has only one encoder.

My problem aren't encoder conection. With one encoder circuit works well, but with 2 or more not because interrupt was used as part of a sequence (or i dont know...)
_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

PostPosted: Mon Jun 18, 2012 10:02 am     Reply with quote

I found this on internet https://sites.google.com/site/proyectosroboticos/encoder/encoder-por-software/5-encoders-y-un-solo-pic/programa-cinco-encoder-y-un-solo-pic-en-ccs
The problem is that code don't use interrupts... I try to use interrupts now.
_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

PostPosted: Mon Jun 18, 2012 11:41 am     Reply with quote

Mmmm i found impedance problem... buffering encoder pins and anded one of the each encoder to interrupt pin seems to work... i put this code, grouping if clauses to avoid mix encoders
Code:

#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 (!INPUT(ENC_A))      // Si RB0 se ha puesto a 1 (flanco de subida),
   { 
       Ext_Int_Edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de bajada.
        If (!INPUT(ENC_B))  // Si RB1 está a 1,
       {
           x++;   // entonces incrementar una unidad el valor de X.
           if (x>11)
           {
           x=1;
           }
        }       
   }
   Else If (!INPUT(ENC_C))      // Si RB0 se ha puesto a 1 (flanco de subida),
   { 
       Ext_Int_Edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de bajada.
        If (!INPUT(ENC_D))  // Si RB1 está a 1,
       {
           y++;   // entonces incrementar una unidad el valor de X.
           if (y>11)
           {
           y=1;
           }
        }       
   }
   
   if (INPUT(ENC_A))                          // Si RB0 se ha puesto a 0 (flanco de bajada),
   { 
       Ext_Int_Edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de subida.
        If (!INPUT(ENC_B))  // Si RB1 está 1,
       {
           x--;// entonces decrementar una unidad el valor de X.
         
           if (x<1)
           {
            x=11;
           }
        }
   } 
   Else if (INPUT(ENC_C))                         // Si RB0 se ha puesto a 0 (flanco de bajada),
   { 
       Ext_Int_Edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de subida.
        If (!INPUT(ENC_D))  // Si RB1 está 1,
       {
           y--;// entonces decrementar una unidad el valor de X.
         
           if (y<1)
           {
            y=11;
           }
        }
     
     
   }       
}

Now, code works except substract "y" varible and some false rebound...

Note: encoder contacts are PULLED UP (common to GND). (Interrupt ocurrs when bit comes from 1 to 0. Encoder pins are buffered to his RB pin and interruption are caused by encoder pins passed trough NOT gate, this go to OR gate and finally this go to RB0 (Interrupt pin) )
_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

PostPosted: Mon Jun 18, 2012 12:48 pm     Reply with quote

Hmmm problem (not rebounds, i think it is caused by protoboard and bad contacts firstly...) in encoder 2 (add but not substract) solved when turn 4 pin connector (connector with encoder pins to mcu), I use RB1, RB2, RB3, RB4 for EncA1, EncB1, EncA2, EncB2. I turn connector to RB4, RB3, RB2, RB1.
Now, encoder 2 works fine, and problem goes to encoder 1 XD then, i think is configuration pins problem or interrupt problem, but it is the same code than other encoder...

How i check if configuration pins are ok? I thought CCS auto configure pins to input and output...

Configuration pins code:
Code:

#include <16F872.h>
//#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(clock=20000000)
#define I2C_SCL   PIN_C3
#define I2C_SDA   PIN_C4
#define RB0       PIN_B0
#define ENC_A     PIN_B1
#define ENC_B     PIN_B2
#define ENC_C     PIN_B3
#define ENC_D     PIN_B4
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
//#use i2c(master,sda=PIN_C4,scl=PIN_C3,FORCE_HW)

_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)


Last edited by danirebollo on Mon Jun 18, 2012 12:59 pm; edited 1 time in total
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

PostPosted: Mon Jun 18, 2012 12:59 pm     Reply with quote

I change to
Code:

#define ENC_A     PIN_B3
#define ENC_B     PIN_B4
#define ENC_C     PIN_B1
#define ENC_D     PIN_B2

and problem was the same: "y" substract, therefore, isnt pin configuration problem. Was interrupt code
_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)
danirebollo



Joined: 10 Oct 2011
Posts: 22

View user's profile Send private message MSN Messenger

PostPosted: Mon Jun 18, 2012 1:11 pm     Reply with quote

yeah! code works.
Code:

#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 (!INPUT(ENC_A))      // Si RB0 se ha puesto a 1 (flanco de subida),
   { 
       Ext_Int_Edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de bajada.
        If (!INPUT(ENC_B))  // Si RB1 está a 1,
       {
           x++;   // entonces incrementar una unidad el valor de X.
           if (x>11)
           {
           x=1;
           }
        }       
   }
   
   ///
   else if (INPUT(ENC_A))                          // Si RB0 se ha puesto a 0 (flanco de bajada),
   { 
       Ext_Int_Edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de subida.
        If (!INPUT(ENC_B))  // Si RB1 está 1,
       {
           x--;// entonces decrementar una unidad el valor de X.
         
           if (x<1)
           {
            x=11;
           }
        }
   }
   ///
   //Else
   If (!INPUT(ENC_C))      // Si RB0 se ha puesto a 1 (flanco de subida),
   { 
       Ext_Int_Edge(L_TO_H);    // entonces activar la siguiente interrupción por flanco de bajada.
        If (!INPUT(ENC_D))  // Si RB1 está a 1,
       {
           y++;   // entonces incrementar una unidad el valor de X.
           if (y>11)
           {
           y=1;
           }
        }     
  }
  //
     Else if (INPUT(ENC_C))                         // Si RB0 se ha puesto a 0 (flanco de bajada),
   { 
       Ext_Int_Edge(H_TO_L);    // entonces activar la siguiente interrupción por flanco de subida.
        If (!INPUT(ENC_D))  // Si RB1 está 1,
       {
           y--;// entonces decrementar una unidad el valor de X.
         
           if (y<1)
           {
            y=11;
           }
        }
   } 
  }


I go to view croatia-spanish match xD, later i post schematics and all information.
_________________
CCS 4.120

(Please beggin my english... are "spanish english" xD)
RHA



Joined: 25 Apr 2006
Posts: 31
Location: Germany

View user's profile Send private message

PostPosted: Mon Jun 18, 2012 11:33 pm     Reply with quote

Like written in another thread :

I always use code like this (for 2 motors with encoder) :
Code:
//******************************************************************************************************
//******************************************************************************************************

#define ENC_NC      0b00010000         // Encoder - no Change
#define ENC_LEFT   0b00100000         // Encoder - one position to left
#define ENC_RIGHT   0b01000000         // Encoder - one position to right
#define ENC_JUMP   0b10000000         // Encoder - Jump (changes 2 positions) ERROR!

int CONST ENC_STATUS[16] = { ENC_NC   , ENC_RIGHT, ENC_LEFT , ENC_JUMP,
                       ENC_LEFT , ENC_NC   , ENC_JUMP , ENC_RIGHT,
                       ENC_RIGHT, ENC_JUMP , ENC_NC   , ENC_LEFT,
                       ENC_JUMP , ENC_LEFT , ENC_RIGHT, ENC_NC };


int8   M1_ENC_STAT;                              //  State Encoder M1
#bit   M1_ENC_STAT_A_ACT   =   M1_ENC_STAT.0            //   Actual signal A
#bit   M1_ENC_STAT_B_ACT   =   M1_ENC_STAT.1            //   Actual signal B
#bit   M1_ENC_STAT_A_OLD   =   M1_ENC_STAT.2            //   Last   signal A
#bit   M1_ENC_STAT_B_OLD   =   M1_ENC_STAT.3            //   Last   signal B
#bit   M1_ENC_STAT_STILL   =   M1_ENC_STAT.4            //   No change in signals
#bit   M1_ENC_STAT_LEFT   =   M1_ENC_STAT.5            //   1 step to left
#bit   M1_ENC_STAT_RIGHT   =   M1_ENC_STAT.6            //   1 step to right
#bit   M1_ENC_STAT_ERROR   =   M1_ENC_STAT.7            //   ERROR

int8   M2_ENC_STAT;                              //  State Encoder M2
#bit   M2_ENC_STAT_A_ACT   =   M2_ENC_STAT.0            //   Actual signal A
#bit   M2_ENC_STAT_B_ACT   =   M2_ENC_STAT.1            //   Actual signal B
#bit   M2_ENC_STAT_A_OLD   =   M2_ENC_STAT.2            //   Last   signal A
#bit   M2_ENC_STAT_B_OLD   =   M2_ENC_STAT.3            //   Last   signal B
#bit   M2_ENC_STAT_STILL   =   M2_ENC_STAT.4            //   No change in signals
#bit   M2_ENC_STAT_LEFT   =   M2_ENC_STAT.5            //   1 step to left
#bit   M2_ENC_STAT_RIGHT   =   M2_ENC_STAT.6            //   1 step to right
#bit   M2_ENC_STAT_ERROR   =   M2_ENC_STAT.7            //   ERROR

//********************************************************************************************************

void   encoder_init() {                           //   Initialize Encoder

      M1_ENC_POS      =   0;                        //   Clear Positions
      M2_ENC_POS      =   0;                        //
      M1_ENC_STAT      =   0;                        //   Clear state
      M2_ENC_STAT      =   0;                        //
      M1_ENC_STAT_A_ACT   =   input(M1_ENCODER_A);      //   Readout actual signals
      M1_ENC_STAT_B_ACT   =   input(M1_ENCODER_B);      //
      M2_ENC_STAT_A_ACT   =   input(M2_ENCODER_A);      //
      M2_ENC_STAT_B_ACT   =   input(M2_ENCODER_B);      //
}
//********************************************************************************************************
//** Keep this part as short as possible because it is called in an Timer-Interrupt

void   encoder() {                                 //   Readout encoder

      M1_ENC_STAT_A_OLD   =   M1_ENC_STAT_A_ACT;         //   Copy last signal to buffer
      M1_ENC_STAT_B_OLD   =   M1_ENC_STAT_B_ACT;         //
      M2_ENC_STAT_A_OLD   =   M2_ENC_STAT_A_ACT;         //
      M2_ENC_STAT_B_OLD   =   M2_ENC_STAT_B_ACT;         //

      M1_ENC_STAT_A_ACT   =   input(M1_ENCODER_A);      //   Readout actual signals
      M1_ENC_STAT_B_ACT   =   input(M1_ENCODER_B);      //
      M2_ENC_STAT_A_ACT   =   input(M2_ENCODER_A);      //
      M2_ENC_STAT_B_ACT   =   input(M2_ENCODER_B);      //

      M1_ENC_STAT   =   ((M1_ENC_STAT & 0x8f) | (ENC_STATUS[(M1_ENC_STAT & 0x0f)]));   //   Get state
      M2_ENC_STAT   =   ((M2_ENC_STAT & 0x8f) | (ENC_STATUS[(M2_ENC_STAT & 0x0f)]));   //

      if      (M1_ENC_STAT_LEFT)   --M1_ENC_POS;
      else if   (M1_ENC_STAT_RIGHT)   ++M1_ENC_POS;

      if      (M2_ENC_STAT_LEFT)   --M2_ENC_POS;
      else if   (M2_ENC_STAT_RIGHT)   ++M2_ENC_POS;

}


Each encoder uses one byte for his state (Mx_ENC_STAT). In this byte there are the last encoder states (2 Bits 2/3), the new encoder state (2 Bits 0/1) and the information of the state (4 Bits - No change, Left, Right, Error 4/5/6/7). The Sub encoder() has to be called in a timer interrupt. For good results the frequency of calling the sub has to be min. 3-4 times higher than the maximum frequency of the encoder.

Description :
In the sub encoder() the old values of the pins are shifted 2 bits left and the new values are read to the bits 0/1. This will give a value in the low nibble between 0 and 15. Now the state left/right/no change/error is read out the table ENC_STATUS and taken to the Mx_ENC_STAT. The highest bit (Error) will not be cleared in this action. It has to be cleared by main routines. After setting the state bits the counter values are incremented or decremented.


With interrupt on change i always got problems (lost edges). With this routine you only have be careful that it is called often enough.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group