Combination Lock
I/O Ditigal Project
What I built
I made a combination lock. Each button corresponds to an LED light of the same color: red, green, and blue. Each light represents a single 0-9 digit of a 3-digit lock. Pressing a button increases its corresponding digit, and the lights blink in increasing faster rates corresponding to their digit. So, pressing the red button 1 time makes the red LED blink once per second. Pressing the green button 3 times makes the green LED light blink 3 times per second. Pressing the blue button 8 times makes the blue LED blink 8 times per second, and so on. Pressing a button 10 times resets its digit to 0.
The combination to unlock the "lock" is 2-0-8. Once you set each digit correctly, a short celebratory LED animation plays.
unsigned long currentTime;
unsigned long currentTick;
bool tick_On;
unsigned long currentATime;
unsigned long previousATime;
unsigned long previousBTime;
unsigned long previousCTime;
bool won = false;
void setup() {
pinMode(2, INPUT); // button red A
pinMode(3, INPUT); // button green B
pinMode(4, INPUT); // button blue C
pinMode(5, OUTPUT); // led red A
pinMode(6, OUTPUT); // led green B
pinMode(7, OUTPUT); // led blue C
currentTime = millis();
currentTick = currentTime;
previousATime = currentTime;
previousBTime = currentTime;
previousCTime = currentTime;
}
bool buttonA;
int countA;
bool ledA_On;
bool buttonB;
int countB;
bool ledB_On;
bool buttonC;
int countC;
bool ledC_On;
bool setChanging = false;
bool changing = false;
bool animatedChanging = false;
void loop() {
bool all = digitalRead(2) && digitalRead(3) && digitalRead(4);
if (all != setChanging) {
setChanging = !setChanging;
if (setChanging) {
animatedChanging = false;
changing = !changing;
countA = 0;
countB = 0;
countC = 0;
} else {
if (changing) {
if (!all && !animatedChanging) {
digitalWrite(5, true);
digitalWrite(6, true);
digitalWrite(7, true);
delay(200);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(200);
digitalWrite(5, true);
digitalWrite(6, true);
digitalWrite(7, true);
delay(200);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(200);
animatedChanging = true;
}
} else {
if (!all && !animatedChanging) {
digitalWrite(5, true);
digitalWrite(6, true);
digitalWrite(7, true);
delay(200);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(200);
digitalWrite(5, true);
digitalWrite(6, true);
digitalWrite(7, true);
delay(200);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(200);
animatedChanging = true;
}
}
}
delay(30);
return;
}
Serial.println(changing);
if (all || changing) {
return;
}
currentTime = millis();
if (won) {
openAnimation();
}
if (digitalRead(2) != buttonA) {
buttonA = !buttonA;
if (buttonA) {
countA++;
if (countA > 9) {
countA = 0;
}
}
delay(10);
}
if (digitalRead(3) != buttonB) {
buttonB = !buttonB;
if (buttonB) {
countB++;
if (countB > 9) {
countB = 0;
}
}
delay(10);
}
if (digitalRead(4) != buttonC) {
buttonC = !buttonC;
if (buttonC) {
countC++;
if (countC > 9) {
countC = 0;
}
}
delay(10);
}
if (countA > 0) {
int loop_dur = 500 / countA;
if (currentTime - previousATime >= loop_dur) {
previousATime = currentTime;
if (countA == 1) {
ledA_On = tick_On;
} else {
ledA_On = !ledA_On;
}
}
} else {
ledA_On = false;
}
if (countB > 0) {
int loop_dur = 500 / countB;
if (currentTime - previousBTime >= loop_dur) {
previousBTime = currentTime;
if (countB == 1) {
ledB_On = tick_On;
} else {
ledB_On = !ledB_On;
}
}
} else {
ledB_On = false;
}
if (countC > 0) {
int loop_dur = 500 / countC;
if (currentTime - previousCTime >= loop_dur) {
previousCTime = currentTime;
if (countC == 1) {
ledC_On = tick_On;
} else {
ledC_On = !ledC_On;
}
}
} else {
ledC_On = false;
}
if (currentTime - currentTick >= 1000) {
currentTick = currentTime;
previousATime = currentTick;
previousBTime = currentTick;
previousCTime = currentTick;
tick_On = !tick_On;
}
digitalWrite(5, ledA_On);
digitalWrite(6, ledB_On);
digitalWrite(7, ledC_On);
if (countA == 2 && countB == 0 && countC == 8){
won = true;
}
}
void openAnimation() {
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(200);
digitalWrite(5, true);
digitalWrite(6, true);
digitalWrite(7, true);
delay(200);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(200);
digitalWrite(5, true);
digitalWrite(6, true);
digitalWrite(7, true);
delay(600);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, false);
delay(100);
for (int i = 0; i < 5; i++){
digitalWrite(5, true);
digitalWrite(6, false);
digitalWrite(7, false);
delay(100);
digitalWrite(5, false);
digitalWrite(6, true);
digitalWrite(7, false);
delay(100);
digitalWrite(5, false);
digitalWrite(6, false);
digitalWrite(7, true);
delay(100);
digitalWrite(5, false);
digitalWrite(6, true);
digitalWrite(7, false);
delay(100);
}
won = false;
countA = 0;
countB = 0;
countC = 0;
}
What I didn't
-
Synchronize all the lights. It wasn't too challenging to sync all three LEDs when they were blinking once per second, but I haven't figured out a general solution that works across all digits.
-
Custom lock code. Working with continuous signals from buttons is not something I'm used to, nor is working with such a limited UI/UX interface. My plan was to allow a user to toggle a "Set" mode by press all buttons at once, assign each digit, and press all buttons at once again to set the lock.
Reflection
I'm unsure if I'll continue this project much further. A big question remains: "What do I want to do?" I'm not sure exactly what pickes my interest for interface labs. I wanted to explore playing with water and sound synthesis, but now these ideas feel too big for my current pace of learning. I'm wondering whether that fear is wisdom trying to tell me to scale back and keep things simpler, or if it's something to overcome and allow myself to pursue what really interests me.