Using Trinket HID libraries in Arduino NANO

Hello everyone

Im a beginner so im sorry if there is any mistake in the question that i have asked.

I am making a USB Volume controller. I found a tutorial which is based on the Digispark attiny85 (Link: http://dangerousprototypes.com/forum/viewtopic.php?f=56&t=7654&p=62864#p62863 ). Since digispark has limited pins I was thinking of using an Arduino nano, as I require more pins because I thought of adding an extra encoder with other multimedia function. Also, it uses the neopixel 8-bit RGB ring for visual effects (Please watch the video for the visual effect : USB Volume Knob - YouTube ). But I guess the TrinketHidCombo.H library does not work for Arduino. So I was wondering if anybody can help me out with the conversion of code from trinket to Arduino.

Thank You !!

CODE : (Written by Markus Gritsch from Dangerous prototypes. Open the above-mentioned link and find the download link for the code at the bottom of the page)

For quick reference:

#include <TrinketHidCombo.h>

#define TRINKET_PINx PINB
#define PIN_ENCODER_A 0
#define PIN_ENCODER_B 2
#define PIN_ENCODER_SWITCH 5

// pos: 0 … 3 * 255
void wheel( uint16_t pos, uint16_t & r, uint16_t & g, uint16_t & b )
{
pos = 3 * 255 - pos;
if ( pos < 255 ) {
r = 255 - pos;
g = 0;
b = pos;
} else if ( pos < 2 * 255 ) {
pos -= 255;
r = 0;
g = pos;
b = 255 - pos;
} else {
pos -= 2 * 255;
r = pos;
g = 255 - pos;
b = 0;
}
}

void boost_and_limit( uint16_t offset, uint16_t & r, uint16_t & g, uint16_t & b )
{
r += offset;
g += offset;
b += offset;
if ( r > 255 ) { r = 255; }
if ( g > 255 ) { g = 255; }
if ( b > 255 ) { b = 255; }
}

void send_twelve( uint8_t r, uint8_t g, uint8_t b )
{
cli();
for ( uint8_t i = 0; i < 12; ++i ) {
sendPixel( r, g, b );
}
sei();
}

void setup()
{
ledsetup();
send_twelve( 0, 0, 0 );

// Set pins as input with internal pull-up resistors enabled.
pinMode( PIN_ENCODER_A, INPUT ); // The Digispark Arduino environment does not know
pinMode( PIN_ENCODER_B, INPUT ); // about INPUT_PULLUP, so we use the old method:
digitalWrite( PIN_ENCODER_A, HIGH );
digitalWrite( PIN_ENCODER_B, HIGH );

pinMode( PIN_ENCODER_SWITCH, INPUT );
digitalWrite( PIN_ENCODER_SWITCH, HIGH );

delay( 1000 ); // This helps to get the device enumerated after computer wake up.
TrinketHidCombo.begin(); // Start the USB device engine and enumerate.
while ( ! TrinketHidCombo.isConnected() ) {
TrinketHidCombo.poll();
}
}

void loop()
{
// One loop takes about 8.6 us.
// bitSet(PORTB, 1);
// bitClear(PORTB, 1);

static uint16_t offset = 0;
static uint16_t ticks = 0;
if ( ticks > 490 ) { // about 200 Hz (400 Hz disables the interrupt to often for V-USB)
ticks = 0;
static uint8_t divider = 0;

static uint16_t pos = 2 * 255; // Start with blue.
uint16_t r, g, b;
wheel( pos, r, g, b );
if ( ( divider & 0x0F ) == 15 ) { // Only advance the color every 16th iteration. → 12.5 Hz
++pos; // One full color cycle takes 255 * 3 / ( 200 / 16 ) = 61.2 s
if ( pos > 3 * 255 ) {
pos = 0;
}
}

// Since we drive the LEDs only at 1/4 of the maximum brightness, and we use 8 bit color values,
// we can use the lowest two color bits to dither the color values. → 50 Hz dither frequency.
if ( ( r & 0x0003 ) > ( divider & 0x0003 ) ) { r += 4; }
if ( ( g & 0x0003 ) > ( divider & 0x0003 ) ) { g += 4; }
if ( ( b & 0x0003 ) > ( divider & 0x0003 ) ) { b += 4; }
r >>= 2; g >>= 2; b >>= 2;

++divider; // Overflows from 255 to 0.

boost_and_limit( offset >> 4, r, g, b );
offset = ( offset >> 1 ) + ( offset >> 2 ) + ( offset >> 3 ) + ( offset >> 4 ) +
( offset >> 5 ) + ( offset >> 6 ); // 204 iterations

// It took about 26 us to get here.
send_twelve( r, g, b ); // Sending takes about 750 us.
}
++ticks;

// Poll the rotary encoder.
static uint8_t enc_prev_pos = 3;
uint8_t enc_cur_pos = 3;
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 );
}

// https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
if ( enc_cur_pos != enc_prev_pos ) {
static uint8_t old_AB = 3;
static int8_t encval = 0;
static const int8_t enc_states[ 16 ] = { 0,-1, 1, 0, 1, 0, 0,-1, -1, 0, 0, 1, 0, 1,-1, 0 };
uint8_t AB = enc_cur_pos;
old_AB <<= 2; // Remember previous state.
old_AB |= AB;
encval += enc_states[ old_AB & 0x0f ];
if ( encval > 2 ) {
offset = 1 << 12;
TrinketHidCombo.pressMultimediaKey( MMKEY_VOL_UP );
encval = 0;
} else if ( encval < -2 ) {
offset = 1 << 12;
TrinketHidCombo.pressMultimediaKey( MMKEY_VOL_DOWN );
encval = 0;
} else if ( AB == 3 ) {
encval = 0; // Bring the encval in sync with the detents in case of lost transitions.
}
enc_prev_pos = enc_cur_pos;
delay( 2 ); // debounce
}

// The switch is active low.
static bool sw_was_pressed = false;
if ( bit_is_clear( TRINKET_PINx, PIN_ENCODER_SWITCH ) ) {
if ( ! sw_was_pressed ) {
sw_was_pressed = true;
offset = 1 << 12;
TrinketHidCombo.pressMultimediaKey( MMKEY_MUTE );
delay( 20 ); // debounce
}
} else {
if ( sw_was_pressed ) {
sw_was_pressed = false;
delay( 20 ); // debounce
}
}

TrinketHidCombo.poll(); // Check if USB needs anything done, do every 10 ms or so.
}

VolumeKnob.ino (4.31 KB)