NewEncoder Library problems

I am trying to load and test out this library on Teensy 4.0 with the examples
When included the library cannot find the other 2 sub-libraries included in the utilities folder
I used the add .zip library function.
Checked the sketchbook folders and all the components are there but for some reason can’t read them
Can anyone help?

Please post the problem code, the full error message and a diagram of where exactly the libraries are installed

the code is just the example attached to the library
no additions

#include “Arduino.h”
#include “NewEncoder.h”

// Adjust number of encoders and pin assignments for particular processor. These work for Teensy 3.2. See README for meaning of constructor arguments.
// Use FULL_PULSE for encoders that produce one complete quadrature pulse per detnet, such as: Rotary Encoder + Extras : ID 377 : $4.50 : Adafruit Industries, Unique & fun DIY electronics and kits
// Use HALF_PULSE for endoders that produce one complete quadrature pulse for every two detents, such as: Rotary Encoder + Extras : ID 377 : $4.50 : Adafruit Industries, Unique & fun DIY electronics and kits
NewEncoder encoders = {
{ 0, 1, -20, 20, 0, FULL_PULSE },
{ 20, 21, 0, 50, 25, FULL_PULSE },
{ 5, 6, -25, 0, -13, FULL_PULSE },
{ 11, 12, -10, 25, 8, FULL_PULSE }
};

const uint8_t numEncoders = sizeof(encoders) / sizeof(NewEncoder);
int16_t prevEncoderValue[numEncoders];

void setup() {
int16_t value;

Serial.begin(115200);
delay(2000);
Serial.println(F(“Starting”));

for (uint8_t index = 0; index < numEncoders; index++) {
if (!encoders[index].begin()) {
Serial.print(F(“Encoder: “));
Serial.print(index);
Serial.println(
F(” Failed to Start. Check pin assignments and available interrupts. Aborting.”));
while (1) {
}
} else {
value = encoders[index];
prevEncoderValue[index] = value;
Serial.print(F("Encoder: “));
Serial.print(index);
Serial.print(F(” Successfully Started at value = "));
Serial.println(value);
}
}
}

void loop() {
int16_t currentValue;
bool up, down;

for (uint8_t index = 0; index < numEncoders; index++) {
up = encoders[index].upClick();
down = encoders[index].downClick();
if (up || down) {
currentValue = encoders[index];
if (currentValue != prevEncoderValue[index]) {
Serial.print(F(“Encoder”));
Serial.print(index);
Serial.print(F(": “));
Serial.println(currentValue);
prevEncoderValue[index] = currentValue;
} else if (up) {
Serial.print(F(“Encoder”));
Serial.print(index);
Serial.println(F(”: At upper limit."));
} else {
Serial.print(F(“Encoder”));
Serial.print(index);
Serial.println(F(": At lower limit."));
}
}
}
}

Here is the error message

In file included from /Users/michaelburnham/Documents/Arduino/libraries/NewEncoder/examples/MultipleEncoders/MultipleEncoders.ino:2:0:
/Users/michaelburnham/Documents/Arduino/libraries/NewEncoder/NewEncoder.h:8:36: fatal error: utility\interrupt_pins.h: No such file or directory
#include "utility\interrupt_pins.h"
^
compilation terminated.
Error compiling for board Teensy 4.0.

and attached is a screenshot of the location of the sub-library

There is a library especcially for teensy 4.0 which uses the build in hardware-quadrature-encoder-decoders of the teensy 4.0

The library can be donwloaded as a zip-library form here

Download from gitHUB using the green download-button

install library with Sketch - inklude library - add zip-library
in the subfolder of .....\Teensy-4.x-Quad-Encoder-Library*examples*....
there is some example-codes

The documentation of the parameters is non-intuitive.

I changed the IO-pins and added some comments to explain the parameters
I tested it with just one encoder but I guess it will work

/* Teensy 4 H/S Encoder Library - TwoKnobs Example
 * http://www.pjrc.com/teensy/td_libs_Encoder.html
 *
 * This example code is in the public domain.
 */

#include "QuadEncoder.h"

// Change these pin numbers to the pins connected to your encoder.
// Allowable encoder pins:
// 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33
// Encoder on channel 1 of 4 available
// Phase A (pin0), PhaseB(pin1), 

// QuadEncoder knobLeft(channel, Phase A, Phase B, pullup-required)
// channel 1, Phase A on pin 2 Phase B on pin 3 0 = no pullup-required
QuadEncoder knobLeft(1, 2, 3, 0); 
// Encoder on channel 2 of 4 available
//Phase A (pin2), PhaseB(pin3), Pullups Req(0)

// QuadEncoder knobRight(channel, Phase A, Phase B, pullup-reuired)
// channel 2, Phase A on pin 5 Phase B on pin 7 0 = no pullup-required
QuadEncoder knobRight(2, 5, 7,0);
//   avoid using pins with LEDs attached

void setup() {
  Serial.begin(115200);
  Serial.println("TwoKnobs Encoder Test:");
  /* Initialize Encoder/knobLeft. */
  knobLeft.setInitConfig();
  knobLeft.init();
  /* Initialize Encoder/knobRight. */
  knobRight.setInitConfig();
  knobRight.init();
}

long positionLeft  = -999;
long positionRight = -999;

void loop() {
  long newLeft, newRight;
  newLeft = knobLeft.read();
  newRight = knobRight.read();
  if (newLeft != positionLeft || newRight != positionRight) {
    Serial.print("Left = ");
    Serial.print(newLeft);
    Serial.print(", Right = ");
    Serial.print(newRight);
    Serial.println();
    positionLeft = newLeft;
    positionRight = newRight;
  }
  // if a character is sent from the serial monitor,
  // reset both back to zero.
  if (Serial.available()) {
    Serial.read();
    Serial.println("Reset both knobs to zero");
    knobLeft.write(0);
    knobRight.write(0);
  }
}

best regards Stefan

OK thanks - I am using PEC11R encoders which seem to have a nasty bounce on them
I'm just looking to improve the performance a bit
I need to use 4 encoders

So i did some more reasearch and came across this website

best regards Stefan

I needed some time to relocate a code-example from user Argmue who wrote a code-version that uses the table-decode-method. This is a polling-version that does not use interrupts. So this means you have to call the function fast enough to catch your max-frequency

/*some rotary-encoders with mechanical switches are unreliable 
 * if you change rotation-direction. 
 * Because sometimes the switch is already opened sometimes not. 
 * This leads to wrong readings. some time ago user argmue 
 * posted a rotery-encoder-sketch that takes care of all 
 * these special situations
*/

// rotary-encoder with debounce written by user argmue

const byte ENCODER_A_PIN = 3;
const byte ENCODER_B_PIN = 2;
const byte SWITCH_PIN = 4;

int Counter = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("\nStart");
  pinMode(ENCODER_A_PIN, INPUT);
  pinMode(ENCODER_B_PIN, INPUT);
  pinMode(SWITCH_PIN, INPUT);
}

void loop() {
  int8_t state = 0;
  if (rotaryEncoder(state)) {
    Serial.println("- SWITCH -");
  }
  if (state == -1) {
    Counter -= 1;
    Serial.print("<-- Counter ");
    Serial.println(Counter);
  }
  
  if (state == 1) {
    Counter += 1;
    Serial.print(" -->");
    Serial.println(Counter);
  }
}

bool rotaryEncoder(int8_t &delta) {
  delta = 0;
  enum {STATE_LOCKED, STATE_TURN_RIGHT_START, STATE_TURN_RIGHT_MIDDLE, STATE_TURN_RIGHT_END, STATE_TURN_LEFT_START, STATE_TURN_LEFT_MIDDLE, STATE_TURN_LEFT_END, STATE_UNDECIDED};
  static uint8_t encoderState = STATE_LOCKED;
  bool a = !digitalRead(ENCODER_A_PIN);
  bool b = !digitalRead(ENCODER_B_PIN);
  bool s = !digitalRead(SWITCH_PIN);
  static bool switchState = s;
  switch (encoderState) {
    case STATE_LOCKED:
      if (a && b) {
        encoderState = STATE_UNDECIDED;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_LEFT_START;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_RIGHT_START;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
    case STATE_TURN_RIGHT_START:
      if (a && b) {
        encoderState = STATE_TURN_RIGHT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_RIGHT_END;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_RIGHT_START;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
    case STATE_TURN_RIGHT_MIDDLE:
    case STATE_TURN_RIGHT_END:
      if (a && b) {
        encoderState = STATE_TURN_RIGHT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_RIGHT_END;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_RIGHT_START;
      }
      else {
        encoderState = STATE_LOCKED;
        delta = -1;
      };
      break;
    case STATE_TURN_LEFT_START:
      if (a && b) {
        encoderState = STATE_TURN_LEFT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_LEFT_START;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_LEFT_END;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
    case STATE_TURN_LEFT_MIDDLE:
    case STATE_TURN_LEFT_END:
      if (a && b) {
        encoderState = STATE_TURN_LEFT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_LEFT_START;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_LEFT_END;
      }
      else {
        encoderState = STATE_LOCKED;
        delta = 1;
      };
      break;
    case STATE_UNDECIDED:
      if (a && b) {
        encoderState = STATE_UNDECIDED;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_RIGHT_END;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_LEFT_END;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
  }

  uint32_t current_time = millis();
  static uint32_t switch_time = 0;
  const uint32_t bounce_time = 30;
  bool back = false;
  if (current_time - switch_time >= bounce_time) {
    if (switchState != s) {
      switch_time = current_time;
      back = s;
      switchState = s;
    }
  }
  return back;
}

best regards Stefan

and here is a version that uses two interrupts per encoder:

/*some rotary-encoders with mechanical switches are unreliable 
 * if you change rotation-direction. 
 * Because sometimes the switch is already opened sometimes not. 
 * This leads to wrong readings. some time ago user argmue 
 * posted a rotery-encoder-sketch that takes care of all 
 * these special situations
*/

// rotary-encoder with debounce written by user argmue

const byte ENCODER_A_PIN = 2;
const byte ENCODER_B_PIN = 3;

volatile int Counter = 0;  // variables used in interrupts-service-routines need addtional attribute volatile
int OldCounter = 0;


void isr_rotaryEncoder() {

  enum {STATE_LOCKED, STATE_TURN_RIGHT_START, STATE_TURN_RIGHT_MIDDLE, STATE_TURN_RIGHT_END, STATE_TURN_LEFT_START, STATE_TURN_LEFT_MIDDLE, STATE_TURN_LEFT_END, STATE_UNDECIDED};
  static uint8_t encoderState = STATE_LOCKED;
  bool a = !digitalRead(ENCODER_A_PIN);
  bool b = !digitalRead(ENCODER_B_PIN);
    
  switch (encoderState) {
    case STATE_LOCKED:
      if (a && b) {
        encoderState = STATE_UNDECIDED;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_LEFT_START;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_RIGHT_START;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
    case STATE_TURN_RIGHT_START:
      if (a && b) {
        encoderState = STATE_TURN_RIGHT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_RIGHT_END;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_RIGHT_START;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
    case STATE_TURN_RIGHT_MIDDLE:
    case STATE_TURN_RIGHT_END:
      if (a && b) {
        encoderState = STATE_TURN_RIGHT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_RIGHT_END;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_RIGHT_START;
      }
      else {
        encoderState = STATE_LOCKED;
        Counter--;
      };
      break;
    case STATE_TURN_LEFT_START:
      if (a && b) {
        encoderState = STATE_TURN_LEFT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_LEFT_START;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_LEFT_END;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
    case STATE_TURN_LEFT_MIDDLE:
    case STATE_TURN_LEFT_END:
      if (a && b) {
        encoderState = STATE_TURN_LEFT_MIDDLE;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_LEFT_START;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_LEFT_END;
      }
      else {
        encoderState = STATE_LOCKED;
        Counter++;
      };
      break;
    case STATE_UNDECIDED:
      if (a && b) {
        encoderState = STATE_UNDECIDED;
      }
      else if (!a && b) {
        encoderState = STATE_TURN_RIGHT_END;
      }
      else if (a && !b) {
        encoderState = STATE_TURN_LEFT_END;
      }
      else {
        encoderState = STATE_LOCKED;
      };
      break;
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("\nStart");  
  pinMode(ENCODER_A_PIN, INPUT);
  pinMode(ENCODER_B_PIN, INPUT);

  attachInterrupt(digitalPinToInterrupt(ENCODER_A_PIN),isr_rotaryEncoder, RISING);  
  attachInterrupt(digitalPinToInterrupt(ENCODER_B_PIN),isr_rotaryEncoder, RISING);  
}


void loop() {

  if (OldCounter != Counter) {
    OldCounter = Counter;
    Serial.print ("Counter ");  
    Serial.print (Counter);  
    Serial.println();
  }
}

best regards Stefan

tardishead:
Here is the error message

In file included from /Users/michaelburnham/Documents/Arduino/libraries/NewEncoder/examples/MultipleEncoders/MultipleEncoders.ino:2:0:
/Users/michaelburnham/Documents/Arduino/libraries/NewEncoder/NewEncoder.h:8:36: fatal error: utility\interrupt_pins.h: No such file or directory
#include "utility\interrupt_pins.h"
^
compilation terminated.
Error compiling for board Teensy 4.0.

When I wrote the NewEncoder library, the T4.0 and T4.1 weren't out yet. I have not since updated it for those boards. I don't have any T4.0/1 boards to test, but it did compile properly when I downloaded the latest versions of "interrupt_pins.h" and "direct_pin_read.h" from the PJRC Encoder Library GitHub and installed them locally in the "utility" directory.

So, you can give that a try. But, I think you've installed the library in the wrong place. Move the entire library NewEncoder library folder to "…/sketchbook/libraries". Then update the two files from the PJRC GitHub

gfvalvo:
When I wrote the NewEncoder library, the T4.0 and T4.1 weren't out yet. I have not since updated it for those boards. I don't have any T4.0/1 boards to test, but it did compile properly when I downloaded the latest versions of "interrupt_pins.h" and "direct_pin_read.h" from the PJRC Encoder Library GitHub and installed them locally in the "utility" directory.

So, you can give that a try. But, I think you've installed the library in the wrong place. Move the entire library NewEncoder library folder to "…/sketchbook/libraries". Then update the two files from the PJRC GitHub

nice that you answered at all. I would appreciate it very much if you would post all the links to the GitHub and the two files you mentioned. Your short mentioning leaves other users to do a lot of search
a quick google search did not come up with the right hit
https://www.google.de/search?lr=&newwindow=1&as_qdr=all&ei=ZPXTX-iUKq7ikgWnspD4Cg&q=PJRC+Encoder+GitHub&oq=PJRC+Encoder+GitHub

on PJRC itself
https://www.pjrc.com/teensy/td_libs_Encoder.html

this page re-directs to this hyper-buggy-super-old encoder-lib frm PaulStoffregen that fails when using it with mechanical-switch-rotary encoders

best regards Stefan

StefanL38:
a quick google search did not come up with the right hit
PJRC Encoder GitHub - Google Search

The very first hit from that Google search is the PJRC Encoder Library on GitHub.

The two files are in the utility folder, same as when it's installed on your computer.

And, it IS this library where I borrowed the two files needed:

StefanL38:
this page re-directs to this hyper-buggy-super-old encoder-lib frm PaulStoffregen that fails when using it with mechanical-rotary encoders

You don’t get it what good service is. So I’m gonna write the detailed description myself
and attach the files myself.

When the Teensy-Addon from PJRC

https://www.pjrc.com/teensy/td_download.html

is installed.
In the subdirectory of this installation similar to
C:\Program Files (x86)\Arduino\hardware*teensy*\avr\libraries\Encoder\utility*interrupt_pins.h*
this file interrupt_pins.h filesize 9kB (instead of 7kB)

and

C:\Program Files (x86)\Arduino\hardware*teensy*\avr\libraries\Encoder\utility*direct_pin_read.h*
this file direct_pin_read.h filesize 4kB (instead of 3kB)

are the right versions and must be copied to the subdirectory similar to

C:\Users\Stefan\Documents\Arduino\libraries*NewEncoder*\utility\

to make it compile with a teensy 4.0

best regards Stefan

direct_pin_read.h (3.82 KB)

interrupt_pins.h (8.3 KB)

StefanL38:
You don't get it what good service is.

I'm not sure what "service" you're looking for or think you're entitled to with regard to a piece of code I wrote for my own personal use and put on GitHub simply in case someone else found it useful.

It's free and you're under no obligation to use it. However, you're welcome to do so and to modify it for your own application needs.

Thanks so much Stefan
you've given me a lot of options. I'll get working

gfvalvo:
I'm not sure what "service" you're looking for or think you're entitled to with regard to a piece of code I wrote for my own personal use and put on GitHub simply in case someone else found it useful.

It's free and you're under no obligation to use it. However, you're welcome to do so and to modify it for your own application needs.

I believe you wrote the code for the PEC11R encoder that I am having trouble with? Bourns should put you on the payroll

So far, in my limited experience, I’ve run across two types of the mechanical rotary encoders:

  • Those that complete a full quadrature cycle for every detent of rotation.

  • Those that complete a full quadrature cycle for every two detents of rotation.

The Bourns PEC11 is an example of the first, while the Alps EC11 is an example of the second.

The code at my GitHub will work with either type by providing the proper argument to the class’s constructor, as explained in the README. There are also comments regarding this in the example code.

I actually “borrowed” the files you were having problems with (as well as that library’s direct pin read technique) from the PJRC Encoder library. So make sure you’ve updated them for the T4.0 and T4.1.

As I said, it looks to me the problem may be that you have the library installed in the wrong directory. Another issue MAY be a backward slash ("") vs forward slash ("/") thing. I’ve never used Linux, but understand there may be some differences in that compared to Windows.

Finally, I highly recommend reading the Buxtronix article I linked at the bottom of the README. It explains the algorithm I used in the library. This is the best encoder algorithm I’ve come across as you get de-bouncing for free.

Yes I was going to try the slash thing. I am on Mac
As for directory on a Mac there is no other place where it can be stored.

tardishead:
As for directory on a Mac there is no other place where it can be stored.

Macs don't have a .../sketchbook/library directory?