4

This question is regarding a project using an Arduino Uno.

I have one of these quadrature rotary encoders.

I'm using a slightly modified version of the code from the article, Quadrature Encoder too Fast for Arduino (with Solution), which uses a library called digitalwritefast.

My version of the code on pastebin - I modified to use different pins for the Uno and a single encoder:

#include <digitalWriteFast.h>  // library for high performance reads and writes by jrraines

#define c_LeftEncoderInterrupt 0
#define c_LeftEncoderPinA 2
#define c_LeftEncoderPinB 3

volatile bool _LeftEncoderBSet;
volatile long _LeftEncoderTicks = 0;

void setup()
{
  Serial.begin(115200); 
  pinMode(c_LeftEncoderPinA, INPUT);      
  digitalWrite(c_LeftEncoderPinA, LOW); 
  pinMode(c_LeftEncoderPinB, INPUT);
  digitalWrite(c_LeftEncoderPinB, LOW);
  attachInterrupt(c_LeftEncoderInterrupt, HandleLeftMotorInterruptA, RISING);
}

// Interrupt service routines for the left motor's quadrature encoder
void HandleLeftMotorInterruptA()
{
  _LeftEncoderBSet = digitalReadFast2(c_LeftEncoderPinB);   // read the input pin
  _LeftEncoderTicks -= _LeftEncoderBSet ? -1 : +1;
}

void loop()
{
  Serial.print(_LeftEncoderTicks);
  Serial.print("\n");
  delay(20);
}

I am attaching output A of the encoder to pin 2 and output B to pin 3.

This setup works fine and I can detect turns in both directions, but my problem is, if I set pin B to any other pin, I get positive direction only (regardless of the direction in which the encoder is turned) - as if pin B isn't plugged in at all (I am modifying c_LeftEncoderPinB accordingly).

I'm assuming that this is something to do with pin 3 being the only other interrupt pin on the Uno (I can't see anything else unique about that pin). Yet I don't know why because the interrupt is on pin A (we're reading the value of pin B in that interrupt, though).

3
  • The code you started from was never meant for bi-directional rotary encoders. I'd suggest looking for a proper rotary encoder library (that also handles de-bouncing). That might safe you some headaches.
    – Gerben
    Oct 30, 2014 at 19:39
  • What happens if you use digitalRead instead of digitalReadFast2?
    – Gerben
    Oct 30, 2014 at 19:44
  • Please do not use pastebin on SE, it is not recommended, in case the link dies (there is a post about this on Meta somewhere). It is far better, and easier for us, if you just post the code directly into your question/answer. Feb 18, 2016 at 12:35

3 Answers 3

2

When turning one way, A is asserted, then B is asserted, then A is deasserted then B is deasserted. You can detect this because A is asserted first, even if you can't tell when B has changed. But if you turn the opposite way then you fail to detect the initial assertion of B, and the code fails.

What you may be able to do is use PinChangeInt to capture the pin change interrupt rather than an external interrupt. This should allow you to use almost any I/O pins on the Uno for the encoder.

3
  • Hi Igancio. Could you clarify - what is it exactly that causes the detection failure on pins other than pin 3? I was assuming that it being an interrupt pin didn't make any difference since we're not actually setting an interrupt on this pin?
    – pat333
    Oct 30, 2014 at 17:31
  • The code needs the interrupt in order to work. No interrupt, no work. Oct 30, 2014 at 17:33
  • 1
    :( I don't understand. The interrupt is working on pin 2. I'm reading from pin 3 after the interrupt, not setting an interrupt on it directly. In the original code, the author is using pins 19 (A) and 25 (B) on an arduino mega. Pin 25 on the Mega is not an interrupt pin either
    – pat333
    Oct 30, 2014 at 18:19
0

My first thought is that something else is off because there is no reason that shouldn't work. It will of course only count 1/4 of the ticks since that's how it was designed to work for very fast motors. I can't comment yet but to Gerben above, I think it is meant to be bidirectional as indicated by the ternary operator. My guess is the problem is with the digitalReadFast library and I would be interested to know if this works when using digitalRead() instead.

My second thought is that this is usually not the best way to do things. Firstly, you would need a really fast motor for the read fast function to matter. Secondly, you're sacrificing resolution by only using one interrupt instead of two. The more generally accepted method is to attach both pins of the encoder to an interrupt. Alternatively, you could use pin change interrupts which allow any pin to be used as an interrupt. However, there are only 3 interrupt service routines on the Uno, one for each port of pins. Whenever one pin on that port triggers, the ISR triggers and you need to keep track of the pin states in order to do anything with it. Here's a good example of the first and info on the second method.

0

OK embarrassingly it turns out my wiring was wrong! I was going astray as it was working in both directions as described, even when only one of the outputs was connected, as long output B was connected to an interrupt. Once the wiring was sorted everything worked perfectly, in both directions, using just one of the interrupt ports.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.