Go Down

Topic: MCP23017 proper rotary encoder reading (Read 3287 times) previous topic - next topic

dagoston93

Hi,
I am working on a project which uses a couple of mcp23017s on the i2c bus and trying to read rotary encoders. 
I have a quite common problem.
I can determine the direction of rotation when I am rotating slowly but as soon as i turn it quick,  the reading is a mess. Sometimes shows opposite direction, sometimes nothing. As i kept searching on google, i found out how exactly encoders work and why the problem occurs. Although I foind only one answer about arduino and mcp23017: "dont turn it quick". In my case it is not an option.
I found a code on a site, which is very promising, and there is a good description(even thouhgh i dont fully understamd it). But this is if the encoder is connected directly to the arduino. The question is how can I turn this  to work with the mcp 23017?




Code: [Select]
/* Rotary encoder read example */
#define ENC_A 14
#define ENC_B 15
#define ENC_PORT PINC
 
void setup()
{
  /* Setup encoder pins as inputs */
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);
  Serial.begin (115200);
  Serial.println("Start");
}
 
void loop()
{
 static uint8_t counter = 0;      //this variable will be changed by encoder input
 int8_t tmpdata;
 /**/
  tmpdata = read_encoder();
  if( tmpdata ) {
    Serial.print("Counter value: ");
    Serial.println(counter, DEC);
    counter += tmpdata;
  }
}
 
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
  static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t old_AB = 0;
  /**/
  old_AB <<= 2;                   //remember previous state
  old_AB |= ( ENC_PORT & 0x03 );  //add current state
  return ( enc_states[( old_AB & 0x0f )]);
}



For example I dont understand what is PINC and the line before the last one.
I am also thinking it would be more efficient to use the SPI version of the IC. I heard it may be faster. And since i am working on a big project with a switch matrix some MAX 7221s that must control hundreds of leds and some servos with a servo controller ic and multi position switches will also add up to the project. And the whole thing would communicate with a pc on the serial bus. So im not even sure if one single arduino mega will be enough for the whole project without getting slow. 

So my question is how to get my encoders working properly at higher speed rotations and should I use the SPI or the I2C version of the IC?

Thanks in advance.

Grumpy_Mike

Yes you should use the SPI version of the chip.

You should arrange the interrupt output pin on the chip to go low when ever any one of your encoder lines go low and then arrange either to pole it frequently, or to generate an interrupt with it.
Is it only the one encoder you want to read?

dagoston93

Thanks for the answer.
No, i need to read at about 10 encoders without missing any movement of any of them. They may be turned simoultaneously also.
So a I am not sure interrupt is the best solution for me. Or is there a way to detect more of them with interrupt?

Grumpy_Mike

#3
Jul 10, 2016, 06:42 pm Last Edit: Jul 10, 2016, 06:42 pm by Grumpy_Mike
Quote
They may be turned simoultaneously also.
So what speed are we talking about here? And how many steps per revolution?

The options are:-
1) Interrupts - you need to arrange things correctly so that one interrupt does not mask the other.
2) Software polling, but depending on the speed required you might not be able to go fast enough.
3) Small circuit to change the signal into step and direction.
4) Conversion into a hardware count. Then each encoder has its own up down counter and you read that counter.

Are these encoders optical or contact. If they are contact then you have switch bounce to consider.

Is it really that important not to miss a pulse?

dagoston93

Hi,
This is going to be part of a homemade small flight simulator.
The encoders will be used to change radio frequency and things like that and like in real-life, they may be turned quite fast sometimes. In that case if 1-2 pulse is missed that may not be that big problem.
I have contact encoders.

I like the idea 3 and 4, but i have no idea how to do them.
Which option would you recommend for me.

I must consider when deciding that in the program many things must happen in the loop(), because I need to scan at about 80 switches and buttons (matrix connected), 8-10 servos on an i2C 12 channel servo controller IC, 8-9 MAX7221 controlling few hundred LED display segments and normal leds, and reading some potentiometers.

So knowing that, which solution should I consider?

Grumpy_Mike

For 3 & 4 look at this
http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html

You only need to scan the switches in the loop function. The other stuff you only do when you need to as a result of inputs or external changes that you throw into the simulation. Otherwise they look after themselves.

Go Up