<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">https://www.pjrc.com/teensy/td_libs_Encoder.html</a><br><br></div>The updated (and working) code is below:<br><br><div><div>/*<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 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, CHANGE);<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>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">https://www.pjrc.com/teensy/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);<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">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">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>