Rotary Encoder to USB Joystick

Status
Not open for further replies.

JavaLava

New member
Hi all,

I'm working on a button box project using encoders, switches, and buttons. I have a teensy++ 2.0 and have been trying to get my encoders to work as button input, with a clockwise rotation being one button, counter clockwise being another button, and the encoder's click being a third button. I will have four of these encoders, which as near as I can tell are http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/keyes-ky-040-arduino-rotary-encoder-user-manual/ one.

I have got it mostly working with a bit of test code and one encoder. The problem is that it seems somewhat unreliable, and I can't spin the encoder very fast or else it won't register any movement. I'll include the code below, but in essence it simply waits for input from the encoder, and then depending on the rotation it turns on a joystick button for a certain amount of time before turning it off. This is achieved with the delay command. If I make the delay too short, the button input won't be read. But if I make the delay too long then the maximum speed that you can turn the dial at is limited. Is there a better way to approach this? Thanks in advance.

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

// If you define ENCODER_DO_NOT_USE_INTERRUPTS *before* including
// Encoder, the library will never use interrupts.  This is mainly
// useful to reduce the size of the library when you are using it
// with pins that do not support interrupts.  Without interrupts,
// your program must call the read() function rapidly, or risk
// missing changes in position.
#define ENCODER_DO_NOT_USE_INTERRUPTS
#include <Encoder.h>
#include <Bounce.h>

// Beware of Serial.print() speed.  Without interrupts, if you
// transmit too much data with Serial.print() it can slow your
// reading from Encoder.  Arduino 1.0 has improved transmit code.
// Using the fastest baud rate also helps.  Teensy has USB packet
// buffering.  But all boards can experience problems if you print
// too much and fill up buffers.

// Change these two numbers to the pins connected to your encoder.
//   With ENCODER_DO_NOT_USE_INTERRUPTS, no interrupts are ever
//   used, even if the pin has interrupt capability
Encoder myEnc(2, 3);
//   avoid using pins with LEDs attached

Bounce button1 = Bounce(2, 10);
Bounce button2 = Bounce(3, 10);
Bounce button8 = Bounce(8, 10);

void setup() {
  Serial.begin(9600);
  Serial.println("Basic NoInterrupts Test:");

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
}

long oldPosition  = -999;

void loop() {

   button1.update();
   button2.update();
   button8.update();

   if (button8.fallingEdge()) {
    Joystick.button(3, 1);
   }

  if (button8.risingEdge()) {
    Joystick.button(3, 0);
  }
    
  long newPosition = myEnc.read()/4;
  if (newPosition != oldPosition) {
    if (newPosition > oldPosition) {
      Joystick.button(1,1);       //turn on button 1 on the joystick
      delay(12);
      Joystick.button(1,0);       //turn off button 1 on the joystick
    }
    else if (newPosition < oldPosition) {
      Joystick.button(2,1);       //turn on button 1 on the joystick
      delay(12);
      Joystick.button(2,0);       //turn off button 1 on the joystick
    }
       
    oldPosition = newPosition;
    Serial.println(newPosition);
  }
}
 
First, the Teensy 2.0++ is (compared to actual hardware) old and slow. Second, you use the slowest variant of encoder processing by defining the non-use of interrupts. Third, your loop() code is clumsy since it uses delay(12) which will make the Teensy blind for encoder events during 12ms which is longer than the run time for the loop code.
Solution: use interrupts for the encoder processing, one per encoder pin which requires 8 interrupts for 4 encoders. And get rid of the delay() code. There are more intelligent ways like elapsedMillis to handle that
 
Hello Theremingenieur, thanks very much for your reply. I'm a novice programmer. Do you have any examples of code demonstrating how to read encoders using interrupts? I have been doing a lot of research and every example I've found has been very complicated and hard for me to follow.

Thanks for the tip on the ellapsedMillis. It's a much more elegant way of doing it than delays.
 
On the Teensy 2.0++, the following pins must be used for the 4 encoder A and B pins: 0, 1, 2, 3, 18, 19, 36, 37.

Then, in your code, comment the following line out:
Code:
#define ENCODER_DO_NOT_USE_INTERRUPTS
, so that interrupts will definitively be used.
 
Thank you so much both of you for replying. I will be able to try your suggestions in a couple hours. I'd like to know more about interrupts, and why all of the example code for the Teensy have them disabled. Is there a good reason not to use them sometimes? If you have any suggestions for reading I'd really appreciate a link.

It's strange, when using the above code, I can watch the serial monitor and spin the encoder quite fast and it won't miss a beat, but when I program it into a game there's almost like a speed limit. I'm not sure my problems are necessarily with the encoder, but with how fast the game can read the joystick button input. I'd appreciate any thoughts on this.
 
Status
Not open for further replies.
Back
Top