Encoder doesn't work with NodeMCU

Hello
I am trying to transfer an old programm from an Arduino Nano to an NodeMCU but as soon as I use the Encoder Library the board freezes. I am completly new to the ESP thing and trying to educate myself as best as I can but I can’t find why this is happening.
Here is an example code which also doesn’t work.
Hope someone can help me to find a solution to that.

#include <Encoder.h>
Encoder myEnc(13, 12);

int bt_up = false;
int bt_down = false;
long oldPosition  = -999;
const int BUTTON_PIN = 15; //Encoder pushbutton pin

const int SHORT_PRESS_TIME = 850;
const int LONG_PRESS_TIME  = 850;

int lastState = LOW;  // the previous state from the input pin
int currentState;     // the current reading from the input pin
unsigned long pressedTime  = 0;
unsigned long releasedTime = 0;
bool isPressing = false;
bool isLongDetected = false;

void setup() {
  Serial.begin(9600);
}

void loop() {

  long newPosition = myEnc.read() / 4;
  if (newPosition > oldPosition) {
    oldPosition = newPosition;
    bt_up = true;
  }
  if (newPosition < oldPosition) {
    oldPosition = newPosition;
    bt_down = true;
  }
  Serial.println(newPosition);

  // read the state of the switch/button:
  currentState = digitalRead(BUTTON_PIN);

  if (lastState == HIGH && currentState == LOW) {       // button is pressed
    pressedTime = millis();
    isPressing = true;
    isLongDetected = false;
  } else if (lastState == LOW && currentState == HIGH) { // button is released
    isPressing = false;
    releasedTime = millis();

    long pressDuration = releasedTime - pressedTime;
  }

  if (isPressing == true && isLongDetected == false) {
    long pressDuration = millis() - pressedTime;

    if ( pressDuration > LONG_PRESS_TIME ) {
      isLongDetected = true;
    }
  }
  // save the the last state
  lastState = currentState;
}

Try: GitHub - gfvalvo/NewEncoder: Rotary Encoder Library
Start with the SingleEncoder example. Run it as-is, make no changes except for the pin numbers in the constructor to match the pins your encoder is connected to. Once, that's known working, integrate it into your application code.

EDIT:
Also provide a link to the datasheet for the specific encoder you're using.

That worked. But how can I get rid off the highest/lowest value count?
The encoder I use is a ky-040 https://www.handsontec.com/dataspecs/module/Rotary%20Encoder.pdf

gfvalvo is such a modest guy ;-))

I modified your code to use the NewEncoder-library which can be downloaded from here

This library is much more reliable than the encoder.h

use the download-button and install in the Arduino-IDE with Sketch - include library Add-zip-library

So here is your code modified to use NewEncoder
two changes:
you need to call the begin-function in setup
newencoder delivers its value without .read

you can define min/max limits

//#include <Encoder.h>
//Encoder myEnc(13, 12);
#include "NewEncoder.h"
NewEncoder myEnc(12, 13, -10, 10, 0, FULL_PULSE);


int bt_up = false;
int bt_down = false;
long oldPosition  = -999;
const int BUTTON_PIN = 15; //Encoder pushbutton pin

const int SHORT_PRESS_TIME = 850;
const int LONG_PRESS_TIME  = 850;

int lastState = LOW;  // the previous state from the input pin
int currentState;     // the current reading from the input pin
unsigned long pressedTime  = 0;
unsigned long releasedTime = 0;
bool isPressing = false;
bool isLongDetected = false;

//#include
void PrintFileNameDateTime()
{
  Serial.println("Code running comes from file ");
  Serial.println(__FILE__);
  Serial.print("  compiled ");
  Serial.print(__DATE__);
  Serial.print(" ");
  Serial.println(__TIME__);
}


boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod )
  {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  
  if (!myEnc.begin()) {
    Serial.println(F("Encoder Failed to Start. Check pin assignments and available interrupts. Aborting."));
    while (1) {
    }
  }  
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 500);

  if ( TimePeriodIsOver(MyTestTimer, 50) ) {
    //delay(100);
    //long newPosition = myEnc.read() / 4;
    long newPosition = myEnc;
    if (newPosition > oldPosition) {
      oldPosition = newPosition;
      bt_up = true;
    }
    if (newPosition < oldPosition) {
      oldPosition = newPosition;
      bt_down = true;
    }
    Serial.println(newPosition);
    //Serial.println(myEnc);

    // read the state of the switch/button:
    currentState = digitalRead(BUTTON_PIN);

    if (lastState == HIGH && currentState == LOW) {       // button is pressed
      pressedTime = millis();
      isPressing = true;
      isLongDetected = false;
    } else if (lastState == LOW && currentState == HIGH) { // button is released
      isPressing = false;
      releasedTime = millis();

      long pressDuration = releasedTime - pressedTime;
    }

    if (isPressing == true && isLongDetected == false) {
      long pressDuration = millis() - pressedTime;

      if ( pressDuration > LONG_PRESS_TIME ) {
        isLongDetected = true;
      }
    }
    // save the the last state
    lastState = currentState;
  }
}

I added my standard utils PrintFileNameDateTime, IfTimePeriodIsoVer and HearBeatBlink

but you can boild down your code to this version

/* SingleEncoder.cpp
   Created on: Jul 25, 2018
   Author: GFV
*/
#include "Arduino.h"
#include "NewEncoder.h"

// Pins 2 and 3 should work for many processors, including Uno. See README for meaning of constructor arguments.
// Use FULL_PULSE for encoders that produce one complete quadrature pulse per detnet, such as: https://www.adafruit.com/product/377
// Use HALF_PULSE for endoders that produce one complete quadrature pulse for every two detents, such as: https://www.adafruit.com/product/377
// NewEncoder encoder(IO_Pin_A, IO_Pin_B, MinValue, MaxValue, InitialValue, HALF_PULSE); //HALF_PULSE FULL_PULSE

NewEncoder encoder(12, 13, -10, 10, 0, FULL_PULSE);

int16_t prevEncoderValue;

void setup() {
  int16_t value;

  Serial.begin(115200);
  //delay(2000);
  Serial.println(F("Starting"));
  if (!encoder.begin()) {

    Serial.println(F("Encoder Failed to Start. Check pin assignments and available interrupts. Aborting."));
    while (1) {
    }
  } else {
    value = encoder;
    Serial.print(F("Encoder Successfully Started at value = "));
    Serial.println(value);
  }
}

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

  up = encoder.upClick();
  down = encoder.downClick();
  if (up || down) {
    currentValue = encoder;
    if (currentValue != prevEncoderValue) {
      Serial.print(F("Encoder: "));
      Serial.println(currentValue);
      prevEncoderValue = currentValue;
    } else if (up) {
      Serial.println(F("Encoder at upper limit."));
    } else {
      Serial.println(F("Encoder at lower limit."));
    }
  }
}

best regards Stefan
Edit: I tested it with a KY40-encoder

malte_entzmin:
That worked. But how can I get rid off the highest/lowest value count?
The encoder I use is a ky-040 https://www.handsontec.com/dataspecs/module/Rotary%20Encoder.pdf

32767
would this range be big enough?
if not Then you would have to take care of the rollover / rollunder of the variable
@GFValvo: how about adding a ignore min/max-feature if parameters for min/max are zero?

or when just using

  up = encoder.upClick();
  down = encoder.downClick();

do they result in a true even if min/max is reached?

best regards Stefan

I tried using "upClick" and "downClick" but it doesn't seem to work.
I use the encoder to navigate in a menu and set variables. So I don't know what the max value is. It could work 99% of the time but it needs to be 100%.
Using the upClick and downClick would be perfekt.
Maybe there is a better way to achieve my goal? I don't need a counter from the encoder. I just need it to trigger an up or down function.

Hope I can use this library. It really works really well.

calling upclick / downclick deliver one time a true if a "click" occured. Then they result in a false until a new click occured.
So this should work very good. Post your code for analysing hwo use upclick/downclick.

About the min/max-values does your adjusting values exceed the number 32.000 ? Which means the user has to scroll and scroll and scroll and ..... until he reaches 64.000?

I guess not so if you simply set min max to

ewEncoder encoder(12, 13, -32000, 32000, 0, FULL_PULSE);

your min/max is -32000 / + 32000

additonal newEncoder offers a function setValue to give the encoder a new value to start from
for scrolling through menus another method is
if you reach the min set value to max or if reaching max setvalue to min

best regards Stefan

I will try upClick and downClick again and report back. Otherwise setValue could work aswell. I can set the value when entering a new Submenu or variable.
Thank you very much. I will try that tomorrow (it's night time in germany) and will report back.

UpClick/downClick worked but now I am having another problem. If I am turning the Encoder a little faster the nodemcu freezes and restarts. I haven‘t had that problem with an arduino nano and the old code. I just found some threats about problems with interrupts and i2c (i am using an oled display) but nothing that helps me. Could this be the problem? And does anyone has an idea what I could try?

Okay. I found out it has to do with fastLED Library. Erasing that part of the code made the node work. Now I have to figure out how to work around that and how i can use fastLED