Rotary Encoder

HI all, sorry for my bad english i speak french.

I have a problem with my rotary encoder i have the code:

if (digitalRead(3) == HIGH) {
    Serial.print("B1");
    delay(72);
    Serial.print("B2");
  } else {
    if (digitalRead(4) == HIGH) {
      Serial.print("C1");
      delay(72);
      Serial.print("C2");
    }

But when i turn rotary encoder to left or right i obtain:
C1C2B1B2C1C2C1C2C1C2C1C2C1C2

There are B1B2 and i don't have turn to the left.

Why ? Help me please

Did you study how a rotary encoder works?
There are tons of material in this forum and a lot of attempts to read a rotary encoder.

How is your setup? Do you use a library? (apparently not, looking at your code fraction).
Pls post your entire code.

I'm a beginner.
My code is :

void setup() {
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);

    Serial.begin(115200);
}

void loop() {
        
  if (digitalRead(3) == HIGH) {
    Serial.print("B1");
    delay(72);
    Serial.print("B2");
  } else {
    if (digitalRead(4) == HIGH) {
      Serial.print("C1");
      delay(72);
      Serial.print("C2");
    }
  }
  
}

I just want to have B1 and B2 in monitor when i turn to right my rotary encoder and C1-C2 when i turn to left. :confused:

With that code, not going to happen... Indeed read a bit more about the rotary encoders.

Have you an example please ?
I want a basic code
Thank you

Let's see... Or here...

Simply said, it does not simply gives you a pulse on pin A for left and pin B for right. No matter the direction it will always pulse both pins. It's only the order which is different. A then B => direction A, B then A => direction B.

Google is your friend (as long as you're doing an apolitical search). I just searched "Arduino rotary encoder" and got 247,000 hits. I think one of those should help you.

I have already see on google but i don't understand..
And i post on arduino.cc because i don't have found solution.

I'm not an expert in electricity, i just want to have a simple arduino sketch for detect when i turn left or when i turn right with a rotary encoder.

I speak french but 95% results on google are english tutorials :confused:

  1. Pin2 is not used in your code
  2. Pin3 and Pin4 are declared as OUTPUT - you have apparently wired the rotary encoder to them

If you want the encoder to be read - you have to declare those pins as INPUT and, if you don't use external resistors, you have to declare them as INPUT_PULLUPs (using Arduino's internal resistors.

But it seems that you have not yet understood at all, how a rotary works.
To give you a short information:

A rotary's pins (let's call them A, B and GND) are producing continuously HIGHs and LOWs being either connected with the common GND or being open (the HIGHs are only HIGHs if A and B are connected to the Arduino with pullup resistors).

The sequence of the HIGHs and LOWs (of A AND B) is a bit different when you turn the shaft CW or CCW -> thus you can distinguish the direction and use it in your code.

Unfortunately this is not yet the whole story - there are more things to be considered like
a) debouncing and
b) timing (code speed to recognize changes in the pattern of the input signals).

Therefore you either need
a) a "debouncing" code or some hardware prerequisites and
b) either an interrupt assisted code or a smart "interupt-less" code AND avoiding any delays in your code

It would also be helpful if you could tell us a bit about the goal of your project as this could determine what else (or what not) has to be considered in the code.

Then just go with a library to do the work.

And, yes, 95% of the pages are English. That's THE language on the web. And you seem to speak English pretty well so I don't see a problem :slight_smile:

void setup() {
    pinMode(3, INPUT_PULLUP);
    pinMode(4, INPUT_PULLUP);

    Serial.begin(115200);
}

void loop() {
        
  if (digitalRead(3) == LOW) {
    Serial.print("B1");
    delay(72);
    Serial.print("B2");
  } else {
    if (digitalRead(4) == LOW) {
      Serial.print("C1");
      delay(72);
      Serial.print("C2");
    }
  }
  
}

This is my new code, but i have the same problem

Edit:
My projet is create a plane board with arduino (mega with custom firmware), i have multiples buttons, switch, rotary.

With my code simple button work perfectly, switch same, but rotary don't work.

Antoine,

I have a simple rotary code which works with (in my opinion) the best rotary library i have ever seen.
Will post it, when I have modified it in a way you could use it in your project.

Before I do that: what is the reason for using the delays(72) in your code?
I have no idea what they are meant for.

No matter which what you turn the knob, both pins will read low.

You need to figure out which goes low first, then that will give you direction. Then you need to keep track of how many times it does from low to high. That will give you a count.

This is a very nice example of how they work;

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

Because when i use the code in hid controller i need to do :

setButton(&joyReport, button);
sendJoyReport(&joyReport);
delay(72);
clearButton(&joyReport, button);
sendJoyReport(&joyReport);

Edit: and 72 is the pulse width

Antoine,

here is the rotary code with your "B1..C2" and delay(72) included, Works perfectly here.
If your rotary has a built-in button, you can attach the button to Pin5.

It might be that you have to change pins 3 and 4 (easiest: in the code) if clockwise/counterclockwise is giving "reverse" signals.

For your convenience pls find attached the used rotary library.

Pls give us a feedback if that works for you.

#include <rotary.h>

/* Example sketch for Rotary library. 
 * Original library written by Ben Buxton (available at http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html)
 * Extended to support encoders with a push button
 *
 * Simple demonstration that will output to the serial monitor when the enocder is turned
 * or the button is pressed.
 * 
 * Modified by Raimund P. Trierscheid
 * 
 */


// Initialize the Rotary object
// Rotary(Encoder Pin 1, Encoder Pin 2, Button Pin)
Rotary r = Rotary(4, 3, 5);                            // change to (3, 4, 5) if direction has to be reversed

void setup() {
  Serial.begin(9600);
  Serial.println("Initialized");
  Serial.println();
}

void loop() {
  // During each loop, check the encoder to see if it's been changed.
  volatile unsigned char val = r.process();

  // if the encoder has been turned, check the direction
  if (val) {
    if (val == r.clockwise()) {
      Serial.print("B1");
      delay(72);
      Serial.print("B2");                    
    }
    else if (val == r.counterClockwise()) {
      Serial.print("C1");
      delay(72);
      Serial.print("C2");
    }
  }

  // Check to see if the button has been pressed.
  // Passes in a debounce delay of 20 milliseconds
  if (r.buttonPressedReleased(20)) {
    Serial.println("Button pressed");
  }
}

Rotary_Button.zip (6.59 KB)

It work perfectly thank you ! :slight_smile:

Thank you for your feedback and good luck with your project progress.

If I could have given Ben Buxton 1000 karma points - he would have deserved it.
The library helped me to save a lot of frustration last year when I made my first steps with rotary encoders and dozens of libraries which didn't work at all or caused very strange behavior of my project.

Well the solution works but it does have one tiny flaw: It uses delay!

In this case, with a 72 ms delay you're able to get away with it, but I'll show you how to do the same without delay by using the Automaton framework.

First I start with a basic sketch and define some Automaton objects: an encoder, two leds and a button. I call the Automaton scheduler from the loop() function.

#include <Automaton.h>

Atm_encoder encoder;
Atm_led led_up, led_down;
Atm_button button;

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

void loop() {
  automaton.run();
}

Now it's time to initialize the led and button components in setup().

  led_up.begin( 4 ) // Led on pin 4
    .blink( 72, 0, 1 );
  led_down.begin( 5 ) // Led on pin 5 
    .blink( 72, 0, 1 );

  button.begin( 18 ) // Encoder button on pin 18
    .onPress( [] ( int idx, int v, int up ) {
      Serial.println( "Button press" );
    });

Both leds are setup to give a single (1) pulse of 72 ms when triggered.
The button uses a lambda expression (more about this in the Automaton Introduction page).

The only thing left is to make the encoder object trigger the led objects whenever the shaft rotates CW (up) of CCW (down), also in setup():

  encoder.begin( 2, 3 ) // Encoder on pins 2 & 3
    .onChange( ATM_UP, led_up, led_up.EVT_BLINK )
    .onChange( ATM_DOWN, led_down, led_down.EVT_BLINK );

That's all. Whenever the encoder moves it triggers one of the led pulses. The button thing just works in parallel. No delay() was used in this sketch and everything remains fully responsive even if the pulses are changed to 7200 ms.

Automaton is an event based framework, therefore the syntax and program flow are different from what you're used to seeing here. It is very well suited to any Arduino sketch that uses combinations of delays and asynchronous inputs.

If the syntax and logic of this sketch seem strange to you there's a short introduction on the project's Github wiki that explains the concepts and syntax.

encoder_pulse.ino (602 Bytes)

@Tinkerspy

I tried your library (framework :slight_smile: ) and the sketch and it worked perfectly.
Will have a closer look into this method after having finished my current project.

Will then try to replace some code of this very big program to see if this could replace some parts of the code. Maybe it can save some SRAM and eventually it can help to simplify the readability and serviceability.

rpt007:
@Tinkerspy

I tried your library (framework :slight_smile: ) and the sketch and it worked perfectly.
Will have a closer look into this method after having finished my current project.

Will then try to replace some code of this very big program to see if this could replace some parts of the code. Maybe it can save some SRAM and eventually it can help to simplify the readability and serviceability.

Great news, but be aware that every library (and framework) has its overhead. With Automaton the number of running machines (each of which has some overhead) can sometimes fill up your SRAM.

If you try to run 30 instances of the led machine on an UNO you'll be pushing the memory limits. Of course that can easily be remedied by creating a custom state machine that controls 30 leds at once in which case you'll have the overhead of only one.

I'd be interested to hear about your experience!