Rotary Encoder Speed

Hi All,
I sure I’m just having a brain frat, but I can’t seam to work out the speed of an rotary encoder.

What I’m trying to do is when the encoder is turned quickly multiply the change in the encoder by the speed i.e a quick 1/4 turn would equal a fully normal turn or a slow 1/4 would equal a 1/10 turn etc…

I have the encoder setup with external pull-ups, capacitors and get a good clean count on rotation.

I was thinking along the lines of measuring the time between pluses and counting that as pluses/ms, but then I get stuck on converting that to a multiplication factor.

I know this is easy just not thinking straight.

anyways here my code (ino):[code]
void funcEncoderA();
void funcEncoderB();

int _encoderPinA = D2;
int _encoderPinB = D3;

int _encoderValueA = 0;
int _encoderValueB = 0;
int _encoderValueOldA = 0;
int _encoderValueOldB = 0;

volatile bool _encoderLastA = false;
volatile bool _encoderLastB = false;
volatile int _encoderPos = 0;

unsigned long _encoderSpeedA = 0;
unsigned long _encoderSpeedB = 0;
float _encoderPercent;
float _encoderSpeedMultiplier;
unsigned long _lastEncoderTimeA;
unsigned long _lastEncoderTimeB;

int _state = 0;

void setup() {
Time.zone(10.00);
Time.setFormat(TIME_FORMAT_ISO8601_FULL);

Serial.begin(115200);
delay(1000);

Serial.printlnf(Time.timeStr() + “:” + millis() + " - System version: %s", System.version().c_str());

// Pin Modes
pinMode(_encoderPinA, INPUT);
pinMode(_encoderPinB, INPUT);
// Interrupts
attachInterrupt(_encoderPinA, funcEncoderA, CHANGE);
attachInterrupt(_encoderPinB, funcEncoderB, CHANGE);
}

void loop() {

}
//----------------------------------------------------------------
void funcEncoderA()
{
_encoderValueA = digitalRead(_encoderPinA);
if(_encoderValueA != _encoderValueOldA)
{
int s = _state & 3;
if (digitalRead(_encoderPinA)) s |= 4;
if (digitalRead(_encoderPinB)) s |= 8;
switch (s) {
case 0: case 5: case 10: case 15:
break;
case 1: case 7: case 8: case 14:
_encoderPos++; break;
case 2: case 4: case 11: case 13:
_encoderPos–; break;
case 3: case 12:
_encoderPos += 2; break;
default:
_encoderPos -= 2; break;
}
_state = (s >> 2);

_encoderSpeedA = millis() - _lastEncoderTimeA;
_lastEncoderTimeA = millis();
Serial.printlnf(Time.timeStr() + ":" + millis() + " - A Change - Encoder A: %s, B: %s,  Value: %d,  Time:  " + _encoderSpeedA, _encoderValueA ? "high" : "low", _encoderValueB ? "high" : "low", _encoderPos);
_encoderValueOldA = _encoderValueA;

}
}

void funcEncoderB()
{
_encoderValueB = digitalRead(_encoderPinB);
if( _encoderValueB != _encoderValueOldB )
{
int s = _state & 3;
if (digitalRead(_encoderPinA)) s |= 4;
if (digitalRead(_encoderPinB)) s |= 8;
switch (s) {
case 0: case 5: case 10: case 15:
break;
case 1: case 7: case 8: case 14:
_encoderPos++; break;
case 2: case 4: case 11: case 13:
_encoderPos–; break;
case 3: case 12:
_encoderPos += 2; break;
default:
_encoderPos -= 2; break;
}
_state = (s >> 2);

_encoderSpeedB = millis() - _lastEncoderTimeB;
_lastEncoderTimeB = millis();
Serial.printlnf(Time.timeStr() + ":" + millis() + " - B Change - Encoder A: %s, B: %s,  Value: %d,  Time: " + _encoderSpeedB, _encoderValueA ? "high" : "low", _encoderValueB ? "high" : "low", _encoderPos);
_encoderValueOldB = _encoderValueB;

}
}
[/code]

and I get an output like Fri Jul 1 10:37:21 2016:5473 - System version: 0.5.1 Fri Jul 1 10:37:24 2016:9315 - B Change - Encoder A: low, B: high, Value: 1, Time: 9315 Fri Jul 1 10:37:24 2016:9319 - A Change - Encoder A: high, B: high, Value: 2, Time: 9319 Fri Jul 1 10:37:24 2016:9326 - B Change - Encoder A: high, B: low, Value: 3, Time: 11 Fri Jul 1 10:37:24 2016:9330 - A Change - Encoder A: low, B: low, Value: 4, Time: 11 Fri Jul 1 10:37:24 2016:9335 - B Change - Encoder A: low, B: high, Value: 5, Time: 9 Fri Jul 1 10:37:24 2016:9339 - A Change - Encoder A: high, B: high, Value: 6, Time: 9 Fri Jul 1 10:37:24 2016:9343 - B Change - Encoder A: high, B: low, Value: 7, Time: 8 Fri Jul 1 10:37:24 2016:9346 - A Change - Encoder A: low, B: low, Value: 8, Time: 7 Fri Jul 1 10:37:24 2016:9351 - B Change - Encoder A: low, B: high, Value: 9, Time: 8 Fri Jul 1 10:37:24 2016:9355 - A Change - Encoder A: high, B: high, Value: 10, Time: 9 Fri Jul 1 10:37:24 2016:9358 - B Change - Encoder A: high, B: low, Value: 11, Time: 7 Fri Jul 1 10:37:24 2016:9362 - A Change - Encoder A: low, B: low, Value: 12, Time: 7 Fri Jul 1 10:37:24 2016:9368 - B Change - Encoder A: low, B: high, Value: 13, Time: 10 Fri Jul 1 10:37:24 2016:9375 - A Change - Encoder A: high, B: high, Value: 14, Time: 13 Fri Jul 1 10:37:24 2016:9380 - B Change - Encoder A: high, B: low, Value: 15, Time: 12 Fri Jul 1 10:37:24 2016:9386 - A Change - Encoder A: low, B: low, Value: 16, Time: 11 Fri Jul 1 10:37:24 2016:9444 - A Change - Encoder A: high, B: low, Value: 15, Time: 58 on a quick 1/4 turn.

Thanks for reading.

I’m not quite sure why you need two interrupts. IMHO one FALLING or RISING interrupt should do.
Just check if the other pin is HIGH or LOW at that time to distinguish between left or right turn - at least this is how I get away with rotary encoders like the ones used in mice (max speed is limited by ISR latency and alignment of the two sensors in respect to the “mask” tho’)

And for your factor, I’d just alter the incrementor depending on the time between two triggers of the interrupt like this

const uint32_t usSlow = 1000000; // 1s between two triggers
const uint32_t usFast = 10000; // 10ms between two triggers 
volatile uint32_t usLastISR;

void ISR()
{
  int incrementor = 10; // how many steps is one trigger worth (default 10)
  int direction;        // factor for direction 

  if (micros() - usLastISR > usSlow)
    incrementor = 1;
  else if (micros() - usLastISR < usFast)
    incrementor = 100;
  usLastISR = micros();

  direction = pinReadFast(_encoderPinB) ? +1 : -1;

  _encoderPos += incrementor * direction;
}

This would require scaling the default step width up to 10 (or any other useful value) to make things easier and avoid needing floating point types for slow turns.