Encoders   mine is a little jumpy

I looked at the playground example for using an encoder and it seemed like the code did not take into account the fact that it was using pullups (e.g. the logic was reversed) and there was no kind debouncing.

Without debouncing I found that for every turn to a new divet (e.g. one click) I was getting 2-4 values instead of just one.
This was using the code for pinA connected to an interrupt and pinB to a normal input and pinCom to gnd.
The two inputs had pullups active.

To debounce I just delayed new interrupt readings by 200ms. This obviously slows down how quickly I can turn the encoder but it cleaned up a lot.
However, if I advance slowly one lcick at a time, sometimes it jumps back a step instead of forward.

What else can I do to make the encoder more reliable?

I am using a panasonic encoder that is equivalent to the alps one used in the example.

The appnotes show to use caps bewteen A and COM and B and COM.
I assume this should help filter the signal a little bit.

Is software debouncing a bad idea?
Should I be doing something different with how it is connected electrically?

thanks!

Hello

Yes mechanical encoders generate a lot of noise... pull up or pull down doesn't matter.

the way I fixed it is to basically put the 2 bits of the current state of the AB pins and the 2 previous state into a byte then build a table that defines what is the sequence of valid values

i.e. if that byte is now (say) 0x04 the next value can only be (say) 0x02 for one directions etc etc

this gave me a very stable reading.

Massimo

If that works then that is a good solution. Can you share the code?

I came across this other post that said the only reliable way was to use a timer interrupt to pole the encoder state.

(I have posted less than 10 posts so I can't post links but it is in the arduino forums)

I contributed something some time ago on this issue, it can be found here.

Hi Criminoy,

I was looking at that thread (using the timer interrupts).
Is this a more effective way than what Massimo is suggesting of just properly comparing state changes of the two pins?

What concerns me is calling the ISR so frequently that it bogs down the software on unecessary tasks and could interfere with the more important realtime data processing (e.g. reading sensor inputs and controlling actuators)

1ms is not so frequent for a timer interrupt, only once every 16,000 clock cycles. The interrupt could be made more efficient by using direct access to the pins rather than digitalRead().

Also you might like to read your other sensor inputs, or control your actuators on the same timing schedule (or set a flag to do so in the main loop once the ISR returns). Using counters in the ISR to divide down to a lower frequency before flagging any inputs/outputs for attention in the main loop is also a good way to schedule lower-rate activities.

Edit: Regardless, it is not good practice to use a bouncy switch on an interrupt input.

ok I am using Crimony's code now and it works great!

What I am not so clear on is exactly how FrequencyTimer2 is using pins 3 and 11 since I need those for other connections.

Right now what I do is when the deBounce() function is called by the timer I disable() the timer, run the code that needs pin 11 (e.g. it was the data pin for my shiftregister) and then enable() it again when I am done.

That works well so far but pin 3 is actually where I have my second encoder hooked up and I don't really have any other spare pins.

Is it possible to disable the timer (in enough time) once the deBounce function is called so that I can then read values from pin3 and then reenable it once I am done?
Is this the best strategy for sharing the pins?

I guess I will give this a try.....

thanks!

FrequencyTimer2 creates a timer (with setPeriod()), and makes available 2 mechanisms for notification of the timer expiration: a) An external output pin (pin 11), and b) An interrupt.

These two mechanisms are controlled independently, a) is controlled by the enable() and disable() calls, and b) is controlled by the setOnOverflow().

If you don't want to use (a), then just don't ever call enable(). The library will leave pin 11 completely alone for your exclusive use.

If you don't want to use (b), then don't ever call setOnOverflow().

In your case to want to use setOnOverflow() but not enable() and disable().

Pin 3 is available for general purpose I/O but because the PWM output which normally is available at pin 3 uses timer2, you can't use PWM output on pin3 when using this library. Go ahead and use pin 3 for your second encoder input, just check both encoder inputs in the ISR.

edit: better understanding of the library.

thanks a lot! the library docs did not make this clear to me (there are not a lot of details about the functions).

Eitherway it is working great now!

hi there,

can someone provide the whole code about encoder reading with the FrequenceyTimer interrupt. i can't get it to work. i do not really understand how to use the frequenceytimer lib and how to combine it with the code from crimony.

thanks in advance,
sebastian

Try this:

// Rotary Encoder debounce with timer interrupt
//
#include <FrequencyTimer2.h>

#define encoder0PinA  2
#define encoder0PinB  4

volatile int encoder0Pos = 0;

// Service routine called by a timer interrupt
//extern "C"
void DebounceSwitch()
{
  static unsigned char rawEncoder0A = 1;
  static unsigned char rawEncoder0B = 1;
  static unsigned char debouncedEncoder0A = 1;  // debounced state of encoder0PinA
  static unsigned char debouncedEncoder0B = 1;  // debounced state of encoder0PinB
  static uint16_t State[] = {
    0xffff, 0xffff     }; // Current debounce status

  rawEncoder0A = digitalRead(encoder0PinA);
  rawEncoder0B = digitalRead(encoder0PinB);

  // Encoder Pin A
  State[0]=(State[0]<<1) | rawEncoder0A | 0xe000;
  if(State[0]==0xf000) { // High --> Low Transition
    if (!debouncedEncoder0B) {   // check channel B to see which way
      // encoder is turning
      encoder0Pos = encoder0Pos + 1;          // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
    debouncedEncoder0A = 0;
  }
  if(State[0]==0xefff) { // Low --> High Transition
    debouncedEncoder0A = 1;
  }

  // Encoder Pin B
  State[1]=(State[1]<<1) | rawEncoder0B | 0xe000;
  if(State[1]==0xf000) { // High --> Low Transition
    debouncedEncoder0B = 0;
  }
  if(State[1]==0xefff) { // Low --> High Transition
    debouncedEncoder0B = 1;
  }

  // Clamp (if required)
  if (encoder0Pos < 0) encoder0Pos = 0;
  if (encoder0Pos > 31) encoder0Pos = 31;


}

void setup() {

  // Encoder setup
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor

  // Timer
  FrequencyTimer2::setPeriod(1000); // 1 ms
  FrequencyTimer2::setOnOverflow(DebounceSwitch);

}

void loop() {

  // just use value of encoder0Pos anywhere here

  delay(100)
}

thank you very much! not only arduino rocks, but its community! it works great with the ALPS encoder (i do have another, that reacts jumpy but the ALPS works great). i really would like to know more about encoders. also the technique massimo describes sounds very interesting, anyway its not clear to me, without code respectively with my little knowledge.