Rotary Encoder Speed Issue

Hi, I am using a DUE with an Omron E6B2-CWZ1X encoder 1000 P R. Seems to be working fine. I am manually turning the encoder to test.

However when I try to change the value of position with below code.

if (position == 1000.00){

It works if the encoder is going slow it works, but if I speed up it seems to totally miss this line of code?
I have tried a number of things that haven't worked. I need to be able to manipulate the variable position


#include "EncoderStepCounter.h"

#define ENCODER_PIN1 41
#define ENCODER_INT1 digitalPinToInterrupt(ENCODER_PIN1)
#define ENCODER_PIN2 43
#define ENCODER_INT2 digitalPinToInterrupt(ENCODER_PIN2)

// Create instance for one full step encoder
EncoderStepCounter encoder(ENCODER_PIN1, ENCODER_PIN2);
// Use the following for half step encoders
//EncoderStepCounter encoder(ENCODER_PIN1, ENCODER_PIN2, HALF_STEP);

void setup() {
// Initialize encoder
// Initialize interrupts
attachInterrupt(ENCODER_INT1, interrupt, CHANGE);
attachInterrupt(ENCODER_INT2, interrupt, CHANGE);

// Call tick on every change interrupt
void interrupt() {

// This is an example on how to change a "long" variable
// with the library. With every loop the value is added
// and then cleared in the encoder library
double position = 0;
void loop() {
signed char pos = encoder.getPosition();
if (pos != 0) {
position += pos;
if (position == 1000.00){
** position=0; **
** }**

Try and stop interrupts, then zero the variable and enable interrupts.
Byt the way, testing a float to be exatly 1000.00 is bad practise. Use >= or <=.

When the encoder turns slowly, each detected step is equal to 1, and you necessarily go through the value 1000; if the encoder turns faster, the detection function returns values of 2,3,4 steps that you add to your position value: you go from 999 to 1002, for example, and the test on the value 1000 cannot be done anymore. You can test if this value is exceeded:

if (position >= 1000.00){

or take over the step detection, you can test this value of 1000 either in the interrupt function or in your main loop (you have to change the pins number):

  // Arduino pro-mini 5V 16 M         *optical* encoder          A & B on pin 2 & 3 
  // if you want to use a mechanical encoder, signals A & B *MUST* be (electricaly) properly debounced !

  #define SignalA          B00000100                          // encoder signal pin 2 (port D)
  #define SignalB          B00001000                          // encoder signal pin 3 (port D)
  #define SignalAB         B00001100                          // both signals
  volatile int             encodPos;                          // encoder position
  volatile byte            LastPortD = SignalA;               // previous A/B state 
  int                      encodLastPos;                      // ----- for this demo, previous position

void setup(void) {
  PORTD |= SignalAB;                                          // internal pullups on interrupt pins 2, 3
  Serial.begin(115200);                                       // fast fast fast !
  attachInterrupt(digitalPinToInterrupt(2), ExtInt, CHANGE);  // encoder pin 2 interrupt vector
  attachInterrupt(digitalPinToInterrupt(3), ExtInt, CHANGE);  // encoder pin 3 interrupt vector 

void ExtInt() {                                               // OPTICAL ENCODER ext. interrupt pin 2, 3
  byte PortD =      PIND  & SignalAB;                         // 
  if ((PortD ^ LastPortD) & SignalA)   encodPos++;            // Rotation ->    {encodPos++; Sense = 1;}
  if ((PortD ^ LastPortD) & SignalB)   encodPos--;            // Rotation <-    {encodPos--; Sense = 0;}
  if ((PortD) &&  (PortD != SignalAB)) PortD ^= SignalAB;     //                              (swap A-B)
   LastPortD  =    PortD;                                     //                  mieux vaut faire court

void loop(void) {                                             // MAIN LOOP
  if (encodLastPos != encodPos) {                             // when the encoder change,
    encodLastPos = encodPos;                                  //
    Serial.println(encodPos);                                 // print encoder position
  }                                                           //
}                                                             //

Undestandable, your loop is too late and you miss the change. Encoders need interrupt routines

Thanks Railroader, I haven't tried stopping the interrupts although I have tried all these variations for testing the float. For accuracy I need it to zero at 1000.00 if it zeroes higher the calibration will be out? Or suppose I can grab the position it zeroes and offset the zero by the correct amount.

I now have some ideas to play with.

Thanks killzone_kid.

Thanks PatMax, that makes sense why I am having issues.

I loaded your sketch and I get the following error?

'PORTD' was not declared in this scope

I am now thinking that maybe I should access Z to calibrate the exact position and use an offset for my zero?

PORTD is a register defined for AVR based Arduinos, like the Uno, but not for the Due. That line of code is intended to turn on the input pullup resistors on the appropriate pins of PORTD.

There is an equivalent function for the Due.

I don't think this will compile for the Due, either:

byte PortD =      PIND  & SignalAB; 

gatorsoft, I had not seen that the DUE is so different from the UNO (pro-mini) that I use and of which I gave an example of program... as jremington points out, there are adaptations to be made to fix and read the 2 pins of the encoder in inputs, and it is quite different from the UNO; maybe someone passing by will confirm how to make this adaptation... here's an example :

(reading the inputs yourself, instead of using a ready-made function (library) is a bit more difficult, but gives more possibilities to intervene).

To reset the encoder position to zero, this can be done automatically when passing a predefined value (1000.00) or by adding a function in the serial terminal, by pressing a key on the keyboard.

Then try

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.