[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