227 lines
6.9 KiB
C++
227 lines
6.9 KiB
C++
/*
|
|
* CDJ-1000 MK3 Jog Wheel + Touch Sensor Test
|
|
* =============================================
|
|
* Board: Arduino Pro Micro (ATmega32U4, 5V/16MHz)
|
|
* Wiring: JOG1 → D2 (INT1 — hardware interrupt)
|
|
* JOG2 → D3 (INT0 — hardware interrupt)
|
|
* TCH → D4 (active LOW, pull-up on JOGB PCB)
|
|
* V+5 → VCC (5V)
|
|
* GND → GND
|
|
*
|
|
* Both encoder pins use hardware interrupts — no missed
|
|
* pulses even at full scratch speed.
|
|
*
|
|
* Touch sensor is a pressure-sensitive sheet switch (DSX1065)
|
|
* with 22kΩ pull-up (R2007) and 22nF debounce cap (C2002)
|
|
* already on the JOGB PCB. TCH is HIGH when not touched,
|
|
* LOW when platter is pressed down.
|
|
*
|
|
* Install: Sketch > Include Library > Manage Libraries >
|
|
* search "Encoder" by Paul Stoffregen (PJRC)
|
|
*
|
|
* Flash: Board = "Arduino Leonardo", then Upload as normal.
|
|
* Rename this file to .ino or add it to an .ino
|
|
* wrapper if your IDE requires it.
|
|
*/
|
|
|
|
#include <Encoder.h>
|
|
|
|
// --- Pin Definitions ---
|
|
#define JOG1_PIN 2
|
|
#define JOG2_PIN 3
|
|
#define TOUCH_PIN 4
|
|
|
|
// --- Encoder Object ---
|
|
Encoder jogWheel(JOG1_PIN, JOG2_PIN);
|
|
|
|
// --- Known PPR (measured: 13000 ticks / 4x decoding = 3250) ---
|
|
#define KNOWN_PPR 3250
|
|
|
|
// --- State Variables ---
|
|
long oldPosition = 0;
|
|
unsigned long lastPrintTime = 0;
|
|
unsigned long lastChangeTime = 0;
|
|
|
|
// Touch state
|
|
bool lastTouchState = false;
|
|
|
|
// Rolling velocity calculation
|
|
long lastVelocityPos = 0;
|
|
unsigned long lastVelocityTime = 0;
|
|
const unsigned long VELOCITY_INTERVAL_MS = 50;
|
|
|
|
// Statistics
|
|
long minPosition = 0;
|
|
long maxPosition = 0;
|
|
unsigned long totalTicks = 0;
|
|
bool firstRevolution = true;
|
|
long revolutionStartPos = 0;
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
while (!Serial) {
|
|
; // Wait for serial port (Pro Micro native USB)
|
|
}
|
|
delay(500);
|
|
|
|
// Touch pin — external pull-up on JOGB PCB (R2007 22kΩ to 5V)
|
|
pinMode(TOUCH_PIN, INPUT);
|
|
|
|
Serial.println(F("========================================"));
|
|
Serial.println(F(" CDJ-1000 MK3 Jog Wheel + Touch Test"));
|
|
Serial.println(F(" Pro Micro (ATmega32U4)"));
|
|
Serial.println(F("========================================"));
|
|
Serial.println(F("Wiring: JOG1→D2, JOG2→D3, TCH→D4, 5V, GND"));
|
|
Serial.println(F(""));
|
|
Serial.println(F("Encoder: hardware interrupts — full speed."));
|
|
Serial.println(F("Touch: active LOW (press platter to trigger)"));
|
|
Serial.println(F("PPR: 3250 (13000 ticks / 4x decoding)"));
|
|
Serial.println(F(""));
|
|
Serial.println(F("Commands (send via Serial Monitor):"));
|
|
Serial.println(F(" 'r' - Reset position counter to 0"));
|
|
Serial.println(F(" 's' - Show statistics"));
|
|
Serial.println(F(" 'p' - Start PPR measurement (rotate exactly 1 turn)"));
|
|
Serial.println(F(" 't' - Read touch sensor state"));
|
|
Serial.println(F(""));
|
|
Serial.println(F("Rotate the jog wheel..."));
|
|
Serial.println(F("----------------------------------------"));
|
|
|
|
lastVelocityTime = millis();
|
|
}
|
|
|
|
void loop() {
|
|
unsigned long now = millis();
|
|
|
|
// --- Read Encoder ---
|
|
long newPosition = jogWheel.read();
|
|
|
|
// --- Read Touch Sensor ---
|
|
bool touched = !digitalRead(TOUCH_PIN); // Active LOW — invert
|
|
|
|
// Print on touch state change
|
|
if (touched != lastTouchState) {
|
|
if (touched) {
|
|
Serial.println(F(">>> TOUCH: PRESSED — vinyl mode <<<"));
|
|
} else {
|
|
Serial.println(F(">>> TOUCH: RELEASED <<<"));
|
|
}
|
|
lastTouchState = touched;
|
|
}
|
|
|
|
// --- Handle Serial Commands ---
|
|
if (Serial.available()) {
|
|
char cmd = Serial.read();
|
|
switch (cmd) {
|
|
case 'r':
|
|
case 'R':
|
|
jogWheel.write(0);
|
|
oldPosition = 0;
|
|
newPosition = 0;
|
|
minPosition = 0;
|
|
maxPosition = 0;
|
|
totalTicks = 0;
|
|
Serial.println(F("\n>>> Position RESET to 0 <<<\n"));
|
|
break;
|
|
|
|
case 's':
|
|
case 'S':
|
|
Serial.println(F("\n--- Statistics ---"));
|
|
Serial.print(F(" Current position: ")); Serial.println(newPosition);
|
|
Serial.print(F(" Min position: ")); Serial.println(minPosition);
|
|
Serial.print(F(" Max position: ")); Serial.println(maxPosition);
|
|
Serial.print(F(" Total range: ")); Serial.println(maxPosition - minPosition);
|
|
Serial.print(F(" Total ticks: ")); Serial.println(totalTicks);
|
|
Serial.print(F(" Touch state: ")); Serial.println(touched ? "PRESSED" : "released");
|
|
Serial.println(F("-----------------\n"));
|
|
break;
|
|
|
|
case 'p':
|
|
case 'P':
|
|
revolutionStartPos = newPosition;
|
|
firstRevolution = false;
|
|
Serial.println(F("\n>>> PPR Measurement Started <<<"));
|
|
Serial.println(F("Slowly rotate EXACTLY one full turn, then press 'p' again."));
|
|
Serial.print(F("Start position: ")); Serial.println(revolutionStartPos);
|
|
break;
|
|
|
|
case 't':
|
|
case 'T':
|
|
Serial.print(F("Touch sensor: "));
|
|
Serial.print(touched ? "PRESSED" : "released");
|
|
Serial.print(F(" (raw pin: "));
|
|
Serial.print(digitalRead(TOUCH_PIN));
|
|
Serial.println(F(")"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// --- Detect Encoder Changes ---
|
|
if (newPosition != oldPosition) {
|
|
long delta = newPosition - oldPosition;
|
|
lastChangeTime = now;
|
|
|
|
// Update statistics
|
|
totalTicks += abs(delta);
|
|
if (newPosition > maxPosition) maxPosition = newPosition;
|
|
if (newPosition < minPosition) minPosition = newPosition;
|
|
|
|
// Print position change
|
|
Serial.print(F("Pos: "));
|
|
Serial.print(newPosition);
|
|
Serial.print(F(" Δ: "));
|
|
Serial.print(delta);
|
|
Serial.print(F(" Dir: "));
|
|
Serial.print(delta > 0 ? "CW >>>" : "<<< CCW");
|
|
|
|
// Show touch state inline when spinning
|
|
if (touched) {
|
|
Serial.print(F(" [SCRATCH]"));
|
|
}
|
|
|
|
// PPR measurement helper
|
|
if (!firstRevolution) {
|
|
long pprDelta = abs(newPosition - revolutionStartPos);
|
|
Serial.print(F(" [PPR ticks: "));
|
|
Serial.print(pprDelta);
|
|
Serial.print(F("]"));
|
|
}
|
|
|
|
Serial.println();
|
|
oldPosition = newPosition;
|
|
}
|
|
|
|
// --- Velocity Calculation (periodic) ---
|
|
if (now - lastVelocityTime >= VELOCITY_INTERVAL_MS) {
|
|
long velocityDelta = newPosition - lastVelocityPos;
|
|
unsigned long dt = now - lastVelocityTime;
|
|
|
|
if (velocityDelta != 0) {
|
|
float ticksPerSec = (float)velocityDelta / dt * 1000.0;
|
|
float rpm = (ticksPerSec / (KNOWN_PPR * 4.0)) * 60.0;
|
|
|
|
Serial.print(F(" >> Velocity: "));
|
|
Serial.print(ticksPerSec, 1);
|
|
Serial.print(F(" ticks/sec RPM: "));
|
|
Serial.print(rpm, 2);
|
|
|
|
if (touched) {
|
|
Serial.print(F(" [VINYL]"));
|
|
}
|
|
|
|
Serial.println();
|
|
}
|
|
|
|
lastVelocityPos = newPosition;
|
|
lastVelocityTime = now;
|
|
}
|
|
|
|
// --- Idle detection ---
|
|
if (lastChangeTime > 0 && (now - lastChangeTime > 2000) && (now - lastPrintTime > 5000)) {
|
|
Serial.print(F(" [idle at position "));
|
|
Serial.print(newPosition);
|
|
Serial.print(F(", touch: "));
|
|
Serial.print(touched ? "PRESSED" : "released");
|
|
Serial.println(F("]"));
|
|
lastPrintTime = now;
|
|
}
|
|
} |