<div dir="ltr"><div>I found the following snippet from this article: <br><a href="http://www.robotoid.com/appnotes/circuits-quad-encoding.html">http://www.robotoid.com/appnotes/circuits-quad-encoding.html</a><br><h2>Reading the Encoder with an Arduino<br></h2>
<p>Let's assume you've built a quad encoder using the LS7184 IC, and 
connected it to an Arduino microcontroller development board, as shown 
in the schematic above. The clock output of the LS7184 provides a pulse 
for each complete step of the encoder wheel. If the wheel has 32 
stripes, for example, you'll get 32 pulses per revolution.</p>

<div class="gmail-sidebar">
  <p> <strong>RoboTip!</strong><br>
  Check out the Mode pin on the LS7184. This sets whether the clock is 
multiplied by 1, 2, or 4. I'm showing it set at 1X, which provides one 
clock pulse per encoder step (if 1 revolution = 32 stripes, then 1 
revolution = 32 pulses). When pin 6 of the LS7184 is brought HIGH, the 
output is multiplied by 2, so you get 64 pulses per revolution. And when
 the pin is left floating the multiplication factor is 4X. </p>
<p>You can use the Mode setting to increase the resolution of the 
encoder, letting you detect smaller changes in rotation. It's useful 
when using encoder discs with relatively few stripe transitions.</p>
</div>

 <p>This sketch for the Arduino reads the clock changes on pin D2, which
 provides for an external interrupt. Each time a clock pulse is detected
 on this pin, the Arduino immediately branches off to an interrupt 
routine -- called <em>encoderIntA</em> in the sketch -- to process the pulse. </p>
 <p>Code within the interrupt routine examines the instantaneous state 
of the direction output of the LS7184, which is connected to Arduino pin
 D4. If the direction is HIGH, the encoder is assumed to be going 
forward, so the count goes up by one. If the direction is LOW, the 
encoder is assumed to be going in reverse, so the count goes down by 
one.</p>
 <p>For demonstration purposes the current count value is displayed in the Serial Monitor window. I use an <em>int</em>-size
 variable to hold the count. This variable can store positive and 
negative values in the range -32,768 to +32,767. If the count goes above
 +32,767, it wraps around as a negative value. </p>
 <p>If you suspect this might ever happen in your application use a <em>long</em>-size variable instead. <br>
   These
 store values from -2,147,483,648 to +2,147,483,647. That's a lot of wheel rotations!</p>

 <pre>/* 
  Quadrature encoder example
  Interface to LSI LS7184 quadrature clock converter
  (USDigital part #LFLS7184)
  
  Demonstrates reading quadrature encoder using Arduino interrupts.
  Clock output is connected to pin 2 (Int0); direction output is 
    connected to pin 4.
  Current position is displayed in Serial Monitor window.
*/

const int clkPinA = 2;
const int dirPinA = 4;
volatile int encoderACount = 0;
volatile boolean changeFlag = false;

void setup() {
  Serial.begin(9600);
  pinMode(clkPinA, INPUT);  
  pinMode(dirPinA, INPUT);  
  attachInterrupt(0, encoderIntA, RISING);
}

void loop() {
 if (changeFlag) {
    changeFlag = false;
    Serial.println(encoderACount);
  }
}

void encoderIntA() {
  if (digitalRead(dirPinA) == HIGH)
    encoderACount++;
  else
    encoderACount--;
  changeFlag = true;
}<br></pre><br></div>This article, <a href="http://makeatronics.blogspot.com/2013/02/efficiently-reading-quadrature-with.html">http://makeatronics.blogspot.com/2013/02/efficiently-reading-quadrature-with.html</a>, has the following section in it:<br><br><h3>
<span style="font-size:large">Using Only 1 Interrupt</span></h3>
<div>
<br></div>
<div>
If you're using an arduino Mega, or the new Due, you have more external 
interrupts to work with, so if you want to hook up multiple encoders or 
you have interrupts dedicated to other hardware you're probably covered.
 But if you're working on an Uno or one of it's predecessors, you are 
limited to only 2 interrupts.</div>
<div>
<br></div>
<div>
It is possible to use this same look-up technique with only 1 interrupt 
per encoder. The trade off is that you will loose half of your 
resolution. In this case, you would hook up the other channel to a 
regular digital pin, and then rework your look-up table keeping in mind 
that you can only detect when one of the channels is changing.</div>
<div>
<br>
<div class="gmail-separator" style="clear:both;text-align:center">
</div>
<div class="gmail-separator" style="clear:both;text-align:center">
</div>
<div class="gmail-separator" style="clear:both;text-align:center">
<a href="http://3.bp.blogspot.com/-9WVs1ImbheQ/U9w53Hm10FI/AAAAAAAAOv4/H313k8qFmnw/s1600/quadrature_half_res.png" style="margin-left:1em;margin-right:1em"><img src="http://3.bp.blogspot.com/-9WVs1ImbheQ/U9w53Hm10FI/AAAAAAAAOv4/H313k8qFmnw/s1600/quadrature_half_res.png" border="0" height="196" width="640"></a></div>
<br></div>
<div>
You might think I'm missing some information on the B channel, but 
remember that the microcontroller only sees when A changes, and reads B 
at that time. In the CW direction, when state 2 started A was high and B
 was low. When it gets to state 3, A is low and B is high. We have no 
information about when B changed from low to high, only that it is now 
high. That's why we loose half the resolution when using only one 
interrupt.</div>
<div>
<br></div>
<div>
Working out the entire look-up table:</div>
<div>
<br>
<div class="gmail-separator" style="clear:both;text-align:center">
</div>
</div>
<div class="gmail-separator" style="clear:both;text-align:center">
<a href="http://4.bp.blogspot.com/-9vT8QVtvlug/U9w537vwMsI/AAAAAAAAOwE/fxmM6ao7DyI/s1600/quadrature_table_half_res.png" style="margin-left:1em;margin-right:1em"><img src="http://4.bp.blogspot.com/-9vT8QVtvlug/U9w537vwMsI/AAAAAAAAOwE/fxmM6ao7DyI/s1600/quadrature_table_half_res.png" border="0"></a></div>
<div class="gmail-separator" style="clear:both;text-align:center">
<br></div>
<div class="gmail-separator" style="clear:both;text-align:left">
If you instead connected channel B to the interrupt, this table would be
 different. One way to tell if you've done the table correctly is that 
the direction column should always be symmetric about the middle. That 
is, entry 1 should equal entry 16, entry 2 = entry 15, entry 3 = entry 
14, etc. Meeting this condition doesn't guarantee that you've done it 
right, but if you don't meet this condition I guarantee you've done it 
wrong.</div>
<div class="gmail-separator" style="clear:both;text-align:left">
<br></div>
<div class="gmail-separator" style="clear:both;text-align:left">
You will need to make some changes to the ISR as well. Line 6 in the ISR
 above assumed that the quadrature channels were hooked up the pins 2 
and 3. For convenience in the code, I suggest you keep the two channels 
adjacent to each other whenever possible, i.e. pins 3 and 4 or pins 1 
and 2. But remember the pins 0 and 1 are used for TX and RX.</div>
<div class="gmail-separator" style="clear:both;text-align:left">
<br></div>
<div class="gmail-separator" style="clear:both;text-align:left">
If you connect channel A to the interrupt on pin 3, and channel B to pin 4, the ISR becomes:</div>
<div class="gmail-separator" style="clear:both;text-align:left">
<br></div>
<pre class="gmail-prettyprint gmail-linenums:8 gmail-prettyprinted"><ol class="gmail-linenums"><li value="8" class="gmail-L7"><span class="gmail-kwd">void</span><span class="gmail-pln"> encoder_isr</span><span class="gmail-pun">()</span><span class="gmail-pln"> </span><span class="gmail-pun">{</span></li><li class="gmail-L8"><span class="gmail-pln">    </span><span class="gmail-kwd">static</span><span class="gmail-pln"> </span><span class="gmail-typ">int8_t</span><span class="gmail-pln"> lookup_table</span><span class="gmail-pun">[]</span><span class="gmail-pln"> </span><span class="gmail-pun">=</span><span class="gmail-pln"> </span><span class="gmail-pun">{</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,-</span><span class="gmail-lit">1</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">1</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">1</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,-</span><span class="gmail-lit">1</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">,</span><span class="gmail-lit">0</span><span class="gmail-pun">};</span></li><li class="gmail-L9"><span class="gmail-pln">    </span><span class="gmail-kwd">static</span><span class="gmail-pln"> </span><span class="gmail-typ">uint8_t</span><span class="gmail-pln"> enc_val </span><span class="gmail-pun">=</span><span class="gmail-pln"> </span><span class="gmail-lit">0</span><span class="gmail-pun">;</span></li><li class="gmail-L0"><span class="gmail-pln">    </span></li><li class="gmail-L1"><span class="gmail-pln">    enc_val </span><span class="gmail-pun">=</span><span class="gmail-pln"> enc_val </span><span class="gmail-pun"><<</span><span class="gmail-pln"> </span><span class="gmail-lit">2</span><span class="gmail-pun">;</span></li><li class="gmail-L2"><span class="gmail-pln">    enc_val </span><span class="gmail-pun">=</span><span class="gmail-pln"> enc_val </span><span class="gmail-pun">|</span><span class="gmail-pln"> </span><span class="gmail-pun">((</span><span class="gmail-pln">PIND </span><span class="gmail-pun">&</span><span class="gmail-pln"> </span><span class="gmail-lit">0b11000</span><span class="gmail-pun">)</span><span class="gmail-pln"> </span><span class="gmail-pun">>></span><span class="gmail-pln"> </span><span class="gmail-lit">3</span><span class="gmail-pun">)</span></li><li class="gmail-L3"><span class="gmail-pln"> </span></li><li class="gmail-L4"><span class="gmail-pln">    enc_count </span><span class="gmail-pun">=</span><span class="gmail-pln"> enc_count </span><span class="gmail-pun">+</span><span class="gmail-pln"> lookup_table</span><span class="gmail-pun">[</span><span class="gmail-pln">enc_val </span><span class="gmail-pun">&</span><span class="gmail-pln"> </span><span class="gmail-lit">0b1111</span><span class="gmail-pun">];</span></li><li class="gmail-L5"><span class="gmail-pun">}</span></li></ol></pre><br><div><br>You can also see what was done here in developing this library:<br><br><a href="http://www.mathertel.de/Arduino/RotaryEncoderLibrary.aspx">http://www.mathertel.de/Arduino/RotaryEncoderLibrary.aspx</a><br><br><br></div><div>for reference: <a href="https://www.google.com/search?num=100&newwindow=1&safe=active&q=arduino+quadrature+encoder+code+single+interupt&oq=arduino+quadrature+encoder+code+single+interupt&gs_l=serp.3..0i71k1l8.0.0.0.959.0.0.0.0.0.0.0.0..0.0....0...1c..64.serp..0.0.0.-xq6S5kokU4">https://www.google.com/search?num=100&newwindow=1&safe=active&q=arduino+quadrature+encoder+code+single+interupt&oq=arduino+quadrature+encoder+code+single+interupt&gs_l=serp.3..0i71k1l8.0.0.0.959.0.0.0.0.0.0.0.0..0.0....0...1c..64.serp..0.0.0.-xq6S5kokU4</a><br><br></div><div>- sgh<br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Sep 13, 2016 at 12:33 AM, Rodney Radford via TriEmbed <span dir="ltr"><<a href="mailto:triembed@triembed.org" target="_blank">triembed@triembed.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div>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.<br><br></div>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.<br><br></div>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.<br><br></div>The nice library I found was at: <a href="https://www.pjrc.com/teensy/td_libs_Encoder.html" target="_blank">https://www.pjrc.com/teensy/<wbr>td_libs_Encoder.html</a><br><br></div>The updated (and working) code is below:<br><br><div><div><span class="">/*<br> * Simple quadrature encoder implementation.  I only have one interrupt available (as I<br> *    am using the other for another purpose on this project), so I can only watch one<br> *    of the two encoder pins.  While this reduces the number of transitions per revolution<br> *    that is okay for this purpose.<br> *<br> * When running this, I only see a stream of 0 and 1 values for the encoderValue - what am<br> *    I doing wrong?<br> */<br>#include "Arduino.h"<br><br>int encoderA = 3;   // This one is an interrupt pin<br>int encoderB = 4;   // This is a standard (not interrupt) pin<br><br></span><span class="">volatile long encoderValue = 0;<br><br>void updateEncoder(void);<br><br>/*<br> * Setup the input pins and attach our interrupt vector<br> */<br>void setup() {<br>   Serial.begin(9600);<br>   <br>   // Set both quadrature channels to input and turn on pullup resistors<br>   pinMode(encoderA, INPUT); <br>   pinMode(encoderB, INPUT);<br>   digitalWrite(encoderA, HIGH);<br>   digitalWrite(encoderB, HIGH);<br><br>   // invoke interrupt routine on each falling edge of encoderA<br></span>   attachInterrupt(1, updateEncoder, CHANGE);<span class=""><br>}<br><br><br>/*<br> * Simply print out the encoder value (at a reasonable rate)<br> */<br>void loop() {<br><br>  Serial.println(encoderValue);<br>  delay(100);<br>}<br><br><br></span>int state = 0;<br><br>/**<br> *               _______         _______<br> *   Pin1 ______|       |_______|       |______ Pin1<br> *           _______         _______         __  <br> *   Pin2 __|       |_______|       |_______|   Pin2<br> *<br> *    <-- negative count                    positive count --><br> *<br> *    new     new     old     old<br> *    pin2    pin1    pin2    pin1    Result<br> *    ----    ----    ----    ----    ------<br> *    0       0       0       0       no movement<br> *    0       0       0       1       +1<br> *    0       0       1       0       -1<br> *    0       0       1       1       +2  (assume pin1 edges only)<br> *    0       1       0       0       -1<br> *    0       1       0       1       no movement<br> *    0       1       1       0       -2  (assume pin1 edges only)<br> *    0       1       1       1       +1<br> *    1       0       0       0       +1<br> *    1       0       0       1       -2  (assume pin1 edges only)<br> *    1       0       1       0       no movement<br> *    1       0       1       1       -1<br> *    1       1       0       0       +2  (assume pin1 edges only)<br> *    1       1       0       1       -1<br> *    1       1       1       0       +1<br> *    1       1       1       1       no movement<br> *<br> * Implementation based on Encoder library at:<br> *     <a href="https://www.pjrc.com/teensy/td_libs_Encoder.html" target="_blank">https://www.pjrc.com/teensy/<wbr>td_libs_Encoder.html</a><br> */ <br>void updateEncoder(void) {<br>   uint8_t s = state & 3;<br>   if (digitalRead(encoderA)) s |= 4;<br>   if (digitalRead(encoderB)) s |= 8;<br>   switch (s) {<br>       case 0: case 5: case 10: case 15:<br>          break;<br>       case 1: case 7: case 8: case 14:<br>          encoderValue++; <br>          break;<br>       case 2: case 4: case 11: case 13:<br>          encoderValue--; <br>          break;<br>       case 3: case 12:<br>          encoderValue += 2; <br>          break;<br>       default:<br>          encoderValue -= 2; <br>          break;<br>       }<br>   state = (s >> 2);<div><div class="h5"><br>}<br><br><div><div><div><div><br><div><div class="gmail_quote">---------- Forwarded message ----------<br>From: <b class="gmail_sendername">Rodney Radford</b> <span dir="ltr"><<a href="mailto:ncgadgetry@gmail.com" target="_blank">ncgadgetry@gmail.com</a>></span><br>Date: Mon, Sep 12, 2016 at 11:45 PM<br>Subject: Quadrature encoder help<br>To: TriEmbed Discussion <<a href="mailto:triembed@triembed.org" target="_blank">triembed@triembed.org</a>><br><br><br><div dir="ltr"><div><div><div>I am adding a quadrature encoder to a project I am working on, but having a problem understanding why this is not working.<br><br></div>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.<br><br></div>I know this is possible, but I have a bug in the code below and I can't seem to find it.<br><br></div>What am I missing?<br><br><br>/*<br> * Simple quadrature encoder implementation.  I only have one interrupt available (as I<br> *    am using the other for another purpose on this project), so I can only watch one<br> *    of the two encoder pins.  While this reduces the number of transitions per revolution<br> *    that is okay for this purpose.<br> *<br> * When running this, I only see a stream of 0 and 1 values for the encoderValue - what am<br> *    I doing wrong?<br> */<br>#include "Arduino.h"<br><br>int encoderA = 3;   // This one is an interrupt pin<br>int encoderB = 4;   // This is a standard (not interrupt) pin<br><br>volatile int  lastB = 0;<br>volatile long encoderValue = 0;<br><br>void updateEncoder(void);<br><br>/*<br> * Setup the input pins and attach our interrupt vector<br> */<br>void setup() {<br>   Serial.begin(9600);<br>   <br>   // Set both quadrature channels to input and turn on pullup resistors<br>   pinMode(encoderA, INPUT); <br>   pinMode(encoderB, INPUT);<br>   digitalWrite(encoderA, HIGH);<br>   digitalWrite(encoderB, HIGH);<br><br>   // invoke interrupt routine on each falling edge of encoderA<br>   attachInterrupt(1, updateEncoder, FALLING);<br>}<br><br><br>/*<br> * Simply print out the encoder value (at a reasonable rate)<br> */<br>void loop() {<br><br>  Serial.println(encoderValue);<br>  delay(100);<br>}<br><br><br>/*<br> * This interrupt routine is called on each falling edge of encoder channel A. We<br> *   look at the B edge to to determine if we are counting up, down, or staying in<br> *   the same location.<br> * Note if we only looked at the current B (and not the previous B), we would get<br> *   duplicate up/down counts on every transition due to non-debounced quadrature<br> *   signals.<br> */<br>void updateEncoder(void) {<br>  <br>  // read the current encoderB value<br>  int newB = (digitalRead(encoderB) & 0x1);<br><br>  // create the 'transition' variable - show both old and new states - if 00 or 11<br>  //    this is a duplicate falling edge (not moved), but if 01 or 10, we have moved<br>  int transition = (lastB << 1) | newB;<br>  <br>  // are we counting up, down, or staying the same location?<br>  switch (transition) {<br>      // transitioned from a 0 -> 1 edge, so counting up<br>      case B01: <br>           encoderValue++; <br>           break;<br>      // transitioned from a 1 -> 0 edge, so counting down<br>      case B10: <br>           encoderValue--; <br>           break;<br>  }<br><br>   // Save current encoderB value for next transition variable<br>   lastB = newB;<br>}<br></div>
</div><br></div></div></div></div></div></div></div></div></div></div>
<br>______________________________<wbr>_________________<br>
Triangle, NC Embedded Computing mailing list<br>
<a href="mailto:TriEmbed@triembed.org">TriEmbed@triembed.org</a><br>
<a href="http://mail.triembed.org/mailman/listinfo/triembed_triembed.org" rel="noreferrer" target="_blank">http://mail.triembed.org/<wbr>mailman/listinfo/triembed_<wbr>triembed.org</a><br>
TriEmbed web site: <a href="http://TriEmbed.org" rel="noreferrer" target="_blank">http://TriEmbed.org</a><br>
<br></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Scott G. Hall<br>Raleigh, NC, USA<br><a href="mailto:scottghall1@gmail.com" target="_blank">scottghall1@gmail.com</a></div>
</div>