[TriEmbed] Fwd: Quadrature encoder help

Rodney Radford ncgadgetry at gmail.com
Mon Sep 12 23:33:26 CDT 2016


The 'best' way to solve any programming problem is to first look at it, hit
your head on the wall, post it for others to help, go to bed... and then
immediately realize the error and have to get up to correct it.

Although I looked at this for over an hour before posting it, it was not
until I was trying to sleep that I realized why I was always seeing 0 or 1
- each transition would just bump it up, and then back down. In order to
count up or down, I was going to need to look at more than just two bits of
state.

I started to code this, and did another google search - you know, the same
thing I did before I asked and came up empty?  Yeah, that thing... and this
time I found a great resource. While I did not need everything in the
library, I was able to pull out just the interrupt routine and that solved
my problem.

The nice library I found was at:
https://www.pjrc.com/teensy/td_libs_Encoder.html

The updated (and working) code is below:

/*
 * Simple quadrature encoder implementation.  I only have one interrupt
available (as I
 *    am using the other for another purpose on this project), so I can
only watch one
 *    of the two encoder pins.  While this reduces the number of
transitions per revolution
 *    that is okay for this purpose.
 *
 * When running this, I only see a stream of 0 and 1 values for the
encoderValue - what am
 *    I doing wrong?
 */
#include "Arduino.h"

int encoderA = 3;   // This one is an interrupt pin
int encoderB = 4;   // This is a standard (not interrupt) pin

volatile long encoderValue = 0;

void updateEncoder(void);

/*
 * Setup the input pins and attach our interrupt vector
 */
void setup() {
   Serial.begin(9600);

   // Set both quadrature channels to input and turn on pullup resistors
   pinMode(encoderA, INPUT);
   pinMode(encoderB, INPUT);
   digitalWrite(encoderA, HIGH);
   digitalWrite(encoderB, HIGH);

   // invoke interrupt routine on each falling edge of encoderA
   attachInterrupt(1, updateEncoder, CHANGE);
}


/*
 * Simply print out the encoder value (at a reasonable rate)
 */
void loop() {

  Serial.println(encoderValue);
  delay(100);
}


int state = 0;

/**
 *               _______         _______
 *   Pin1 ______|       |_______|       |______ Pin1
 *           _______         _______         __
 *   Pin2 __|       |_______|       |_______|   Pin2
 *
 *    <-- negative count                    positive count -->
 *
 *    new     new     old     old
 *    pin2    pin1    pin2    pin1    Result
 *    ----    ----    ----    ----    ------
 *    0       0       0       0       no movement
 *    0       0       0       1       +1
 *    0       0       1       0       -1
 *    0       0       1       1       +2  (assume pin1 edges only)
 *    0       1       0       0       -1
 *    0       1       0       1       no movement
 *    0       1       1       0       -2  (assume pin1 edges only)
 *    0       1       1       1       +1
 *    1       0       0       0       +1
 *    1       0       0       1       -2  (assume pin1 edges only)
 *    1       0       1       0       no movement
 *    1       0       1       1       -1
 *    1       1       0       0       +2  (assume pin1 edges only)
 *    1       1       0       1       -1
 *    1       1       1       0       +1
 *    1       1       1       1       no movement
 *
 * Implementation based on Encoder library at:
 *     https://www.pjrc.com/teensy/td_libs_Encoder.html
 */
void updateEncoder(void) {
   uint8_t s = state & 3;
   if (digitalRead(encoderA)) s |= 4;
   if (digitalRead(encoderB)) s |= 8;
   switch (s) {
       case 0: case 5: case 10: case 15:
          break;
       case 1: case 7: case 8: case 14:
          encoderValue++;
          break;
       case 2: case 4: case 11: case 13:
          encoderValue--;
          break;
       case 3: case 12:
          encoderValue += 2;
          break;
       default:
          encoderValue -= 2;
          break;
       }
   state = (s >> 2);
}


---------- Forwarded message ----------
From: Rodney Radford <ncgadgetry at gmail.com>
Date: Mon, Sep 12, 2016 at 11:45 PM
Subject: Quadrature encoder help
To: TriEmbed Discussion <triembed at triembed.org>


I am adding a quadrature encoder to a project I am working on, but having a
problem understanding why this is not working.

I have used quadrature encoders before, implementing them with 0, 1, and 2
interrupt lines.  In this case, I only have one interrupt line available so
I am interrupting on one channel and checking the other.

I know this is possible, but I have a bug in the code below and I can't
seem to find it.

What am I missing?


/*
 * Simple quadrature encoder implementation.  I only have one interrupt
available (as I
 *    am using the other for another purpose on this project), so I can
only watch one
 *    of the two encoder pins.  While this reduces the number of
transitions per revolution
 *    that is okay for this purpose.
 *
 * When running this, I only see a stream of 0 and 1 values for the
encoderValue - what am
 *    I doing wrong?
 */
#include "Arduino.h"

int encoderA = 3;   // This one is an interrupt pin
int encoderB = 4;   // This is a standard (not interrupt) pin

volatile int  lastB = 0;
volatile long encoderValue = 0;

void updateEncoder(void);

/*
 * Setup the input pins and attach our interrupt vector
 */
void setup() {
   Serial.begin(9600);

   // Set both quadrature channels to input and turn on pullup resistors
   pinMode(encoderA, INPUT);
   pinMode(encoderB, INPUT);
   digitalWrite(encoderA, HIGH);
   digitalWrite(encoderB, HIGH);

   // invoke interrupt routine on each falling edge of encoderA
   attachInterrupt(1, updateEncoder, FALLING);
}


/*
 * Simply print out the encoder value (at a reasonable rate)
 */
void loop() {

  Serial.println(encoderValue);
  delay(100);
}


/*
 * This interrupt routine is called on each falling edge of encoder channel
A. We
 *   look at the B edge to to determine if we are counting up, down, or
staying in
 *   the same location.
 * Note if we only looked at the current B (and not the previous B), we
would get
 *   duplicate up/down counts on every transition due to non-debounced
quadrature
 *   signals.
 */
void updateEncoder(void) {

  // read the current encoderB value
  int newB = (digitalRead(encoderB) & 0x1);

  // create the 'transition' variable - show both old and new states - if
00 or 11
  //    this is a duplicate falling edge (not moved), but if 01 or 10, we
have moved
  int transition = (lastB << 1) | newB;

  // are we counting up, down, or staying the same location?
  switch (transition) {
      // transitioned from a 0 -> 1 edge, so counting up
      case B01:
           encoderValue++;
           break;
      // transitioned from a 1 -> 0 edge, so counting down
      case B10:
           encoderValue--;
           break;
  }

   // Save current encoderB value for next transition variable
   lastB = newB;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.triembed.org/pipermail/triembed_triembed.org/attachments/20160913/5e2d7696/attachment.htm>


More information about the TriEmbed mailing list