Required Libraries
We need four libraries for the Rotary Trinkey: one each for the rotary encoder, the NeoPixel, capacitive touch, and HID.
In the Arduino library manager, search for RotaryEncoder and install RotaryEncoder.
Then, search for NeoPixel and install Adafruit NeoPixel (double check the name!)
Next, install Adafruit FreeTouch.
Finally, install HID-Project.
All examples are in the GitHub repository https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Rotary_Trinkey/ with Arduino examples NOT containing "CircuitPython" in the directory name.
// SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries // // SPDX-License-Identifier: MIT #include <Adafruit_NeoPixel.h> #include "Adafruit_FreeTouch.h" #include <RotaryEncoder.h> // Create the neopixel strip with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); int16_t neo_brightness = 20; // initialize with 20 brightness (out of 255) RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::FOUR3); // This interrupt will do our encoder reading/checking! void checkPosition() { encoder.tick(); // just call tick() to check the state. } uint8_t wheel_offset = 99; int last_rotary = 0; void setup() { Serial.begin(115200); //while (!Serial); // start neopixels strip.begin(); strip.setBrightness(neo_brightness); strip.show(); // Initialize all pixels to 'off' attachInterrupt(PIN_ENCODER_A, checkPosition, CHANGE); attachInterrupt(PIN_ENCODER_B, checkPosition, CHANGE); // set up the encoder switch, which is separate from the encoder pinMode(PIN_ENCODER_SWITCH, INPUT_PULLDOWN); } void loop() { // read encoder int curr_rotary = encoder.getPosition(); RotaryEncoder::Direction direction = encoder.getDirection(); if (curr_rotary != last_rotary) { Serial.print("Encoder value: "); Serial.print(curr_rotary); Serial.print(" direction: "); Serial.print((int)direction); // behavior differs if switch is pressed if (!digitalRead(PIN_ENCODER_SWITCH)) { // update color if (direction == RotaryEncoder::Direction::CLOCKWISE) { wheel_offset++; } if (direction == RotaryEncoder::Direction::COUNTERCLOCKWISE) { wheel_offset--; } } else { // update brightness if (direction == RotaryEncoder::Direction::CLOCKWISE) { neo_brightness += 10; } if (direction == RotaryEncoder::Direction::COUNTERCLOCKWISE) { neo_brightness -= 10; } // ranges between 0 and 255 if (neo_brightness > 255) neo_brightness = 255; if (neo_brightness < 0) neo_brightness = 0; } Serial.print(" wheel color: "); Serial.print(wheel_offset); Serial.print(" brightness: "); Serial.println(neo_brightness); last_rotary = curr_rotary; // update pixels! strip.setBrightness(neo_brightness); strip.setPixelColor(0, Wheel(wheel_offset)); strip.show(); } } // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { if(WheelPos < 85) { return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } else if(WheelPos < 170) { WheelPos -= 85; return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else { WheelPos -= 170; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } }
Rotate the rotary encoder to change the color of the NeoPixel. Press and rotate the rotary encoder to change the brightness of the NeoPixel.
Note that you can use the onboard NeoPixel like any strip. We have A full guide on NeoPixels and how to use and code them here.
We pre-define two constants, PIN_NEOPIXEL
and NUM_NEOPIXEL
so you don't have to remember the NeoPixel pin or quantity.
// SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries // // SPDX-License-Identifier: MIT #include <Adafruit_NeoPixel.h> #include <RotaryEncoder.h> #include "HID-Project.h" // https://github.com/NicoHood/HID // Create the neopixel strip with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); int16_t neo_brightness = 20; // initialize with 20 brightness (out of 255) RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::FOUR3); // This interrupt will do our encoder reading/checking! void checkPosition() { encoder.tick(); // just call tick() to check the state. } int last_rotary = 0; bool last_button = false; void setup() { Serial.begin(115200); //while (!Serial); delay(100); Serial.println("Rotary Trinkey Surface Dial"); // start neopixels strip.begin(); strip.setBrightness(neo_brightness); strip.show(); // Initialize all pixels to 'off' attachInterrupt(PIN_ENCODER_A, checkPosition, CHANGE); attachInterrupt(PIN_ENCODER_B, checkPosition, CHANGE); // set up the encoder switch, which is separate from the encoder pinMode(PIN_ENCODER_SWITCH, INPUT_PULLDOWN); // Sends a clean report to the host. This is important on any Arduino type. SurfaceDial.begin(); } void loop() { // read encoder int curr_rotary = encoder.getPosition(); RotaryEncoder::Direction direction = encoder.getDirection(); // read switch bool curr_button = digitalRead(PIN_ENCODER_SWITCH); if (direction != RotaryEncoder::Direction::NOROTATION) { Serial.print("Encoder value: "); Serial.print(curr_rotary); Serial.print(" direction: "); Serial.print((int)direction); if (direction == RotaryEncoder::Direction::CLOCKWISE) { Serial.println(" Rotate+"); SurfaceDial.rotate(40); } if (direction == RotaryEncoder::Direction::COUNTERCLOCKWISE) { Serial.println(" Rotate-"); SurfaceDial.rotate(-40); } last_rotary = curr_rotary; } if (curr_button && !last_button) { // switch pressed! Serial.println("Press"); SurfaceDial.press(); } if (!curr_button && last_button) { // switch released! Serial.println("Release"); SurfaceDial.release(); } last_button = curr_button; delay(10); // debounce }
Rotate the rotary encoder to engage the surface dial. Press the button to engage the surface dial options. Rotate to choose the mode.
Volume Play/Pause Example
Perhaps you'd like to simply use the rotary encoder as a volume knob and the button as a play/pause button. Compile and upload the following example.
// SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries // // SPDX-License-Identifier: MIT #include <Adafruit_NeoPixel.h> #include <RotaryEncoder.h> #include "HID-Project.h" // https://github.com/NicoHood/HID // Create the neopixel strip with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); int16_t neo_brightness = 20; // initialize with 20 brightness (out of 255) RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::FOUR3); // This interrupt will do our encoder reading/checking! void checkPosition() { encoder.tick(); // just call tick() to check the state. } int last_rotary = 0; bool last_button = false; void setup() { Serial.begin(115200); //while (!Serial); delay(100); Serial.println("Rotary Trinkey Volume Knob"); // start neopixels strip.begin(); strip.setBrightness(neo_brightness); strip.show(); // Initialize all pixels to 'off' attachInterrupt(PIN_ENCODER_A, checkPosition, CHANGE); attachInterrupt(PIN_ENCODER_B, checkPosition, CHANGE); // set up the encoder switch, which is separate from the encoder pinMode(PIN_ENCODER_SWITCH, INPUT_PULLDOWN); // Sends a clean report to the host. This is important on any Arduino type. Consumer.begin(); } void loop() { // read encoder int curr_rotary = encoder.getPosition(); RotaryEncoder::Direction direction = encoder.getDirection(); // read switch bool curr_button = digitalRead(PIN_ENCODER_SWITCH); if (direction != RotaryEncoder::Direction::NOROTATION) { Serial.print("Encoder value: "); Serial.print(curr_rotary); Serial.print(" direction: "); Serial.print((int)direction); if (direction == RotaryEncoder::Direction::CLOCKWISE) { Serial.println(" Vol +"); Consumer.write(MEDIA_VOLUME_UP); } if (direction == RotaryEncoder::Direction::COUNTERCLOCKWISE) { Serial.println(" Vol -"); Consumer.write(MEDIA_VOLUME_DOWN); } last_rotary = curr_rotary; } if (curr_button && !last_button) { // switch pressed! Serial.println("Play/Pause"); Consumer.write(MEDIA_PLAY_PAUSE); } last_button = curr_button; delay(10); // debounce }
Rotate the rotary encoder to increase or decrease your volume. Press the button to play or pause.
Page last edited January 21, 2025
Text editor powered by tinymce.