Mehanical rotary encoder - fine tunning ?

Hi to all.

I have two different codes but the one that i want to use is not working.

This one is working version:
int state, prevstate = 0, count = 0;
int nextEncoderState[4] = { 2, 0, 3, 1 };
int prevEncoderState[4] = { 1, 3, 0, 2 };

void setup()
{
pinMode(7, INPUT);
pinMode(5, INPUT);
pinMode(6, OUTPUT);
digitalWrite(6, LOW);
digitalWrite(5, HIGH);
digitalWrite(7, HIGH);
Serial.begin(9600);
}

void loop()
{
state = (digitalRead(7) << 1) | digitalRead(5);
if (state != prevstate) {
if (state == nextEncoderState[prevstate]) {
count++;
} else if (state == prevEncoderState[prevstate]) {
count--;
}
Serial.println(count, DEC);
prevstate = state;
}
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
When i start to spin encoder i get one LED blink and one serial output, which is OK.
//---------------------------------------------------------------------------------

Code in attach is the code with interrupts, but this one is not working ( there is no serial output ).

static int pinA = 5; // Our first hardware interrupt pin is digital pin 2
static int pinB = 7; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

void setup() {
pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
Serial.begin(9600); // start the serial monitor link
}

void PinA(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPos --; //decrement the encoder's position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
sei(); //restart interrupts
}

void PinB(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPos ++; //increment the encoder's position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
sei(); //restart interrupts
}

void loop(){
if(oldEncPos != encoderPos) {
Serial.println(encoderPos);
oldEncPos = encoderPos;
}
}

//---------------------------------------------------------------------------
Any ideas why the second code shows no output ?
HW connection: all 3 pins are connected to 5/6/7 and in second case i have try with 5/6, 5/7, 6/7 and one pin to GND but none of them worked. This encoder will be hooked up to motor shaft and main purpose is to count motors RPM. Regarding count, some action needs to be triggered.

After a dozen posts, you should know how to properly post code here. Since that's not the case, please read the first four posts at the top of this Forum for the proper way to post here, especially using code tags when presenting code listings.

static int pinA = 5; // Our first hardware interrupt pin is digital pin 2
static int pinB = 7; // Our second hardware interrupt pin is digital pin 3
 attachInterrupt(0,PinA,RISING); // set an interrupt on PinA
  attachInterrupt(1,PinB,RISING); // set an interrupt on PinB,

What Arduino has interrupt 0 on pin 5 and interrupt 1 on pin7?

@cattledog
:-), i corrected this but still no output.

I have added one serial print in loop and i can see it on serial output but it looks like that if case is never triggered ?
Basically, there is no output on serial monitor.

A.

Show us, both the corrected code and the output. Don't forget the code-tags though :wink:

there nothing much to show. I changed 5 and 7 with 2 and 3 :slight_smile:

static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
void loop(){
  //Serial.print("Start");
  //Serial.print('\n'); 
  if(oldEncPos != encoderPos) {
    Serial.println(encoderPos);
    oldEncPos = encoderPos;
  }
}

If i uncomment serial print i can see "start" message, but that's only thing i can see.
There's no rotary count or any other character....

btw. this is the tutorial that am following:

And my wires are connected on the same way...

A.

It might not be much, but if we have to try and make the same changes as you did it's a recipe for differences. Aka, post ALL the code again.

/*******Interrupt-based Rotary Encoder Sketch*******
by Simon Merrett, based on insight from Oleg Mazurov, Nick Gammon, rt, Steve Spence
*/

static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

void setup() {
  pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
  attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
  Serial.begin(115200); // start the serial monitor link
}

void PinA(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
  if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPos --; //decrement the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void PinB(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
  if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    encoderPos ++; //increment the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void loop(){
  if(oldEncPos != encoderPos) {
    Serial.println(encoderPos);
    oldEncPos = encoderPos;
  }
}

If i uncomment serial print i can see "start" message, but that's only thing i can see.
There's no rotary count or any other character....

I can not confirm your issue. When I run your code I see the count increment/decrement every 4 quadrature transitions.

//check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge

You appear to be looking for count changes at detents and the output is what I would see if there were a detent every 4 transitions.

Have you verified the detent position according to note 5 of the tutorial?

Make sure you find out where the detent state is for your encoder and adapt your code accordingly. My example uses an encoder whose pins are both disconnected from ground and are pulled high by their respective input pullup resistors. This drives my selection of a RISING interrupt. If both pins were connected to ground when at detent, they would need code which was looking for FALLING pin voltage.

I am not using one of the mechanical encoders shown in the tutorial, but an optical one, and my encoder is connected to Vcc and uses external pull ups on the A/B outputs. I don't have one of the mechanicals to test with your code.

  attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
  attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)

That code is NOT setting an interrupt on PinA. PinA is the (stupid) name for a function that is to be executed when an interrupt of the right kind happens on the pin associated with interrupt 0.

Surely you can think of a better name for the function than PinA().

@paulS
-it's not my code. Please look at previous posts.

@cattledog
i will check your suggestions. Strange, i have tested few different HW connections and nothing.
Just to be on the same track, this is the encoder that am using:

arnix:
-it's not my code. Please look at previous posts.

When you use code in YOUR project, it becomes YOUR code.

arnix:
btw. this is the tutorial that am following:
https://www.instructables.com/id/Improved-Arduino-Rotary-Encoder-Reading/

In general, I'm suspect of any Arduino code found on instructables. Don't know about this code. But the fact that the author thinks it's necessary to turn 'off' and then 'on' interrupts while inside an ISR doesn't bode well.

So, I’m not really inclined to dig into this code. But, if you would like take a look at some interrupt-driven code based on the State Machine concept that works well, check out:GitHub - gfvalvo/NewEncoder: Rotary Encoder Library. It works both with encoders that produce one complete quadrature cycle every detent and those that produce one complete quadrature cycle for every two detents. See the ReadMe and examples.

You're welcome to use it as-is or modify it to your needs.

@gfvalvo
I downloaded zip file / extrected and i can see that lib is installed but when i run example file singleencoder.ino
i get error : no such file or directory --> /utility / interrupts_pins.h

I can see this file in my arduino lib directory so it's there....

?

A.

Which board are you using?

arnix:
I downloaded zip file / extrected and i can see that lib is installed but when i run example file singleencoder.ino
i get error : no such file or directory --> /utility / interrupts_pins.h

I can see this file in my arduino lib directory so it's there....

That example has been tested on an Uno and other Arduino-type boards. Check your installation and post the COMPLETE pathname / filename for:

NewEncoder.cpp
NewEncoder.h
direct_pin_read.h
interrupt_pins.h
SingleEncoder.ino

Also, try exiting and restarting the Arduino IDE.

Error message:

Arduino: 1.8.8 (Linux), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from /home/john/Arduino/libraries/NewEncoder-master/examples/SingleEncoder/SingleEncoder.ino:8:0:
/home/john/Arduino/libraries/NewEncoder-master/NewEncoder.h:8:36: fatal error: utility\interrupt_pins.h: No such file or directory
#include "utility\interrupt_pins.h"

^
compilation terminated.
exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.


Path to the file ( file is in utility folder ):
~/Arduino/libraries/NewEncoder-master/utility$

A.

There should be a "libraries" folder inside your "sketchbook" folder. Try putting the entire "NewEncoder" folder (remove the "-master" part) there.

Since this isn't a code problem but a tool / configuration problem, I have no other suggestions. Perhaps someone more familiar with the IDE's inner workings can help.