My current code modifications:
void setup() {
pinMode(CLOCK, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(COLON, OUTPUT);
digitalWrite(COLON, LOW);
pinMode(LED_PM, OUTPUT);
pinMode(LED_ALARM, OUTPUT);
pinMode(LED_TOP, OUTPUT);
pinMode(LED_DET, OUTPUT);
pinMode(BUZZER, OUTPUT);
pinMode(TRIGGER, OUTPUT);
pinMode(HOUR_BUTTON_PIN, INPUT);
pinMode(MIN_BUTTON_PIN, INPUT);
pinMode(ALARM_BUTTON_PIN, INPUT);
pinMode(DET_BUTTON_PIN, INPUT);
pinMode(WIRE_1, INPUT);
pinMode(WIRE_2, INPUT);
pinMode(WIRE_3, INPUT);
pinMode(WIRE_4, INPUT);
digitalWrite(HOUR_BUTTON_PIN, HIGH);
digitalWrite(MIN_BUTTON_PIN, HIGH);
digitalWrite(ALARM_BUTTON_PIN, HIGH);
digitalWrite(DET_BUTTON_PIN, HIGH);
digitalWrite(WIRE_1, HIGH);
digitalWrite(WIRE_2, HIGH);
digitalWrite(WIRE_3, HIGH);
digitalWrite(WIRE_4, HIGH);
if (EEPROMValid() && (!((buttonPressed(HOUR_BUTTON)) && (buttonPressed(MIN_BUTTON))))) {
defaultCountdownSeconds = EEPROM.read(10);
defaultCountdownSeconds = defaultCountdownSeconds << 8;
defaultCountdownSeconds |= EEPROM.read(11);
if (defaultCountdownSeconds > 5999) {
defaultCountdownSeconds = DEFAULT_COUNTDOWN_DURATION;
}
} else {
defaultCountdownSeconds = DEFAULT_COUNTDOWN_DURATION;
}
TIMSK2 &= ~(1 << TOIE2);
TCCR2A &= ~((1 << WGM21) | (1 << WGM20));
TCCR2B &= ~(1 << WGM22);
ASSR &= ~(1 << AS2);
TIMSK2 &= ~(1 << OCIE2A);
TCCR2B |= (1 << CS22);
TCCR2B &= ~(1 << CS21);
TCCR2B |= (1 << CS20);
TCNT2 = 0;
TIMSK2 |= (1 << TOIE2);
TIMSK1 &= ~(1 << TOIE1);
TCCR1A = 0;
TCCR1B = (1 << CS12) | (1 << CS10);
TIMSK1 |= (1 << TOIE1);
TCNT1 = TIMER1_SECOND_START;
if (buttonPressed(DET_BUTTON)) {
beep(3500, 50);
silent = false;
digitalWrite(LED_TOP, LOW);
digitalWrite(LED_DET, LOW);
while (buttonPressed(DET_BUTTON));
}
}
void loop() {
delay(10);
if (buttonPressedNew(DET_BUTTON)) {
if ((displayZeros) || (isDefused)) {
isDefused = false;
displayZeros = false;
displayCountdown = false;
return;
}
detPressed = true;
digitalWrite(LED_TOP, LOW);
digitalWrite(LED_DET, LOW);
countdownSeconds = defaultCountdownSeconds;
displayCountdown = true;
}
if (!buttonPressed(DET_BUTTON)) {
if (detPressed) {
detPressed = false;
defaultCountdownSeconds = countdownSeconds;
writeEEPROM();
countdown();
}
}
}
void countdown() {
int ledCounter = 0;
int ledCounterThreshold = 100000;
byte ledCurrentState = HIGH;
byte defusePin;
byte detPin;
byte speedUpPin;
byte pausePin;
boolean defused = false;
countdownRunning = true;
int fractionalSecond;
defusePin = random(WIRE_1, (WIRE_4 + 1));
speedUpPin = random(WIRE_1, (WIRE_4 + 1));
pausePin = random(WIRE_1, (WIRE_4 + 1));
detPin = defusePin;
while (detPin == defusePin) {
detPin = random(WIRE_1, (WIRE_4 + 1));
}
digitalWrite(LED_PM, LOW);
// Keep track of how far we are into the current second so we can correct later.
fractionalSecond = TCNT1 - TIMER1_SECOND_START;
// Reset back to the last second boundary so we can start the countdown immediately and so that the first second isn't truncated
TCNT1 = TIMER1_SECOND_START;
beep(3800, 30);
digitalWrite(LED_DET, ledCurrentState);
while ((countdownSeconds > 0) && (!defused)) {
for (int i = 0; i < 10000; i++) {
if (digitalRead(detPin) == HIGH) {
countdownSeconds = 0;
break;
}
if (digitalRead(defusePin) == HIGH) {
defused = true;
break;
}
if (digitalRead(speedUpPin) == HIGH) {
ledCounterThreshold == 400000;
break;
}
if (digitalRead(pausePin) == HIGH) {
delay(100);
}
}
delay(20);
if (ledCounter++ > ledCounterThreshold) {
ledCounter = 0;
if (ledCurrentState == HIGH) {
ledCurrentState = LOW;
} else {
ledCurrentState = HIGH;
}
digitalWrite(LED_DET, ledCurrentState);
}
}
digitalWrite(LED_DET, LOW);
countdownRunning = false;
if (!defused) {
detonate();
} else {
beep(4500, 80);
isDefused = true;
digitalWrite(LED_TOP, HIGH);
while (!((buttonPressed(HOUR_BUTTON)) || (buttonPressed(MIN_BUTTON))))
}
// Now to keep the time accurate, add back in the fractional second that we took off when we started the countdown sequence.
// Wait until we can add it back to TCNT1 without overflowing.
while (TCNT1 >= (65535 - fractionalSecond));
TCNT1 += fractionalSecond;
}
void detonate() {
for (int i = 0; i < 8; i++) {
digitalWrite(LED_DET, HIGH);
beep(5000, 50, false);
delay(25);
digitalWrite(LED_DET, LOW);
delay(25);
}
unsigned long triggerStart = millis();
unsigned long triggerStop = triggerStart + TRIGGER_DURATION_MS;
digitalWrite(TRIGGER, HIGH);
for (int i = 0; i < 50; i++) {
if (millis() >= triggerStop) {
digitalWrite(TRIGGER, LOW);
}
digitalWrite(random(LED_PM, LED_DET + 1), HIGH);
digitalWrite(random(LED_PM, LED_DET + 1), HIGH);
for (int j = 0; j < 5; j++) {
beep(random(100, 300), 10);
}
for (int led = LED_PM; led <= LED_DET; led++) {
digitalWrite(led, LOW);
}
}
displayCountdown = false;
blank = false;
digitalWrite(LED_DET, HIGH);
while (millis() < triggerStop) {
if (buttonPressedNew(DET_BUTTON)) {
displayZeros = true;
break;
}
}
digitalWrite(TRIGGER, LOW);
while (!((buttonPressed(HOUR_BUTTON)) || (buttonPressed(MIN_BUTTON)))) { }
}
boolean buttonPressed(byte button) {
if (digitalRead(buttonPins[button]) == LOW) {
if (buttonState[button] == HIGH) {
buttonChange[button] = millis();
buttonState[button] = LOW;
}
return true;
} else {
if (buttonState[button] == LOW) {
buttonChange[button] = millis();
buttonState[button] = HIGH;
}
return false;
}
}
boolean buttonPressedNew(byte button) {
if (digitalRead(buttonPins[button]) == LOW) {
if (buttonState[button] == HIGH) {
buttonChange[button] = millis();
buttonState[button] = LOW;
return true;
}
return false;
} else {
if (buttonState[button] == LOW) {
buttonChange[button] = millis();
buttonState[button] = HIGH;
}
return false;
}
}
void beep(int frequency, int duration) {
beep(frequency, duration, true);
}
void beep(int frequency, int duration, boolean disableDisplayInterrupt) {
int us = 1000000 / frequency / 2;
int loopCount = (duration * ((float)frequency / 1000.0));
if (disableDisplayInterrupt) {
TIMSK2 &= ~(1 << TOIE2);
}
for (int i = 0; i < loopCount; i++) {
if (!silent) PORTB |= (1 << 3);
delayMicroseconds(us);
if (!silent) PORTB &= ~(1 << 3);
delayMicroseconds(us);
}
TIMSK2 |= (1 << TOIE2);
}
// This is the display interrupt to implement multiplexing of the digits.
ISR(TIMER2_OVF_vect) {
byte nDigits = 4;
byte data;
byte digitValue;
byte displayHours, displayMinutes;
TCNT2 = 0;
displayHours = countdownSeconds / 60;
displayMinutes = countdownSeconds % 60;
if (displayCountdown) {
displayHours = countdownSeconds / 60;
displayMinutes = countdownSeconds % 60;
}
if (displayZeros) {
displayHours = 0;
displayMinutes = 0;
}
if (++currentDigit > (nDigits - 1)) {
currentDigit = 0;
}
switch (currentDigit) {
case 0:
digitValue = displayMinutes % 10;
break;
case 1:
digitValue = displayMinutes / 10;
break;
case 2:
digitValue = displayHours % 10;
break;
case 3:
digitValue = displayHours / 10;
break;
}
data = (digitValue << 4);
data |= 0x0F;
if (!blank) {
data &= ~(1 << currentDigit);
}
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, data);
digitalWrite(LATCH, HIGH);
}
// Timer 1 interrupt. This executes every second.
ISR(TIMER1_OVF_vect) {
TCNT1 = TIMER1_SECOND_START;
ticked = true;
seconds++;
if (seconds == 60) {
seconds = 0;
minutes++;
if (minutes == 60) {
minutes = 0;
hours++;
}
}
if ((countdownRunning) && (countdownSeconds > 0)) {
beep(3800, 30);
countdownSeconds--;
}
}