|
|
View previous topic :: View next topic |
Author |
Message |
danirebollo
Joined: 10 Oct 2011 Posts: 22
|
2 rotary encoders interrupt problem |
Posted: Sun Jun 17, 2012 4:04 pm |
|
|
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
|
|
Posted: Sun Jun 17, 2012 4:36 pm |
|
|
Give us a few more clues.
Compiler, PIC, schematic, short complete compilable code etc.
Mike |
|
|
danirebollo
Joined: 10 Oct 2011 Posts: 22
|
|
Posted: Sun Jun 17, 2012 5:20 pm |
|
|
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
|
|
|
danirebollo
Joined: 10 Oct 2011 Posts: 22
|
Re: rotary encoder |
Posted: Mon Jun 18, 2012 9:36 am |
|
|
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
|
|
|
danirebollo
Joined: 10 Oct 2011 Posts: 22
|
|
Posted: Mon Jun 18, 2012 11:41 am |
|
|
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
|
|
Posted: Mon Jun 18, 2012 12:48 pm |
|
|
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
|
|
Posted: Mon Jun 18, 2012 12:59 pm |
|
|
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
|
|
Posted: Mon Jun 18, 2012 1:11 pm |
|
|
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
|
|
Posted: Mon Jun 18, 2012 11:33 pm |
|
|
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. |
|
|
|
|
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
|