Wednesday 6 August 2014

Rotary Encoder

I've been experimenting with the RGB Illuminated Rotary Encoder that I hope to use. It took me a while to figure out the pins, they aren't in the datasheet but in a subsidiary dimensional drawing which shows it as it would appear on a PCB. I did this little diagram to help me solder it up:


I still managed to get the wrong color wire so it took me a while to figure out why the colors were wrong. Luckily that's easily fixed in software with pin assignments. 

Since I last used a Rotary Encoder with Arduino there's been some development and a couple of new libraries.  I've been using the Encoder library. This works best with external interrupt pins so I used 2 and 3 on the Mega. It seems pretty rock solid, in the past I've always had problems missing events - especially with code that polls. With these encoders I can usually generate reliable increments and decrements by a single count for each detent position and they seem to work for slow or rapid twisting. They actually feel pretty nice with a slight click as they rotate.

The illumination part I just did via standard PWM pins on the Mega (4,5,6) and 7 for the switch. The switch is "normally low" and so benefits from a pull-down resistor between pin 7 and ground. In my code I subclassed the Encoder object to make my own class that also knows about the switch and the RGB LED. Here's the definition of the class:

// This class subclasses the Encoder library described here:
// http://www.pjrc.com/teensy/td_libs_Encoder.html
// As such the pins the encoder pins should be attached to hardware interrupts.
// Additions to this class are support for the RGB led and the push button.
// The LED pins should support PWM
// The Button Pin needs a pull-down resistor on it and is normally low.
class RGBEncoder : 
public Encoder {

public:

  RGBEncoder( int enc_pin_1, int enc_pin_2, int red_pin, int blue_pin, int green_pin, int button_pin );

  void begin(); // Start the rotary encoder operating

  void setColor( int red, int green, int blue );
  // Set the color based on the RGB values. 
  // Each one is in the range 0-255;

  void update ( );  // Read the current encoder value, looking for changes

  int getValue( );   // Get the current encoder value

  boolean buttonPressed(); // Returns true if the button has been pressed.


private:

  int m_red_pin;
  int m_green_pin;
  int m_blue_pin;
  int m_button_pin;
  boolean m_button_pressed;
  long int m_button_down_time;
  long int m_button_check_time;

};



The full code is available on github. Currently the push-button detection is pretty simplistic. It uses a short delay period to debounce and simply keeps a flag for when the button has been pressed for more than 10ms. There's a lot more sophisticated treatment of buttons in another rotary encoder library that I'm very tempted to ..... ummm... "borrow".  It would be useful to be able to detect double clicks and to know when the button is being held down while turning. My main human interface will be only two encoders and a small screen so I'll need as much flexibility as I can get.

Ultimately it's not likely I'll want to use the six PWM pins just to drive the RGB LEDs in the two encoders I'll be using. The PWM pins rely on the timers and it's likely I will find better use for them as oscillators or modulators.  Instead I will investigate the use of an LED PWM driver such as the PCA9685 as featured in this Adafruit board. It's I2C driven so can be used with just two pins instead of six. The driver has 16 channels so maybe I'll add a couple of extra RGB LEDs simply for gratuitous effect.

Currently I don't have a lot of useful things I can do with the encoder other than admire the colors and verify it works. I did hook it up to traverse the MIDI notes and to change color - red for higher notes and blue for lower ones. Here's a video:











No comments:

Post a Comment