// https://wokwi.com/projects/387121472215461889
// https://forum.arduino.cc/t/effect-switcher-and-relays-eeprom-question/1209660
# include <EEPROM.h>
# include <LiquidCrystal.h>
# include <Wire.h>
# include <Keypad.h>
# include <ezButton.h>
ezButton ezBankButton(A6), ezProgButton(A7), ezSaveButton(A9), ezDownButton(A12);
LiquidCrystal lcd(A5, A4, A3, A2, A1, A0);
#define rHot LOW
#define rGnd HIGH
void setupRelays();
void switchRelay(int, int);
const byte rows = 9;
const byte cols = 1;
char keys[rows][cols] = {
{'a'},
{'b'},
{'c'},
{'d'},
{'e'},
{'f'},
{'g'},
{'h'},
{'i'},
};
byte rowPins[rows] = { 34, 35, 36, 37, 38, 39, 40, 41, 42 }; /* buttons or momentary switches */
const byte colPins[cols] = { A15}; // just 1 column a..i
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
const int OneRelayPin[9] = { 11, 14, 15, 16, 17, 18, 19, 20, 21 }; /* pin 1 on relay - reset/default has pin 1 at 0v - RED LED */
const int TenRelayPin[9] = { 10, 9, 8, 7, 6, 5, 4, 3, 2 }; /* pin 10 on relay - reset/default has pin 10 at 5v - BLUE LED */
const int presetLEDPin[9] = { 44, 45, 46, 47, 48, 49, 50, 51, 52 }; /* shows which preset is engaged - GREEN LED */
const int effectLEDPin[9] = { 22, 23, 24, 25, 26, 27, 28, 29, 30 }; /* shows which effects are engaged - YELLOW LED */
const int progLED = A8; // shows if we're in program mode - GREEN LED
const int saveLED = A10; // shows if we're in save mode - YELLOW LED (dull red, turns yellow when combined with program's GREEN LED)
byte midiChannel = 0;
const int numberOfPedal = 9;
const int bankVariable = 9; // bank variable of "9" ensures banks are never overwritten by accident
const int numberOfBanks = 9; // up to 11 works well. After that, need to find a new bankVariable number
int bank = 0; //Starting Bank Number
boolean saveOn = false;
boolean progOn = false;
/******************************************************/
void setup() {
lcd.begin(16, 2);
lcd.print("I am a");
lcd.setCursor(0, 1);
lcd.print("realcowboy.");
setupRelays(); // pins and initial state
pinMode(progLED, OUTPUT);
pinMode(saveLED, OUTPUT);
for (int ii = 0; ii < numberOfPedal; ii++) /* setup device */
{
pinMode(presetLEDPin[ii], OUTPUT);
pinMode(effectLEDPin[ii], OUTPUT);
digitalWrite(presetLEDPin[ii], LOW);
digitalWrite(effectLEDPin[ii], LOW);
delay(10);
}
delay(10);
for (int ii = 0; ii < numberOfPedal; ii++) {
digitalWrite(presetLEDPin[ii], HIGH);
digitalWrite(effectLEDPin[ii], HIGH);
delay(10);
}
digitalWrite(progLED, LOW);
digitalWrite(saveLED, LOW);
delay(10);
digitalWrite(progLED, HIGH);
digitalWrite(saveLED, HIGH);
delay(10);
Serial.begin(31250); /* for midi communication - pin 1 TX */
ezBankButton.setDebounceTime(20);
ezProgButton.setDebounceTime(20);
ezSaveButton.setDebounceTime(20);
ezDownButton.setDebounceTime(20);
delay (1500);
}
/*********************************************************/
void midiProg(byte status, int data) {
Serial.write(status);
Serial.write(data);
}
/*********************************************************/
// save your effect/loop selections to a preset
void memory(int addr, int led) {
for (int ii = 0; ii < numberOfPedal; ii++) {
EEPROM.write((addr) + ii, digitalRead(effectLEDPin[ii]));
digitalWrite(presetLEDPin[ii], HIGH); // turns off all preset LEDs
}
lcd.clear();
lcd.print("Program saved to");
lcd.setCursor(0, 1);
lcd.print("Bank ");
lcd.print(bank);
lcd.print(" Preset ");
lcd.print(led + 1);
/* Preset LED will flash when saving effects loops */
delay(100);
digitalWrite(presetLEDPin[led], LOW);
delay(100);
digitalWrite(presetLEDPin[led], HIGH);
delay(100);
digitalWrite(presetLEDPin[led], LOW);
delay(100);
digitalWrite(presetLEDPin[led], HIGH);
delay(100);
digitalWrite(presetLEDPin[led], LOW);
delay(100);
digitalWrite(presetLEDPin[led], HIGH);
delay(100);
digitalWrite(presetLEDPin[led], LOW);
delay(100);
digitalWrite(presetLEDPin[led], HIGH);
delay(100);
digitalWrite(presetLEDPin[led], LOW);
delay(100);
digitalWrite(presetLEDPin[led], HIGH);
delay(100);
digitalWrite(presetLEDPin[led], LOW);
delay(100);
digitalWrite(presetLEDPin[led], HIGH);
saveOn = !saveOn; // turn off program/save modes
progOn = !progOn;
for (int ii = 0; ii < numberOfPedal; ii++) {
digitalWrite(effectLEDPin[ii], HIGH); // turns off all effect LEDs
}
lcd.clear();
lcd.print("Program Again Or");
lcd.setCursor(0, 1);
lcd.print("Press Any Preset");
}
/*********************************************************/
void resetAllRelays() {
for (int ii = 0; ii < numberOfPedal; ii++){
digitalWrite(OneRelayPin[ii], rGnd);
digitalWrite(TenRelayPin[ii], rGnd);
}
}
/*********************************************************/
void resetAllLeds() {
for (int ii = 0; ii < numberOfPedal; ii++) {
digitalWrite(presetLEDPin[ii], HIGH);
}
}
/*********************************************************/
// select your effects/loops
void writeOut(int relay) {
resetAllLeds();
digitalWrite(effectLEDPin[relay], !digitalRead(effectLEDPin[relay]));
lcd.clear();
lcd.print("Current Bank: ");
lcd.print(bank);
lcd.setCursor(0, 1);
lcd.print("Select Loops: ");
lcd.print(relay + 1);
}
/*********************************************************/
// default mode - USE THE SWITCH!
void readPreset(int addr, int pcNum, int led) {
for (int ii = 0; ii < numberOfPedal; ii++) {
int kPreset = EEPROM.read((addr) + ii);
switchRelay(ii, kPreset ? HIGH : LOW);
digitalWrite(effectLEDPin[ii], EEPROM.read((addr) + ii));
digitalWrite(presetLEDPin[ii], HIGH);
}
digitalWrite(presetLEDPin[led], LOW);
lcd.clear();
lcd.print(" B-");
lcd.print(bank);
lcd.setCursor(0, 1);
lcd.print("Preset ");
lcd.print(led + 1);
delay(9);
resetAllRelays();
}
/*********************************************************/
void loop() {
ezBankButton.loop();
ezProgButton.loop();
ezSaveButton.loop();
ezDownButton.loop();
bool doBank = ezBankButton.isPressed();
bool doProg = ezProgButton.isPressed();
bool doSave = ezSaveButton.isPressed();
bool doDown = ezDownButton.isPressed(); // down will be easier to get working now ;-)
static bool firstTime = true;
doBank |= firstTime; firstTime = false; // makes the bank = 1 on start up
if (doBank) {
bank++;
Serial.print("bank became "); Serial.println(bank);
for (int ii = 0; ii < numberOfPedal; ii++) {
digitalWrite(presetLEDPin[ii], HIGH); //turn OFF all preset/effect LEDs
digitalWrite(effectLEDPin[ii], HIGH);
}
lcd.clear();
lcd.print(" B-");
lcd.print(bank);
lcd.setCursor(0, 1);
lcd.print("Press Any Preset");
if (bank >= numberOfBanks + 1) {
bank = 1;
Serial.println(" bank zeroed ");
}
}
if (doProg) {
progOn = !progOn;
if (progOn == HIGH && saveOn == HIGH) {
saveOn = !saveOn; // make sure we're not in save mode
lcd.clear();
lcd.print("Program Mode:");
lcd.setCursor(0, 1);
lcd.print("Select Loops");
} else if (progOn == HIGH) {
for (int ii = 0; ii < numberOfPedal; ii++) {
digitalWrite(presetLEDPin[ii], HIGH); //turn OFF all preset/effect LEDs
digitalWrite(effectLEDPin[ii], HIGH);
}
lcd.clear();
lcd.print("Program Mode:");
lcd.setCursor(0, 1);
lcd.print("Select Loops");
} else {
lcd.clear(); // resets the LCD to default if we exit program mode
lcd.print(" B-");
lcd.print(bank);
lcd.setCursor(0, 1);
lcd.print("Press Any Preset");
if (bank >= numberOfBanks + 1) {
bank = 1;
Serial.println(" bank zeroed ");
}
}
}
digitalWrite(progLED, progOn);
if (doSave) {
saveOn = !saveOn;
if (saveOn == HIGH && progOn == HIGH) {
lcd.clear(); // actual save mode
lcd.print("Save Mode:");
lcd.setCursor(0, 1);
lcd.print("Select Preset");
} else if (saveOn == HIGH && progOn == LOW) {
lcd.clear(); // warns to exit save mode before hitting any buttons
lcd.print("Uh Oh: Exit Save");
lcd.print(bank);
lcd.setCursor(0, 1);
lcd.print("Mode ASAP!");
if (bank >= numberOfBanks + 1) {
bank = 1;
Serial.println(" bank zeroed ");
}
digitalWrite(saveLED, saveOn);
} else {
lcd.clear(); // resets the LCD to default if we exit save mode
lcd.print(" B-");
lcd.print(bank);
lcd.setCursor(0, 1);
lcd.print("Press Any Preset");
if (bank >= numberOfBanks + 1) {
bank = 1;
Serial.println(" bank zeroed ");
}
}
}
digitalWrite(saveLED, saveOn);
unsigned char kMode = 0;
if (saveOn) kMode += 2;
if (progOn) kMode += 1;
char key = keypad.getKey();
if (!key) return;
char mKey = key - 'a'; // mKey is therefore 0..8
if (0) {
Serial.print(kMode); Serial.print(" mode ");
Serial.print((int) mKey); Serial.print(" token ");
Serial.println("");
}
# define READ 0
# define WRITE 1
# define MEMORY 3
switch (kMode) {
case WRITE :
writeOut(mKey); // relay
break;
case MEMORY :
Serial.print("memory bank is "); Serial.println(bank);
memory(bank * bankVariable + 100 * (mKey), mKey); // addr, led
break;
case READ :
Serial.print("read bank is "); Serial.print(bank); Serial.print("-"); Serial.println(bank * bankVariable + 100 * (mKey));
readPreset(bank * bankVariable + 100 * (mKey), mKey + 1, mKey); // addr, pcNum, relay
break;
default :
Serial.print(kMode); Serial.println(" error");
}
}
void setupRelays() {
for (int ii = 0; ii < numberOfPedal; ii++) {
pinMode(OneRelayPin[ii], OUTPUT);
pinMode(TenRelayPin[ii], OUTPUT);
digitalWrite(OneRelayPin[ii], LOW);
delay(20);
digitalWrite(TenRelayPin[ii], LOW);
digitalWrite(OneRelayPin[ii], HIGH);
delay(20);
digitalWrite(TenRelayPin[ii], HIGH);
// initRelay();
}
}
void switchRelay(int relayNumber, int onOff) {
// engages relays on and off in read mode
if (onOff) {
digitalWrite(OneRelayPin[relayNumber], rGnd);
digitalWrite(TenRelayPin[relayNumber], rHot);
} else {
digitalWrite(TenRelayPin[relayNumber], rGnd);
digitalWrite(OneRelayPin[relayNumber], rHot);
}
}
/*
void initRelay() {
// cascades all relays to default state
// digitalWrite(OneRelayPin[relayNumber], rGnd);
digitalWrite(TenRelayPin[relayNumber], rHot);
//}
//digitalWrite(OneRelayPin[relayNumber], rGnd);
delay(20);
digitalWrite(TenRelayPin[relayNumber], rGnd);
//delay(20);
}*/BANK
PROG
SAVE