How to connect rotary encoder to ESP32

Thread Starter

Meca10

Joined Jun 15, 2021
27
Hello everyone

I tried to connect a rotary encoder with ESP32. However I can't to connect the Esp32 inputs to A and B encoder outputs because I have to polarized the encoder to minimum to 5 volts and the maximum voltage value for each ESP GPIO port is 3.3 volts. I used a tension divider on 25 and 26 ESP pins. Also I used the YES gate CD4050 for level the voltaje value without success in two cases.

Anyone can give me an idea to instrument the encoder outputs.

Thanks.
 

John P

Joined Oct 14, 2008
2,025
Try running the encoder on 3.3V even though it says it needs 5V. Less than the specified voltage won't do it any harm (unlike plugging your ESP32 into 5V!) and it might actually work OK.
 

Thread Starter

Meca10

Joined Jun 15, 2021
27
hi Meca,
Please post your Sketch.
Are you using 4050 as a 5V to 3V3 level shifter.???
E
Hi Eric

Yes I tried to make a voltaje shifter you can see in schematic 2. First to all, I connect two resistor divider for each encoder output (schematic 1). The poblem is that esp32 never dectect the hardware interrupt.
 

Attachments

BobTPH

Joined Jun 5, 2013
8,807
A simple voltage divider should work. Are you sure your code is correct? Try writing a program that controls an LED based on the output, then see what happens when you rotate the shaft.
 

BobTPH

Joined Jun 5, 2013
8,807
Don’t know enough about ESP32 to look at the code. You need to debug it. First, see if the input is changing when rotate ithe encoder shaft as I previously suggested.
 

ericgibbs

Joined Jan 29, 2010
18,766
hi Meca,
Modified your Sketch, it now works with a rotary encoder switch OK, needs tidying up a little.

E
BTW: some other interrupt source was triggering your isr's, counting all the time.
Added the WiFi libs , so that we could stop WiFi

C-like:
// Encoder rotary switch test OK 08072022/57

#include <ETH.h>
#include <WiFi.h>
#include <WiFiAP.h>
#include <WiFiClient.h>
#include <WiFiGeneric.h>
#include <WiFiMulti.h>
#include <WiFiScan.h>
#include <WiFiServer.h>
#include <WiFiSTA.h>
#include <WiFiType.h>
#include <WiFiUdp.h>

#define CHANNEL_A 25 //Green
#define CHANNEL_B 26 //White
volatile long temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder

portMUX_TYPE synch = portMUX_INITIALIZER_UNLOCKED;

void ai0() {
  if (CHANNEL_B == LOW) {
    counter++;
  } else {
    counter--;
  }
}

void ai1() {
  if (CHANNEL_A == LOW) {
    counter--;
  } else {
    counter++;
  }
}
void setup() {
  WiFi.mode(WIFI_OFF);
  btStop();
  Serial.begin (115200);
  Serial.println ("Ready");

  pinMode(CHANNEL_A, INPUT_PULLUP);
  pinMode(CHANNEL_B, INPUT_PULLUP);

  attachInterrupt(CHANNEL_A, ai0, RISING);
  attachInterrupt(CHANNEL_B, ai1, RISING);
}

void loop() {
  // Send the value of counter
  if ( counter != temp ) {
    Serial.println (counter);
    temp = counter;
  }
}
 

Attachments

Last edited:

Thread Starter

Meca10

Joined Jun 15, 2021
27
hi Meca,
Modified your Sketch, it now works with a rotary encoder switch OK, needs tidying up a little.

E
BTW: some other interrupt source was triggering your isr's, counting all the time.
Added the WiFi libs , so that we could stop WiFi

C-like:
// Encoder rotary switch test OK 08072022/57

#include <ETH.h>
#include <WiFi.h>
#include <WiFiAP.h>
#include <WiFiClient.h>
#include <WiFiGeneric.h>
#include <WiFiMulti.h>
#include <WiFiScan.h>
#include <WiFiServer.h>
#include <WiFiSTA.h>
#include <WiFiType.h>
#include <WiFiUdp.h>

#define CHANNEL_A 25 //Green
#define CHANNEL_B 26 //White
volatile long temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder

portMUX_TYPE synch = portMUX_INITIALIZER_UNLOCKED;

void ai0() {
  if (CHANNEL_B == LOW) {
    counter++;
  } else {
    counter--;
  }
}

void ai1() {
  if (CHANNEL_A == LOW) {
    counter--;
  } else {
    counter++;
  }
}
void setup() {
  WiFi.mode(WIFI_OFF);
  btStop();
  Serial.begin (115200);
  Serial.println ("Ready");

  pinMode(CHANNEL_A, INPUT_PULLUP);
  pinMode(CHANNEL_B, INPUT_PULLUP);

  attachInterrupt(CHANNEL_A, ai0, RISING);
  attachInterrupt(CHANNEL_B, ai1, RISING);
}

void loop() {
  // Send the value of counter
  if ( counter != temp ) {
    Serial.println (counter);
    temp = counter;
  }
}
Hi Eric

Can you saw the Schematics on last image?

I test the CD4050 output when I polarized to 3.3 volts and send 5 volts to input and CD4050 output is 0 volts.
Do you have any idea of the reason happen this?
 

dendad

Joined Feb 20, 2016
4,451
Check your encoder to see if it has open collector outputs.
Do you get any output pulses with nothing connected to the outputs?
I use an encoder that looks similar and the encoder runs on 5V but the outputs are open collector so are pulled up to 3.3V with 2K2 resistors for the ESP32.
This is the encoder...
1657283730057.png
https://www.ebay.com.au/itm/100-200-360-400-500-600P-R-Photoelectric-Incremental-Rotary-Encoder-5-TFZTHFUK/264813336983?ssPageName=STRK:MEBIDX:IT&var=564637649454&_trksid=p2057872.m2749.l2649

And my circuit.
1657283582814.png
If you want to see my progress, here is a post..
http://www.sadarc.org/xenforo/uploa...th-adaptive-step-rate-and-vernier-display.11/
It is a while since I worked on it. I hope there is some info there to help you.
 

ericgibbs

Joined Jan 29, 2010
18,766
Hi Meca,
This Sketch is an alternative method for the Encoder.
My Encoder outputs a HIGH when at rest. LOW for rotation.
This use only one ISR
E
BTW: Have you solved the 4050 hardware problem, the level shifter should work.

C-like:
// Encoder rotary switch test OK 08072022/57 V2.0
// Meca V2.0
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>

#define CHANNEL_A 25
#define CHANNEL_B 26
int ChanAnew = LOW;                // Current state of Pin A
int ChanAlast = ChanAnew;      // Last read value of Pin A

volatile long temp, counter = 0; 

portMUX_TYPE synch = portMUX_INITIALIZER_UNLOCKED;

void ai0() {
  ChanAnew = digitalRead(CHANNEL_A);

  // 1 step
  if ((ChanAlast == LOW) && (ChanAnew == HIGH)) {

    if (digitalRead(CHANNEL_B) == HIGH) {
      counter++;
    } else {
      counter--;
    }
  }
  ChanAlast = ChanAnew;
}

void setup() {
  WiFi.mode(WIFI_OFF);
  btStop();
  Serial.begin (115200);
  Serial.println ("Ready");

  pinMode(CHANNEL_A, INPUT_PULLUP);  // Note PULL UP Set
  pinMode(CHANNEL_B, INPUT_PULLUP);
  attachInterrupt(CHANNEL_A, ai0, CHANGE);
}

void loop() {
  // Send the value of counter
  if ( counter != temp ) {
    Serial.println (counter);
    temp = counter;
  }
}
 

Attachments

dendad

Joined Feb 20, 2016
4,451
Ah, once again I miss an important point. It just show that skimming through the replies quickly leads to errors. Sorry!
But, if an open collector encoder is selected for next time, it does make interfacing easier.
 

ericgibbs

Joined Jan 29, 2010
18,766
Hi Meca,
This is a faster version of the program, the ISR is located in the ESP32 RAM.
Tested using a continuous rotation encoder, 9000 steps per 360deg revolution. CW=Increment, CCW=Decrement.
Just for Demo converted the Count to Degrees rotation.
Added a Counter ZeroSet P/B routine.
Used a level shifter module [not a 4050] between the Encoder +5V levels and the ESP32 3.3V input pins.

E

C-like:
// Rotary Encoder test OK 08072022/57 V3.0
// Meca V2.0
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiServer.h>

#define CHANNEL_A 25
#define CHANNEL_B 26
#define ZeroSet 0

int ChanAnew = LOW;
int ChanAlast = ChanAnew;

volatile float temp, counter = 0;

portMUX_TYPE synch = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR ai0() {
  portENTER_CRITICAL(&synch);
  ChanAnew = digitalRead(CHANNEL_A);

  // 1 step
  if ((ChanAlast == LOW) && (ChanAnew == HIGH)) {

    if (digitalRead(CHANNEL_B) == HIGH) {
      counter++;
    } else {
      counter--;
    }
  }
  ChanAlast = ChanAnew;
  portEXIT_CRITICAL(&synch);
}

void setup() {
  WiFi.mode(WIFI_OFF);
  btStop(); // Stop Bluetooth
  Serial.begin (115200);
  Serial.println ("Encoder Ready");

  pinMode(CHANNEL_A, INPUT_PULLUP);  // Note PULL UP Set
  pinMode(CHANNEL_B, INPUT_PULLUP);
  pinMode(ZeroSet, INPUT_PULLUP);

  attachInterrupt(CHANNEL_A, ai0, CHANGE);
}

void loop() {
  // Send the value of counter
  if ( counter != temp ) {
    Serial.print (counter);
    Serial.print ("  Angle=" );
    Serial.println (counter / 25, 1);
    temp = counter;
  }
  if (digitalRead(ZeroSet) == LOW) {
    counter = 0;
  }
}
 

Attachments

Top