Encoder help needed for newbie

Status
Not open for further replies.

rfresh737

Well-known member
I'm learning how to use an encoder.

I am using the code below from a Teensy tutorial I found.

However, when I run it, nothing displays in the serial window.

I'm using the Ardunio IDE with the Teensy option installed. I can run a simple serial Hello World sketch so that seems to work ok. And I can run the fast blink sketch and the LED on my Teensy 3.2 board blinks accordingly.

So for my encoder code below, something must be wrong or I have the wrong setup on my breadboard.

Thanks for any help.


Code:
/* Encoder Library - TwoKnobs Example
 * http://www.pjrc.com/teensy/td_libs_Encoder.html
 *
 * This example code is in the public domain.
 */

#include <Encoder.h>

// Change these pin numbers to the pins connected to your encoder.
//   Best Performance: both pins have interrupt capability
//   Good Performance: only the first pin has interrupt capability
//   Low Performance:  neither pin has interrupt capability
Encoder knobRight(5, 6);
//   avoid using pins with LEDs attached

void setup() {
  Serial.begin(9600);
  Serial.println("Knob Encoder Test:");
}

long positionRight = -999;

void loop() {
  long newRight;
  newRight = knobRight.read();
  if (newRight != positionRight)
  {
    Serial.print(", Right = ");
    Serial.print(newRight);
    Serial.println();
    positionRight = newRight;
  }
  // if a character is sent from the serial monitor,
  // reset knob back to zero.
  if (Serial.available())
  {
    Serial.read();
    Serial.println("Reset knob to zero");
    knobRight.write(0);
  }
}
 
Maybe one thing that is confusing me is how the pins are referenced. I have the pin assignment card that came with my Teensy 3.2. But as I look at encoder sketches on the internet, I see lines like this:

Code:
Encoder rotary = Encoder(15, 16);	// Rotary Encoder on pin 5 and 6

So I see those 4 pins on my pin assignment card but why does the code say Encoder(15, 16) and the note says pin 5 and 6?

And which Teensy board pins do I actually connect the encoder A and B pins to? 15,16 or 5,6?
 
So I see those 4 pins on my pin assignment card but why does the code say Encoder(15, 16) and the note says pin 5 and 6?

Well note that the reference to pins 5 & 6 is part of a comment and as such can be anything. Usually when the comment doesn't match the code (or doesn't appear to) it's because the user forgot to change it (or perhaps they are listing physical vs. "Arduino" pins or something?)

And which Teensy board pins do I actually connect the encoder A and B pins to? 15,16 or 5,6?

Since you're using a Teensy 3.2 is shouldn't matter (it's recommended to use pins that support interrupts and the 3.2 supports interrupts on all pins). Just make sure you use the same pin numbers in the code that you've wired the encoder to.

In fact I just ported some Encoder menu code I wrote for the Teensy++ 2.0 and I just picked two free digital pins on the 3.2 and it worked just fine (for my tests I'm using pins 24 and 25).

Double-check that you're using the correct pins and if it still doesn't work perhaps post a few close-up pictures of your wiring?

Regards,

Brad.
 
But as I look at encoder sketches on the internet, I see lines like this:

Where exactly "on the internet"? Please give a link.

Code:
Encoder rotary = Encoder(15, 16);	// Rotary Encoder on pin 5 and 6

So I see those 4 pins on my pin assignment card but why does the code say Encoder(15, 16) and the note says pin 5 and 6?

Somebody probably edited the pin numbers, but neglected to update the comment. Sloppy, but common.

Specific details in comments rarely get updated as source code is changed. That's one of the main reasons I tend to write code which descriptive naming and relatively few comments, where the comments only have general concepts. But many people do put a lot of comments in their code, with redundant details, which tend to become out of sync when they or others change the code.
 
Regarding your problem of seeing nothing in the serial monitor, I'd suggest first going back to that LED blink example. Add a simple Serial.print("something") within the loop. Then make sure you can see it print to the serial monitor window every time the LED blinks.

If you've got the wrong port selected, or a windows driver issue, you'll need to resolve that with known-good code. Make sure you have the serial monitor working properly with something simple before you try to depend upon using it with something unknown.
 
Thank you both for the comments. So the pin assignments then are just what they are...follow the pin mapping...got it.

I replaced my encoder with another one and the sketch worked!
 
Regarding your problem of seeing nothing in the serial monitor, I'd suggest first going back to that LED blink example. Add a simple Serial.print("something") within the loop. Then make sure you can see it print to the serial monitor window every time the LED blinks.

If you've got the wrong port selected, or a windows driver issue, you'll need to resolve that with known-good code. Make sure you have the serial monitor working properly with something simple before you try to depend upon using it with something unknown.

Yes, I got the blink program to work and the Hello World serial.print() to work.

Thank you...
 
So, I got one encoder working. I need two so I added another encoder.

The code below doesn't work with both encoders in the code.
In the Loop if I remm out one of the encoder blocks then the other encoder works ok.
But if I leave both encoders in the Loop then neither one works.
I must be stepping on my toes but I can't see where.
One encoder is mapped to pins 2,3 and the other encoder is mapped to pins 4,5
This is a Teensy 3.2 board.
Thanks for any help.

Code:
/* Rotary encoder handler for arduino.
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * Quick implementation of rotary encoder routine.
 *
 * More info: http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
 *
 */

#define ROTARY_FMS_Outer_PIN2 2
#define ROTARY_FMS_Outer_PIN3 3
#define ROTARY_FMS_Inner_PIN4 4
#define ROTARY_FMS_Inner_PIN5 5
#define DIR_CCW 0x10
#define DIR_CW 0x20

unsigned char result1 = 0;
unsigned char result2 = 0;
    
const unsigned char ttable[7][4] = {
{0x0, 0x2, 0x4, 0x0}, {0x3, 0x0, 0x1, 0x10},
{0x3, 0x2, 0x0, 0x0}, {0x3, 0x2, 0x1, 0x0},
{0x6, 0x0, 0x4, 0x0}, {0x6, 0x5, 0x0, 0x20},
{0x6, 0x5, 0x4, 0x0},
};

volatile unsigned char state = 0;

/* Call this once in setup(). */
void rotary_init() {
  pinMode(ROTARY_FMS_Outer_PIN2, INPUT);
  pinMode(ROTARY_FMS_Outer_PIN3, INPUT);
  digitalWrite(ROTARY_FMS_Outer_PIN2, HIGH);
  digitalWrite(ROTARY_FMS_Outer_PIN3, HIGH);

  pinMode(ROTARY_FMS_Inner_PIN4, INPUT);
  pinMode(ROTARY_FMS_Inner_PIN5, INPUT);
  digitalWrite(ROTARY_FMS_Inner_PIN4, HIGH);
  digitalWrite(ROTARY_FMS_Inner_PIN5, HIGH);
}

/* Read input pins and process for events. Call this either from a
 * loop or an interrupt (eg pin change or timer).
 *
 * Returns 0 on no event, otherwise 0x80 or 0x40 depending on the direction.
 */
unsigned char rotary_process_FMS_Outer() {
  unsigned char pinstate = (digitalRead(ROTARY_FMS_Outer_PIN3) << 1) | digitalRead(ROTARY_FMS_Outer_PIN2);
  state = ttable[state & 0xf][pinstate];
  return (state & 0x30);
}
unsigned char rotary_process_FMS_Inner() {
  unsigned char pinstate = (digitalRead(ROTARY_FMS_Inner_PIN5) << 1) | digitalRead(ROTARY_FMS_Inner_PIN4);
  state = ttable[state & 0xf][pinstate];
  return (state & 0x30);
}

void setup() {
  Serial.begin(9600);
  rotary_init();
}

void loop() {
  // if I remm out this block of code then the block below works fine
  result1 = rotary_process_FMS_Outer();
  if (result1 == 16)
  {
    Serial.println("FMS Outer Left");      
  }
  if (result1 == 32)
  {
    Serial.println("FMS Outer Right");
  }
  
// if I remm out this block of code then the above block works fine
  result2 = rotary_process_FMS_Inner();
  if (result2 == 16)
  {
    Serial.println("FMS Inner Left");
  }
  if (result2 == 32)
  {
    Serial.println("FMS Inner Right");
  }
  
}
 
I fear that there is the "state" variable conflicting between calls for both encoders. I'd use two of these, one for each encoder as follows.
Can't test it for the moment, because I have no teensy at my day job in the office, but that should work.
Code:
/* Rotary encoder handler for arduino.
 *
 * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
 * Contact: bb@cactii.net
 *
 * Quick implementation of rotary encoder routine.
 *
 * More info: http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
 *
 */

#define ROTARY_FMS_Outer_PIN2 2
#define ROTARY_FMS_Outer_PIN3 3
#define ROTARY_FMS_Inner_PIN4 4
#define ROTARY_FMS_Inner_PIN5 5
#define DIR_CCW 0x10
#define DIR_CW 0x20

unsigned char result1 = 0;
unsigned char result2 = 0;
    
const unsigned char ttable[7][4] = {
{0x0, 0x2, 0x4, 0x0}, {0x3, 0x0, 0x1, 0x10},
{0x3, 0x2, 0x0, 0x0}, {0x3, 0x2, 0x1, 0x0},
{0x6, 0x0, 0x4, 0x0}, {0x6, 0x5, 0x0, 0x20},
{0x6, 0x5, 0x4, 0x0},
};

volatile unsigned char stateInner = 0;
volatile unsigned char stateOuter = 0;

/* Call this once in setup(). */
void rotary_init() {
  pinMode(ROTARY_FMS_Outer_PIN2, INPUT);
  pinMode(ROTARY_FMS_Outer_PIN3, INPUT);
  digitalWrite(ROTARY_FMS_Outer_PIN2, HIGH);
  digitalWrite(ROTARY_FMS_Outer_PIN3, HIGH);

  pinMode(ROTARY_FMS_Inner_PIN4, INPUT);
  pinMode(ROTARY_FMS_Inner_PIN5, INPUT);
  digitalWrite(ROTARY_FMS_Inner_PIN4, HIGH);
  digitalWrite(ROTARY_FMS_Inner_PIN5, HIGH);
}

/* Read input pins and process for events. Call this either from a
 * loop or an interrupt (eg pin change or timer).
 *
 * Returns 0 on no event, otherwise 0x80 or 0x40 depending on the direction.
 */
unsigned char rotary_process_FMS_Outer() {
  unsigned char pinstate = (digitalRead(ROTARY_FMS_Outer_PIN3) << 1) | digitalRead(ROTARY_FMS_Outer_PIN2);
  stateOuter = ttable[stateOuter & 0xf][pinstate];
  return (state & 0x30);
}
unsigned char rotary_process_FMS_Inner() {
  unsigned char pinstate = (digitalRead(ROTARY_FMS_Inner_PIN5) << 1) | digitalRead(ROTARY_FMS_Inner_PIN4);
  stateInner = ttable[stateInner & 0xf][pinstate];
  return (state & 0x30);
}

void setup() {
  Serial.begin(9600);
  rotary_init();
}

void loop() {
  // if I remm out this block of code then the block below works fine
  result1 = rotary_process_FMS_Outer();
  if (result1 == 16)
  {
    Serial.println("FMS Outer Left");      
  }
  if (result1 == 32)
  {
    Serial.println("FMS Outer Right");
  }
  
// if I remm out this block of code then the above block works fine
  result2 = rotary_process_FMS_Inner();
  if (result2 == 16)
  {
    Serial.println("FMS Inner Left");
  }
  if (result2 == 32)
  {
    Serial.println("FMS Inner Right");
  }
  
}
 
Yep...that was it...I created two separate variables as you suggested. Thanks much.

What I don't understand is why that worked because I only turn one encoder at a time. It was obviously stepping on itself but I still can't see where or understand how that was happening.
 
When calling the routine for the second encoder, the state variable which had been set by and for the first encoder was overwritten by the second and vice-versa.
 
Status
Not open for further replies.
Back
Top