#include <EEPROM.h>
#define MODE_EEPROM_ADDR 10
// Define pin assignments
#define LED_PIN PB6
#define BUTTON_PIN PB7
// Init Pins
// const uint8_t buttonPins[] = {12, 11, 10, 9, 7, 6, 5, 4};
const uint8_t buttonPins[] = {4, 5, 6, 7, 9, 10, 11, 12};
const uint8_t ledPins[] = {A0, A1, 2, 3, A4, A5};
const uint8_t additionalLedPin = A2;
const int numButton = sizeof(buttonPins) / sizeof(buttonPins[0]);
const int numLed = sizeof(ledPins) / sizeof(ledPins[0]);
int buttonRead[numButton] = {LOW};
// Additional LED
bool isAnim = false;
bool isManual = false;
bool manualButtonState[numLed] = {0};
// 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
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;
bool elapsedButtonFlag = false;
unsigned long startButtonTime = 0;
unsigned long elapsedButtonTime = 0;
int animLedFlag[numLed] = {LOW}; // Array to store which LED is HIGH while anim is running
bool checkBothButtonsPressed(int button1, int button2, bool inverse=false);
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() {
// Disable the external crystal oscillator
cli(); // Disable interrupts
// Clear the external crystal oscillator bits in the configuration register
CLKPR = (1 << CLKPCE); // Enable change of clock division
CLKPR = 0; // Set clock division factor to 1 (no division)
sei(); // Enable interrupts
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(additionalLedPin, OUTPUT);
animMode = readIntFromEEPROM(MODE_EEPROM_ADDR);
if(animMode == -1) {animMode = 0;} // init
Serial.println(animMode);
}
void loop() {
readButtons();
handleButtons();
handleAnimations();
handleAdditionalLed();
}
void handleAdditionalLed() {
isManual = false;
for (int i = 0; i < numLed; i++) {
if (manualButtonState[i] == true) {
isManual = true;
break;
}
}
if (isAnim == 1 || isManual == 1) {
digitalWrite(additionalLedPin, HIGH);
} else {
digitalWrite(additionalLedPin, LOW);
}
}
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;
} else {delayUpButtonPressed = false;}
}
// Delay Down
if (buttonStates[2] == HIGH && buttonStates[6] == HIGH ) {
if (checkBothButtonsPressed(2, 6)) {
Serial.println("Triggered: delayDown");
delayDown();
delayDownButtonPressed = true;
} else {delayDownButtonPressed = false;Serial.println("DON'T DELETE THIS");}
}
// Animation 1 - Animation 11
if (buttonStates[4] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: anim1");
resetAnim();
selectedAnim = 0;
} else if (buttonStates[0] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: anim3");
resetAnim();
selectedAnim = 2;
} else if (buttonStates[3] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: anim7");
resetAnim();
selectedAnim = 6;
} else if (buttonStates[7] == HIGH) {
if(buttonStates[5] == LOW) {
Serial.println("Triggered: anim2");
resetAnim();
selectedAnim = 1;
}
} else if (buttonStates[0] == HIGH && buttonStates[1] == HIGH) {
Serial.println("Triggered: anim5");
resetAnim();
selectedAnim = 4;
} else if (buttonStates[0] == HIGH) {
if(buttonStates[4] == LOW && buttonStates[5] == LOW) {
Serial.println("Triggered: anim4");
resetAnim();
selectedAnim = 3;
}
} else if (buttonStates[1] == HIGH) {
if (buttonStates[6] == LOW && buttonStates[5] == LOW) {
Serial.println("Triggered: anim6");
resetAnim();
selectedAnim = 5;
} else {Serial.println("DON'T DELETE THIS");}
} else if (buttonStates[4] == HIGH && buttonStates[5] == HIGH) {
Serial.println("Triggered: anim9");
resetAnim();
selectedAnim = 8;
} else if (buttonStates[4] == HIGH) {
if(buttonStates[0] == LOW && buttonStates[5] == LOW) {
Serial.println("Triggered: anim8");
resetAnim();
selectedAnim = 7;
}
} else if (buttonStates[5] == HIGH && buttonStates[6] == HIGH) {
Serial.println("Triggered: anim11");
resetAnim();
selectedAnim = 10;
} else if (buttonStates[5] == HIGH) {
if(buttonStates[1] == LOW && buttonStates[4] == LOW) {
Serial.println("Triggered: anim10");
resetAnim();
selectedAnim = 9;
}
}
// Mode
if (buttonStates[6] == HIGH) {
if(!modeButtonPressed && !delayUpButtonPressed &&
!delayDownButtonPressed && buttonStates[1] == LOW &&
buttonStates[2] == LOW && buttonStates[5] == LOW) {
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");
manualTurnOnLed(0, HIGH);
} else {
manualTurnOffLed(0);
}
if (buttonStates[3] == HIGH) {
if (!checkBothButtonsPressed(3, 7, true)) {
Serial.println("Triggered: LED2 ON");
manualTurnOnLed(1, HIGH);
}
} else {
manualTurnOffLed(1);
}
if (buttonStates[5] == HIGH && buttonStates[7] == HIGH) {
Serial.println("Triggered: LED3 ON");
manualTurnOnLed(2, HIGH);
} else {
manualTurnOffLed(2);
}
if (buttonStates[0] == HIGH && buttonStates[5] == HIGH) {
Serial.println("Triggered: LED4 ON");
manualTurnOnLed(3, HIGH);
} else {
manualTurnOffLed(3);
}
if (buttonStates[2] == HIGH) {
if (!checkBothButtonsPressed(2, 6, true)) {
Serial.println("Triggered: LED5 ON");
manualTurnOnLed(4, HIGH);
}
} else {
manualTurnOffLed(4);
}
if (buttonStates[1] == HIGH && buttonStates[5] == HIGH) {
Serial.println("Triggered: LED6 ON");
manualTurnOnLed(5, HIGH);
} else {
manualTurnOffLed(5);
}
}
void modeButtonAnimation() {
if(!animMode) {
digitalWrite(ledPins[0], HIGH);
delay(100);
digitalWrite(ledPins[0], LOW);
} else {
digitalWrite(ledPins[0], HIGH);
delay(100);
digitalWrite(ledPins[0], LOW);
delay(100);
digitalWrite(ledPins[1], HIGH);
delay(100);
digitalWrite(ledPins[1], LOW);
}
}
// Add this function to check if both buttons are pressed within a tolerance
bool checkBothButtonsPressed(int button1, int button2, bool inverse=false) {
int tolerance = 20;
int currentButtonState1 = buttonStates[button1];
int currentButtonState2 = buttonStates[button2];
if(inverse) {
return (currentButtonState1 == HIGH && currentButtonState2 == HIGH &&
millis() - lastDebounceTime[button1] > tolerance &&
millis() - lastDebounceTime[button2] > tolerance);
}
// 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]();
isAnim = true;
} else {
isAnim = false;
// 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(maxAnimBatch);
}
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() {
// if (!checkBothButtonsPressed(1, 6, true)) {
resetAnim();
animMode = !animMode;
writeIntIntoEEPROM(MODE_EEPROM_ADDR, animMode); // Save Mode to EEPROM
Serial.println(animMode);
modeButtonAnimation();
// } else {Serial.println("DON'T DELETE THIS");}
}
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) {
selectedAnim = -1;
// resetAnim();
} else {
animBatch += 1;
}
}
}
void animDigitalWrite(int ledIndex, int state) {
digitalWrite(ledPins[ledIndex], manualButtonState[ledIndex]? HIGH:state);
animLedFlag[ledIndex] = state;
}
void manualTurnOnLed(int ledIndex, int state) {
digitalWrite(ledPins[ledIndex], state);
manualButtonState[ledIndex] = true;
isManual = true;
}
void manualTurnOffLed(int ledIndex) {
if(animLedFlag[ledIndex] == LOW) {
digitalWrite(ledPins[ledIndex], LOW);
manualButtonState[ledIndex] = false;
}
}
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);
}