commit 5fbf5ea2e0c7b41f3d1f3d129d8f3ed3c8091046 Author: Stefan Ritter Date: Wed Mar 15 17:02:07 2023 +0100 Init diff --git a/Code/Code.ino b/Code/Code.ino new file mode 100644 index 0000000..a6e85f5 --- /dev/null +++ b/Code/Code.ino @@ -0,0 +1,212 @@ +// +// Cavaliere Heartbeat +// + +#include +#include // Encoder by Paul Stoffregen + +#include +Adafruit_SSD1306 display(128, 64, &Wire, 4); + +#define audio 12 // Pin for 3,5 Jack +#define led 13 // Pin for LED +#define rot_clk 4 // Rotary encoder CLK pin +#define rot_dt 3 // Rotary encoder DT pin +#define rot_sw 2 // Rotary encoder SW pin, 1 = not pushed, 0 = pushed +#define triggerLengthMS 50 // How long the trigger should stay on in milliseconds when triggerLength = 1 +#define bpm_value_min 80 // 20 bpm is minimum (80 / 4) +#define bpm_value_max 1200 // 300 bpm is maximum (300 * 4) +#define offset_x 5 // Display offset +#define offset_y 5 // Display offset + +int bpm; // BPM, who'd have thought +int bpms; // BPM to milliseconds +int eeprom_bpm; // BPM stored in EEPROM +int bpm_value; // Later bpm * 4 because of the 4 rotary encoder steps +int triggerLength = 2; // 1 = triggerLengthMS, 2 = half of bpm +int stayOnTime; // How long the trigger should stay on in milliseconds when triggerLength = 2 +unsigned long currentTime; // Timing stuff +unsigned long previousTime = 0; // Timing stuff +int state = 0; // Prevent trigger flood +int rot_sw_state = 0; // Rotary encoder SW state +int rot_sw_temp = 0; // Some dumb temp shit +long rot_old_pos = 0; // Don't ask + +// Pins for the rotary encoder up and down +Encoder rot_enc(rot_dt, rot_clk); + +void setup() { + Serial.begin(9600); + + // Read stored BPM data + if (EEPROM.read(0) != 1) { + // No BPM data stored, let's initialize it with 120 BPM + EEPROM.write(0, 1); // Set byte 0 to 1 + EEPROM.write(1, 1); // 1 x 100 + EEPROM.write(2, 2); // 2 x 10 + EEPROM.write(3, 0); // 0 x 1 + bpm = 120; + bpm_value = bpm * 4; + bpms = 60000 / bpm; + Serial.println("No stored BPM found. Initialized with 120 BPM."); + } else { + // BPM data stored + int a = EEPROM.read(1); + int b = EEPROM.read(2); + int c = EEPROM.read(3); + eeprom_bpm = (a * 100) + (b * 10) + (c * 1); + bpm = eeprom_bpm; + bpm_value = bpm * 4; + bpms = 60000 / bpm; + Serial.print("Stored BPM data found: "); + Serial.println(eeprom_bpm); + } + + // Display + display.begin(SSD1306_SWITCHCAPVCC, 0x3C); + display.setTextColor(SSD1306_WHITE); + displayUpdate(bpm, bpm); + + // Calculate how long the LED should stay on + if (triggerLength == 1) { + stayOnTime = triggerLengthMS; + } else if (triggerLength == 2) { + stayOnTime = bpms / 2; + } + + // Enable inputs and outputs + pinMode(audio, OUTPUT); + pinMode(led, OUTPUT); + pinMode(rot_clk, INPUT); + pinMode(rot_dt, INPUT); + pinMode(rot_sw, INPUT); +} + +void loop() { + // Beat stuff + currentTime = millis(); + + if (currentTime - previousTime >= bpms) { + triggerOn(); + previousTime = currentTime; + state = 1; + } + + if (currentTime - previousTime >= stayOnTime && state == 1) { + triggerOff(); + state = 0; + } + + // Rotary encoder stuff + long rot_new_pos = rot_enc.read(); + + if (rot_new_pos != rot_old_pos) { + if (rot_new_pos > rot_old_pos) { + bpm_value++; + if (bpm_value > bpm_value_max) { + bpm_value = bpm_value_max; + } + } + + if (rot_new_pos < rot_old_pos) { + bpm_value--; + if (bpm_value < bpm_value_min) { + bpm_value = bpm_value_min; + } + } + + displayUpdate(bpm, bpm_value / 4); + + rot_old_pos = rot_new_pos; + } + + // Rotary encoder button + rot_sw_state = digitalRead(rot_sw); + + if (rot_sw_state == 1) { + rot_sw_temp = 0; + } + + if (rot_sw_state == 0 && rot_sw_temp == 0) { + rot_sw_push(); + rot_sw_temp = 1; + } +} + +void triggerOn() { + Serial.print("Trigger ON at "); + Serial.print(currentTime); + Serial.println(" milliseconds"); + + digitalWrite(audio, HIGH); + digitalWrite(led, HIGH); +} + +void triggerOff() { + Serial.print("Trigger OFF at "); + Serial.print(currentTime); + Serial.println(" milliseconds"); + + digitalWrite(audio, LOW); + digitalWrite(led, LOW); +} + +void rot_sw_push() { + // Recalculate BPM stuff + bpm = bpm_value / 4; + bpms = 60000 / bpm; + if (triggerLength == 2) { + stayOnTime = bpms / 2; + } + + Serial.print("BPM set to "); + Serial.println(bpm); + + displayUpdate(bpm, bpm); + + // Save new BPM to EEPROM + int a = bpm / 100; + int b = (bpm - (a * 100)) / 10; + int c = (bpm - (a * 100) - (b * 10)); + EEPROM.write(1, a); + EEPROM.write(2, b); + EEPROM.write(3, c); +} + +int displayUpdate(int bpm, int bpm2) { + display.clearDisplay(); + + display.setTextSize(1); + display.setCursor(0 + offset_x, 0 + offset_y); + display.println("cavaliere HEARTBEAT"); + + display.setTextSize(2); + display.setCursor(0 + offset_x, 18 + offset_y); + display.println("BPM"); + display.setCursor(0 + offset_x, 40 + offset_y); + display.println("NEW"); + + String bpmToStr; + String bpm2ToStr; + + // Leading whitespace when bpm < 100 + display.setCursor(68 + offset_x, 18 + offset_y); + if (bpm < 100) { + bpmToStr = " " + String(bpm); + } else { + bpmToStr = String(bpm); + } + display.println(bpmToStr); + + // Leading whitespace when bpm2 < 100 + display.setCursor(68 + offset_x, 40 + offset_y); + if (bpm2 < 100) { + bpm2ToStr = " " + String(bpm2); + } else { + bpm2ToStr = String(bpm2); + } + display.println(bpm2ToStr); + + display.display(); + return 0; +} diff --git a/Fritzing/Circuit.fzz b/Fritzing/Circuit.fzz new file mode 100644 index 0000000..2dd9988 Binary files /dev/null and b/Fritzing/Circuit.fzz differ diff --git a/Fritzing/Rotary Encoder with switch (KY-040).fzpz b/Fritzing/Rotary Encoder with switch (KY-040).fzpz new file mode 100644 index 0000000..ea15a9f Binary files /dev/null and b/Fritzing/Rotary Encoder with switch (KY-040).fzpz differ diff --git a/Front/Front Plate.psd b/Front/Front Plate.psd new file mode 100644 index 0000000..95fcb3d Binary files /dev/null and b/Front/Front Plate.psd differ diff --git a/Logo/LCDAssistant.exe b/Logo/LCDAssistant.exe new file mode 100644 index 0000000..428e034 Binary files /dev/null and b/Logo/LCDAssistant.exe differ diff --git a/Logo/logo b/Logo/logo new file mode 100644 index 0000000..96f57b5 --- /dev/null +++ b/Logo/logo @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// File generated by LCD Assistant +// http://en.radzio.dxp.pl/bitmap_converter/ +//------------------------------------------------------------------------------ + +const unsigned char logo [] PROGMEM = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xEF, 0x01, 0x01, 0x01, 0x01, 0x01, +0x00, 0x00, 0xEF, 0xFF, 0x11, 0x11, 0x11, 0xFF, 0xFF, 0xEF, 0x00, 0x1F, 0xDF, 0xC0, 0x80, 0x80, +0xDE, 0x5F, 0x1F, 0x00, 0xEF, 0xFF, 0x11, 0x11, 0x11, 0xFF, 0xFF, 0xEF, 0x00, 0xEF, 0xEF, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xEF, 0x00, 0xEF, 0xFF, 0x11, 0x11, 0x11, 0x11, 0x11, +0x00, 0x00, 0xEF, 0xFF, 0x11, 0x11, 0x71, 0xFF, 0xDF, 0x0F, 0x00, 0xEF, 0xFF, 0x11, 0x11, 0x11, +0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x81, 0x61, 0x10, 0x60, 0x80, 0x00, 0x01, 0x01, 0x00, 0x00, +0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xE0, 0xF1, 0xF1, +0xE0, 0xC1, 0xE1, 0xF1, 0xF1, 0xE1, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, +0x01, 0x01, 0x81, 0x61, 0x10, 0x60, 0x81, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, +0x00, 0x01, 0x01, 0x81, 0xC1, 0xC1, 0x01, 0xC1, 0xC1, 0x41, 0x40, 0x40, 0x40, 0x40, 0x01, 0x06, +0xC8, 0xC6, 0x41, 0x41, 0x41, 0xC1, 0xC1, 0xC1, 0x01, 0xC1, 0xC1, 0x41, 0x41, 0x41, 0xC0, 0xC0, +0xC0, 0x00, 0x41, 0x43, 0x47, 0x4F, 0x47, 0x43, 0x41, 0x00, 0x00, 0xC0, 0xC0, 0x41, 0x41, 0x41, +0xC1, 0xC1, 0xC1, 0x01, 0xC1, 0xC1, 0x40, 0x40, 0x40, 0x40, 0x41, 0x06, 0x08, 0xC6, 0xC1, 0x41, +0x41, 0x41, 0xC1, 0xC1, 0xC1, 0x01, 0x41, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7B, 0x7F, 0x04, 0x04, 0x04, 0x3F, 0x7F, 0x7B, 0x00, 0x7B, 0x7F, 0x44, 0x44, 0x44, +0x44, 0x44, 0x00, 0x00, 0x7B, 0x7F, 0x04, 0x04, 0x04, 0x3F, 0x7F, 0x7B, 0x00, 0x7B, 0x7F, 0x04, +0x04, 0x1C, 0x7F, 0x77, 0x43, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x7B, +0x7F, 0x44, 0x44, 0x44, 0x7F, 0x7F, 0x7B, 0x00, 0x7B, 0x7F, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, +0x00, 0x7B, 0x7F, 0x04, 0x04, 0x04, 0x3F, 0x7F, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/Logo/logo.bmp b/Logo/logo.bmp new file mode 100644 index 0000000..6717963 Binary files /dev/null and b/Logo/logo.bmp differ