#include <EEPROM.h>
#define MODE_EEPROM_ADDR 10
// Init Pins
const uint8_t buttonPins[] = {12, 11, 10, 9, 7, 6, 5, 4};
const uint8_t ledPins[] = {A0, A1, 2, 3, A4, A5};
const uint8_t led4Pin = A2;
const int numButton = sizeof(buttonPins) / sizeof(buttonPins[0]);
const int numLed = sizeof(ledPins) / sizeof(ledPins[0]);
int buttonRead[numButton] = {LOW};
// Init Mode Button
int animMode = 0; // 0 and 1
int modeLastButtonState = LOW;
int modeButtonState;
bool modeButtonPressed = false;
// Init Speed Button
bool delayUpButtonPressed = false;
bool delayDownButtonPressed = false;
// Init Animation Button
const int animDelayTimeRef = 1000;
int animDelayTime = animDelayTimeRef; // initial delay for animation
int buttonStates[numButton] = {LOW}; // Array to store the current state of the buttons
int lastButtonStates[numButton] = {LOW}; // Array to store the previous state of the buttons
int animButtonCounter = 0;
int animButtonLastPressed;
unsigned long buttonPressTime[numButton] = {0}; // Array to store the time when each button was last pressed
bool isAnim = false;
unsigned long lastDebounceTime[numButton] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned long debounceDelay = 50;
int selectedAnim = -1; // Array to store the current selected anim
unsigned long animPreviousMillis = 0;
uint32_t animBatch = 0;
unsigned long delayMillis = 10000;
int animLedFlag[numLed] = {LOW}; // Array to store which LED is HIGH while anim is running
void anim1();
void anim2();
void anim3();
void anim4();
void anim5();
void anim6();
void anim7();
void anim8();
void anim9();
void anim10();
void anim11();
// Function pointer type for animation functions
typedef void (*AnimationFunction)();
// Array of animation functions
AnimationFunction animations[] = {anim1, anim2, anim3, anim4, anim5, anim6, anim7, anim8, anim9, anim10, anim11};
void setup() {
Serial.begin(9600);
for (uint8_t i = 0; i < numButton; i++) {
pinMode(buttonPins[i], INPUT);
}
for (uint8_t i = 0; i < numLed; i++) {
pinMode(ledPins[i], OUTPUT);
}
pinMode(led4Pin, OUTPUT);
animMode = readIntFromEEPROM(MODE_EEPROM_ADDR);
if(animMode == -1) {animMode = 0;} // init
Serial.println(animMode);
}
void loop() {
readButtons();
handleButtons();
handleAnimations();
}
void readButtons() {
for (int i = 0; i < 8; i++) {
int reading = digitalRead(buttonPins[i]);
if (reading != lastButtonStates[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != buttonStates[i]) {
buttonStates[i] = reading;
}
}
lastButtonStates[i] = reading;
}
}
void handleButtons() {
// Delay Up
if (buttonStates[1] == HIGH && buttonStates[6] == HIGH) {
if (checkBothButtonsPressed(1, 6)) {
Serial.println("Triggered: delayUp");
delayUp();
delayUpButtonPressed = true;
}
}
// Delay Down
if (buttonStates[2] == HIGH && buttonStates[6] == HIGH ) {
if (checkBothButtonsPressed(2, 6)) {
Serial.println("Triggered: delayDown");
delayDown();
delayDownButtonPressed = true;
}
}
// Animation 1 - Animation 11
if (buttonStates[4] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: anim1");
resetAnim();
selectedAnim = 0;
} else if (buttonStates[7] == HIGH) {
Serial.println("Triggered: anim2");
resetAnim();
selectedAnim = 1;
} else if (buttonStates[0] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: anim3");
resetAnim();
selectedAnim = 2;
} else if (buttonStates[0] == HIGH) {
Serial.println("Triggered: anim4");
resetAnim();
selectedAnim = 3;
} else if (buttonStates[0] == HIGH && buttonStates[1] == HIGH) {
Serial.println("Triggered: anim5");
resetAnim();
selectedAnim = 4;
} else if (buttonStates[1] == HIGH) {
Serial.println("Triggered: anim6");
resetAnim();
selectedAnim = 5;
} else if (buttonStates[3] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: anim7");
resetAnim();
selectedAnim = 6;
} else if (buttonStates[4] == HIGH) {
Serial.println("Triggered: anim8");
resetAnim();
selectedAnim = 7;
} else if (buttonStates[4] == HIGH && buttonStates[5] == HIGH) {
Serial.println("Triggered: anim9");
resetAnim();
selectedAnim = 8;
} else if (buttonStates[5] == HIGH) {
Serial.println("Triggered: anim10");
resetAnim();
selectedAnim = 9;
} else if (buttonStates[5] == HIGH && buttonStates[6] == HIGH) {
Serial.println("Triggered: anim11");
resetAnim();
selectedAnim = 10;
}
// Mode
if (buttonStates[6] == HIGH && !modeButtonPressed) {
Serial.println("Triggered: modeFunction");
modeFunction();
modeButtonPressed = true;
} else if (buttonStates[6] == LOW) {
modeButtonPressed = false;
}
// Manual Button 1 - Manual Button 6
if (buttonStates[0] == HIGH && buttonStates[4] == HIGH) {
Serial.println("Triggered: LED1 ON");
digitalWrite(ledPins[0], HIGH);
} else {
manualTurnOffLed(0);
}
if (buttonStates[3] == HIGH) {
Serial.println("Triggered: LED2 ON");
digitalWrite(ledPins[1], HIGH);
} else {
manualTurnOffLed(1);
}
if (buttonStates[5] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: LED3 ON");
digitalWrite(ledPins[2], HIGH);
} else {
manualTurnOffLed(2);
}
if (buttonStates[0] == HIGH && buttonStates[5] == HIGH) {
Serial.println("Triggered: LED4 ON");
digitalWrite(ledPins[3], HIGH);
} else {
manualTurnOffLed(3);
}
if (buttonStates[2] == HIGH) {
Serial.println("Triggered: LED5 ON");
digitalWrite(ledPins[4], HIGH);
} else {
manualTurnOffLed(4);
}
if (buttonStates[1] == HIGH && buttonStates[5] == HIGH) {
Serial.println("Triggered: LED6 ON");
digitalWrite(ledPins[5], HIGH);
} else {
manualTurnOffLed(5);
}
}
// Add this function to check if both buttons are pressed within a tolerance
bool checkBothButtonsPressed(int button1, int button2) {
int tolerance = 20;
int currentButtonState1 = buttonStates[button1];
int currentButtonState2 = buttonStates[button2];
// Check if both buttons were pressed within the tolerance window
return (currentButtonState1 == HIGH && currentButtonState2 == HIGH &&
millis() - lastDebounceTime[button1] < tolerance &&
millis() - lastDebounceTime[button2] < tolerance);
}
void handleAnimations() {
// Check if selectedAnim is within a valid range
if (selectedAnim >= 0 && selectedAnim < sizeof(animations) / sizeof(animations[0])) {
// Call the selected animation function
animations[selectedAnim]();
} else {
// Serial.println("Invalid animation selection");
}
}
void anim1() {
// Implement your anim1 function here
// Seperti delay pada umumnya namun tidak memblock program lain
// Tambah animasi dengan menambah else if animBatch +1
int maxAnimBatch;
if(animMode == 0) {
maxAnimBatch = 5;
if(animBatch == 0) {
animDigitalWrite(0, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 1) {
animDigitalWrite(0, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 2) {
animDigitalWrite(1, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 3) {
animDigitalWrite(1, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 4) {
animDigitalWrite(2, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 5) {
animDigitalWrite(2, LOW);
delayMillis = 0; // Delay terakhir 0
}
} else {
maxAnimBatch = 5;
if(animBatch == 0) {
animDigitalWrite(0, HIGH);
animDigitalWrite(1, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 1) {
animDigitalWrite(0, LOW);
animDigitalWrite(1, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 2) {
animDigitalWrite(2, HIGH);
animDigitalWrite(3, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 3) {
animDigitalWrite(2, LOW);
animDigitalWrite(3, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 4) {
animDigitalWrite(4, HIGH);
animDigitalWrite(5, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 5) {
animDigitalWrite(4, LOW);
animDigitalWrite(5, LOW);
delayMillis = 0; // Delay terakhir 0
}
}
// Millis function logic. Set parameter to max animBatch
animMillisFunction(5);
}
void anim2() {
// Implement your anim2 function here
anim1();
}
void anim3() {
// Implement your anim1 function here
anim1();
}
void anim4() {
// Implement your anim2 function here
anim1();
}
void anim5() {
// Implement your anim1 function here
anim1();
}
void anim6() {
// Implement your anim2 function here
anim1();
}
void anim7() {
// Implement your anim1 function here
anim1();
}
void anim8() {
// Implement your anim2 function here
anim1();
}
void anim9() {
// Implement your anim1 function here
anim1();
}
void anim10() {
// Implement your anim2 function here
anim1();
}
void anim11() {
// Implement your anim1 function here
anim1();
}
// Define other animation functions (anim3, anim4, ..., anim11) similarly
void modeFunction() {
resetAnim();
animMode = !animMode;
writeIntIntoEEPROM(MODE_EEPROM_ADDR, animMode); // Save Mode to EEPROM
Serial.println(animMode);
}
void delayUp() {
animDelayTime = min(animDelayTime * 1.1, animDelayTimeRef * 2);
Serial.println(animDelayTime);
}
void delayDown() {
animDelayTime = max(animDelayTime / 1.1, animDelayTimeRef / 2);
Serial.println(animDelayTime);
}
// ----------------------------------
// Utility Function
void animMillisFunction(int maxBatch) {
if(millis() - animPreviousMillis > delayMillis) {
animPreviousMillis = millis();
// animBatch >= di sesuaikan dengan jumlah maksimal batch animasi
if(animBatch >= maxBatch) {
isAnim = false;
// resetAnim();
} else {
animBatch += 1;
}
}
}
void animDigitalWrite(int ledIndex, int state) {
digitalWrite(ledPins[ledIndex], state);
animLedFlag[ledIndex] = state;
}
void manualTurnOffLed(int ledIndex) {
if(animLedFlag[ledIndex] == LOW) {
digitalWrite(ledPins[ledIndex], LOW);
}
}
void turnOffAllLeds() {
for(uint8_t i = 0; i < numLed; i++) {
digitalWrite(ledPins[i], LOW);
}
}
void resetAnim() {
animBatch = 0;
turnOffAllLeds();
// if(!isSelectedAnim) {
// selectedAnim = -1;
// }
}
boolean compareArray(int a[], int b[]) {
const int arraySize = sizeof(a) / sizeof(a[0]);
boolean res = true;
for (int i = 0; i < arraySize; i++) {
if( a[i] != b[i] ) {
// Serial.println("not equal");
//set your boolean flag here
res = false;
break;
}
}
return res;
}
void writeIntIntoEEPROM(int address, int number) {
EEPROM.write(address, number >> 8);
EEPROM.write(address + 1, number & 0xFF);
}
int readIntFromEEPROM(int address) {
return (EEPROM.read(address) << 8) + EEPROM.read(address + 1);
}