A much-requested interface for computers is alternative access to keyboard special function keys.
This project uses the HID library with a rotary encoder switch as a digital volume control for PC sound. The push button connected to the encoder shaft is used as a mute/unmute button.
The wiring is shown below. One side of the switch has two pins, that is the push switch. The side with three contacts is the rotary part of the switch. Circuit power comes from the USB connection.
The code for the volume project is below. Ensure you have installed the HID library. The trickiest part is the poll function must be called every 10 milliseconds so all the other processing needs to be done quickly.
The code for reading the encoder is a bit involved. The switch transitions need to be determined so the direction the switch is being turned can be found. To read things quickly, the sketch uses microcontroller port polling which is much quicker than digitalRead function calls. Direct port access techniques are discussed on arduino.cc.
/**************************************************************************/ /*! @file ProTrinketVolumeKnobPlus.ino @author Mike Barela for Adafruit Industries @license MIT This is an example of using the Adafruit Pro Trinket with a rotary encoder as a USB HID Device. Turning the knob controls the sound on a multimedia computer, pressing the knob mutes/unmutes the sound Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! @section HISTORY v1.0 - First release 1/26/2015 Mike Barela based on code by Frank Zhou */ /**************************************************************************/ #include <ProTrinketHidCombo.h> #define PIN_ENCODER_A 3 #define PIN_ENCODER_B 5 #define TRINKET_PINx PIND #define PIN_ENCODER_SWITCH 4 static uint8_t enc_prev_pos = 0; static uint8_t enc_flags = 0; static char sw_was_pressed = 0; void setup() { // set pins as input with internal pull-up resistors enabled pinMode(PIN_ENCODER_A, INPUT_PULLUP); pinMode(PIN_ENCODER_B, INPUT_PULLUP); pinMode(PIN_ENCODER_SWITCH, INPUT_PULLUP); TrinketHidCombo.begin(); // start the USB device engine and enumerate // get an initial reading on the encoder pins if (digitalRead(PIN_ENCODER_A) == LOW) { enc_prev_pos |= (1 << 0); } if (digitalRead(PIN_ENCODER_B) == LOW) { enc_prev_pos |= (1 << 1); } } void loop() { int8_t enc_action = 0; // 1 or -1 if moved, sign is direction // note: for better performance, the code will use // direct port access techniques // http://www.arduino.cc/en/Reference/PortManipulation uint8_t enc_cur_pos = 0; // read in the encoder state first if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_A)) { enc_cur_pos |= (1 << 0); } if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_B)) { enc_cur_pos |= (1 << 1); } // if any rotation at all if (enc_cur_pos != enc_prev_pos) { if (enc_prev_pos == 0x00) { // this is the first edge if (enc_cur_pos == 0x01) { enc_flags |= (1 << 0); } else if (enc_cur_pos == 0x02) { enc_flags |= (1 << 1); } } if (enc_cur_pos == 0x03) { // this is when the encoder is in the middle of a "step" enc_flags |= (1 << 4); } else if (enc_cur_pos == 0x00) { // this is the final edge if (enc_prev_pos == 0x02) { enc_flags |= (1 << 2); } else if (enc_prev_pos == 0x01) { enc_flags |= (1 << 3); } // check the first and last edge // or maybe one edge is missing, if missing then require the middle state // this will reject bounces and false movements if (bit_is_set(enc_flags, 0) && (bit_is_set(enc_flags, 2) || bit_is_set(enc_flags, 4))) { enc_action = 1; } else if (bit_is_set(enc_flags, 2) && (bit_is_set(enc_flags, 0) || bit_is_set(enc_flags, 4))) { enc_action = 1; } else if (bit_is_set(enc_flags, 1) && (bit_is_set(enc_flags, 3) || bit_is_set(enc_flags, 4))) { enc_action = -1; } else if (bit_is_set(enc_flags, 3) && (bit_is_set(enc_flags, 1) || bit_is_set(enc_flags, 4))) { enc_action = -1; } enc_flags = 0; // reset for next time } } enc_prev_pos = enc_cur_pos; if (enc_action > 0) { TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP); // Clockwise, send multimedia volume up } else if (enc_action < 0) { TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN); // Counterclockwise, is multimedia volume down } // remember that the switch is active low if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_SWITCH)) { if (sw_was_pressed == 0) // only on initial press, so the keystroke is not repeated while the button is held down { TrinketHidCombo.pressMultimediaKey(MMKEY_MUTE); // Encoder pushed down, toggle mute or not delay(5); // debounce delay } sw_was_pressed = 1; } else { if (sw_was_pressed != 0) { delay(5); // debounce delay } sw_was_pressed = 0; } TrinketHidCombo.poll(); // check if USB needs anything done, do every 10 ms or so }
Use
Plug the USB cable into the Pro Trinket. You should hear a sound (if using Windows) and note that Windows Update loads the USB device driver.
Start playing music on the computer. As you turn the knob, the volume should go up one way, down the other. Push down on the switch and the sound should be muted, another push, unmute.
Text editor powered by tinymce.