Arnov Sharma
Published © MIT

IOTA STATION- A Mini PC with Giant Rotary Knob

A Mini PC powered by Lattepanda IOTA SBC

BeginnerFull instructions provided10 hours969
IOTA STATION- A Mini PC with Giant Rotary Knob

Things used in this project

Hardware components

DFRobot Lattepanda LOTA
×1
PCBWay Custom PCB
PCBWay Custom PCB
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1
RP2040
Raspberry Pi RP2040
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

lower body

Base

Encoder holder

Legs/Lift part

Main Body

Outer Knob

Rotary Mechanism

Knob Main Body

Code

code

C/C++
#include <Adafruit_TinyUSB.h>

// ================== PINS ==================
#define ENC_A   0
#define ENC_B   1
#define ENC_BTN 2

// ================== HID ===================
Adafruit_USBD_HID hid_consumer;
Adafruit_USBD_HID hid_keyboard;

uint8_t const consumer_desc[] = {
  TUD_HID_REPORT_DESC_CONSUMER()
};

uint8_t const keyboard_desc[] = {
  TUD_HID_REPORT_DESC_KEYBOARD()
};

// ================== MODE ==================
bool volumeMode = true;
bool lastBtn = HIGH;

// ================== ENCODER (DETENT LOCK) ==================
int8_t readEncoder() {
  static uint8_t last = 0b11;
  static int8_t count = 0;

  uint8_t now = 0;
  if (digitalRead(ENC_A)) now |= 1;
  if (digitalRead(ENC_B)) now |= 2;

  if (now != last) {
    if ((last == 0b11 && now == 0b01) ||
        (last == 0b01 && now == 0b00) ||
        (last == 0b00 && now == 0b10) ||
        (last == 0b10 && now == 0b11))
      count++;

    if ((last == 0b11 && now == 0b10) ||
        (last == 0b10 && now == 0b00) ||
        (last == 0b00 && now == 0b01) ||
        (last == 0b01 && now == 0b11))
      count--;

    last = now;
  }

  if (now == 0b11) {
    if (count >= 4) { count = 0; return +1; }
    if (count <= -4) { count = 0; return -1; }
    count = 0;
  }

  return 0;
}

// ================== HID SEND ==================
void sendVolume(uint16_t key) {
  hid_consumer.sendReport(0, &key, sizeof(key));
  delay(2);
  uint16_t zero = 0;
  hid_consumer.sendReport(0, &zero, sizeof(zero));
}

void sendKey(uint8_t keycode) {
  uint8_t press[8] = {0};
  uint8_t release[8] = {0};

  press[2] = keycode;

  hid_keyboard.sendReport(0, press, sizeof(press));
  delay(2);
  hid_keyboard.sendReport(0, release, sizeof(release));
}

// ================== SETUP ==================
void setup() {
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  pinMode(ENC_BTN, INPUT_PULLUP);

  hid_consumer.setReportDescriptor(consumer_desc, sizeof(consumer_desc));
  hid_consumer.begin();

  hid_keyboard.setReportDescriptor(keyboard_desc, sizeof(keyboard_desc));
  hid_keyboard.begin();

  while (!TinyUSBDevice.mounted()) delay(10);
}

// ================== LOOP ==================
void loop() {
  // Button toggle
  bool btn = digitalRead(ENC_BTN);
  if (lastBtn == HIGH && btn == LOW) {
    volumeMode = !volumeMode;
    delay(300);
  }
  lastBtn = btn;

  // Encoder
  int8_t move = readEncoder();
  if (move != 0) {
    if (volumeMode) {
      if (move > 0)
        sendVolume(HID_USAGE_CONSUMER_VOLUME_INCREMENT);
      else
        sendVolume(HID_USAGE_CONSUMER_VOLUME_DECREMENT);
    } else {
      if (move > 0)
        sendKey(HID_KEY_PAGE_DOWN);
      else
        sendKey(HID_KEY_PAGE_UP);
    }
  }
}

Credits

Arnov Sharma
373 projects • 389 followers
I'm Arnov. I build, design, and experiment with tech—3D printing, PCB design, and retro consoles are my jam.

Comments