Guest User

Noootropic Defusable Clock Code - Modified By TDG_BullDog

a guest
May 20th, 2016
124
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. Defusable Clock Firmware
  3. Copyright (C) 2011 nootropic design, LLC
  4. All rights reserved.
  5.  
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10.  
  11. To increase countdown time, hold the red DET button then press HOUR
  12. and MIN buttons to increase minutes and seconds before releasing
  13. the DET button.
  14.  
  15. To decrease countdown time, hold the red DET button and the ALARM
  16. button, then press HOUR and MIN buttons to decrease minutes and seconds.
  17.  
  18. If the countdown duration is changed, it will be remembered next time
  19. the device is powered on.
  20.  
  21. At detonation, trigger goes HIGH for 3 seconds. To change trigger duration,
  22. change TRIGGER_DURATION_MS.
  23.  
  24. */
  25.  
  26. #include <EEPROM.h>
  27.  
  28. #define CLOCK 2
  29. #define LATCH 3
  30.  
  31.  
  32. #define DATA 4
  33. #define COLON 13
  34. #define MIN_BUTTON 0
  35. #define HOUR_BUTTON 1
  36. #define DET_BUTTON 2
  37. #define ALARM_BUTTON 3
  38. #define MIN_BUTTON_PIN 9
  39. #define HOUR_BUTTON_PIN 10
  40. #define DET_BUTTON_PIN 12
  41. #define ALARM_BUTTON_PIN 15
  42. #define LED_PM 16
  43. #define LED_ALARM 17
  44. #define LED_TOP 18
  45. #define LED_DET 19
  46. #define BUZZER 11
  47. #define TRIGGER 14
  48. #define WIRE_1 5
  49. #define WIRE_2 6
  50. #define WIRE_3 7
  51. #define WIRE_4 8
  52. #define TIMER1_SECOND_START 49910
  53. #define DEFAULT_COUNTDOWN_DURATION 10
  54. #define TRIGGER_DURATION_MS 3000
  55. #define ALARM_OFF 0
  56. #define ALARM_ON 1
  57. #define ALARM_DET 2
  58. #define EEPROM_MAGIC_NUMBER 0xbad0
  59.  
  60. volatile byte hours = 12;
  61. volatile byte minutes = 0;
  62. volatile byte seconds = 0;
  63. volatile boolean pm = false;
  64. volatile unsigned int countdownDuration = DEFAULT_COUNTDOWN_DURATION;
  65. volatile unsigned int countdownSeconds = DEFAULT_COUNTDOWN_DURATION;
  66. unsigned int defaultCountdownSeconds;
  67. unsigned int compareSeconds;
  68. boolean detPressed = false;
  69. boolean displayZeros = false;
  70. volatile boolean ticked = false;
  71. boolean displayCountdown = false;
  72. boolean countdownRunning = false;
  73. boolean isDefused = false;
  74. boolean silent = false;
  75. boolean LEDTESTON = false;
  76.  
  77. //Default Game Mode 1: Pin1 = Disarm, Pin3 = Det
  78. //Game Mode 2: Random Disarm/Det
  79. unsigned int gameMode = 1;
  80.  
  81. byte buttonPins[4] = {MIN_BUTTON_PIN, HOUR_BUTTON_PIN, DET_BUTTON_PIN, ALARM_BUTTON_PIN};
  82. byte buttonState[4] = {HIGH, HIGH, HIGH, HIGH};
  83. unsigned long buttonChange[4] = {0L, 0L, 0L, 0L};
  84.  
  85. byte alarmMode = ALARM_OFF;
  86. volatile boolean alarmRinging = false;
  87. ////boolean displayAlarmTime = false;
  88. // Set to true if you want the PM LED on during PM hours.  I think it's too bright and
  89. // annoying, so I'm setting this to false by default.
  90. ////boolean usePMIndicator = false;
  91.  
  92. boolean blank = false;
  93.  
  94. volatile byte currentDigit = 0;
  95.  
  96. void setup() {
  97.  
  98.     pinMode(CLOCK, OUTPUT);
  99.     pinMode(LATCH, OUTPUT);
  100.     pinMode(DATA, OUTPUT);
  101.     pinMode(COLON, OUTPUT);
  102.     digitalWrite(COLON, LOW);
  103.  
  104.     pinMode(LED_PM, OUTPUT);
  105.     pinMode(LED_ALARM, OUTPUT);
  106.     pinMode(LED_TOP, OUTPUT);
  107.     pinMode(LED_DET, OUTPUT);
  108.     pinMode(BUZZER, OUTPUT);
  109.     pinMode(TRIGGER, OUTPUT);
  110.  
  111.     pinMode(HOUR_BUTTON_PIN, INPUT);
  112.     pinMode(MIN_BUTTON_PIN, INPUT);
  113.     pinMode(ALARM_BUTTON_PIN, INPUT);
  114.     pinMode(DET_BUTTON_PIN, INPUT);
  115.     pinMode(WIRE_1, INPUT);
  116.     pinMode(WIRE_2, INPUT);
  117.     pinMode(WIRE_3, INPUT);
  118.     pinMode(WIRE_4, INPUT);
  119.  
  120.     digitalWrite(HOUR_BUTTON_PIN, HIGH);
  121.     digitalWrite(MIN_BUTTON_PIN, HIGH);
  122.     digitalWrite(ALARM_BUTTON_PIN, HIGH);
  123.     digitalWrite(DET_BUTTON_PIN, HIGH);
  124.     digitalWrite(WIRE_1, HIGH);
  125.     digitalWrite(WIRE_2, HIGH);
  126.     digitalWrite(WIRE_3, HIGH);
  127.     digitalWrite(WIRE_4, HIGH);
  128.  
  129.     // Read data from EEPROM
  130.     // User can hold HOUR and MIN buttons to skip EEPROM read (factory reset procedure).
  131.     if (EEPROMValid() && (!((buttonPressed(HOUR_BUTTON)) && (buttonPressed(MIN_BUTTON))))) {
  132.         hours = EEPROM.read(2);
  133.         minutes = EEPROM.read(3);
  134.         seconds = EEPROM.read(4);
  135.         pm = EEPROM.read(5);
  136.         ////alarmHours = EEPROM.read(6);
  137.         ////alarmMinutes = EEPROM.read(7);
  138.         ////alarmpm = EEPROM.read(8);
  139.         alarmMode = EEPROM.read(9);
  140.         defaultCountdownSeconds = EEPROM.read(10);
  141.         defaultCountdownSeconds = defaultCountdownSeconds << 8;
  142.         defaultCountdownSeconds |= EEPROM.read(11);
  143.         if (defaultCountdownSeconds > 5999) {
  144.             // guard against bad data
  145.             defaultCountdownSeconds = DEFAULT_COUNTDOWN_DURATION;
  146.         }
  147.     } else {
  148.         hours = 12;
  149.         minutes = 0;
  150.         seconds = 0;
  151.         ////alarmHours = 12;
  152.         ////alarmMinutes = 0;
  153.         pm = false;
  154.         ////alarmpm = false;
  155.         alarmMode = ALARM_OFF;
  156.         defaultCountdownSeconds = DEFAULT_COUNTDOWN_DURATION;
  157.         writeEEPROM();
  158.     }
  159.  
  160.     // Initialize timers.
  161.     // Timer1 is used to keep the clock time
  162.     // Timer2 is used for the display multiplexing
  163.  
  164.     // Disable the timer overflow interrupt
  165.     TIMSK2 &= ~(1 << TOIE2);
  166.  
  167.     // Set timer2 to normal mode
  168.     TCCR2A &= ~((1 << WGM21) | (1 << WGM20));
  169.     TCCR2B &= ~(1 << WGM22);
  170.  
  171.     // Use internal I/O clock
  172.     ASSR &= ~(1 << AS2);
  173.  
  174.     // Disable compare match interrupt
  175.     TIMSK2 &= ~(1 << OCIE2A);
  176.  
  177.     // Prescalar is clock divided by 128
  178.     TCCR2B |= (1 << CS22);
  179.     TCCR2B &= ~(1 << CS21);
  180.     TCCR2B |= (1 << CS20);
  181.  
  182.     // Start the counting at 0
  183.     TCNT2 = 0;
  184.  
  185.     // Enable the timer2 overflow interrupt
  186.     TIMSK2 |= (1 << TOIE2);
  187.  
  188.     // init timer1
  189.     // set prescaler to 1024
  190.     TIMSK1 &= ~(1 << TOIE1);
  191.     TCCR1A = 0;
  192.     TCCR1B = (1 << CS12) | (1 << CS10);
  193.     TIMSK1 |= (1 << TOIE1);
  194.     // With prescalar of 1024, TCNT1 increments 15,625 times per second
  195.     // 65535 - 15625 = 49910
  196.     TCNT1 = TIMER1_SECOND_START;
  197.  
  198.     randomSeed(analogRead(0));
  199.  
  200.     if (buttonPressed(DET_BUTTON)) {
  201.         // enable silent mode for testing
  202.         beep(3500, 50);
  203.         silent = true;
  204.         while (buttonPressed(DET_BUTTON)); // wait for release
  205.     }
  206.  
  207.     while ((buttonPressed(HOUR_BUTTON)) || (buttonPressed(MIN_BUTTON))); // wait for release of factory reset procedure
  208.  
  209. }
  210.  
  211. void loop() {
  212.  
  213.     delay(10); // this helps with button debouncing
  214.  
  215.     if (ticked) {
  216.         ticked = false;
  217.         writeEEPROM();
  218.     }
  219.  
  220.     if (alarmRinging) {
  221.         ////if (alarmMode == ALARM_ON) {
  222.         ////  ringAlarm();
  223.         ////}
  224.         if (alarmMode == ALARM_DET) {
  225.             for (int i = 0; i < 4; i++) {
  226.                 beep(3900, 250, false);
  227.                 delay(250);
  228.             }
  229.             displayCountdown = true;
  230.             countdownSeconds = defaultCountdownSeconds;
  231.             countdown();
  232.             alarmRinging = false;
  233.         }
  234.     }
  235.  
  236.     //When the Alarm button is hit, change the game mode. Indicate the game mode by number of beeps
  237.     if (buttonPressedNew(ALARM_BUTTON) && !buttonPressed(DET_BUTTON))
  238.     {
  239.         if(gameMode == 1)
  240.         {
  241.             for (int i = 0; i < 2; i++) {
  242.                 beep(3900, 100, false);
  243.                 digitalWrite(LED_ALARM, HIGH);
  244.                 delay(30);
  245.                 digitalWrite(LED_ALARM, LOW);
  246.                 delay(400);
  247.             }
  248.             gameMode = 2;
  249.         }
  250.         else if(gameMode == 2)
  251.         {
  252.             for (int i = 0; i < 3; i++) {
  253.                 beep(3900, 100, false);
  254.                 digitalWrite(LED_ALARM, HIGH);
  255.                 delay(30);
  256.                 digitalWrite(LED_ALARM, LOW);
  257.                 delay(400);
  258.             }
  259.             gameMode = 3;
  260.         }
  261.         else if (gameMode == 3)
  262.         {
  263.             beep(3900, 100, false);
  264.             digitalWrite(LED_ALARM, HIGH);
  265.             delay(30);
  266.             digitalWrite(LED_ALARM, LOW);
  267.             gameMode = 1;
  268.         }
  269.     }
  270.  
  271.     if (buttonPressedNew(HOUR_BUTTON) || buttonHeld(HOUR_BUTTON, 150)) {
  272.         if (!displayCountdown) {
  273.             hours++;
  274.             if (hours == 12) {
  275.                 pm = !pm;
  276.             }
  277.             if (hours == 13) {
  278.                 hours = 1;
  279.             }
  280.             if (pm) {
  281.                 digitalWrite(LED_PM, HIGH);
  282.             } else {
  283.                 digitalWrite(LED_PM, LOW);
  284.             }
  285.         }
  286.  
  287.         if (displayCountdown) {
  288.             if (!buttonPressed(ALARM_BUTTON)) {
  289.                 if (countdownSeconds < 5940) {
  290.                     countdownSeconds += 60;
  291.                     countdownDuration += 60;
  292.                 }
  293.             } else {
  294.                 if (countdownSeconds >= 60 ) {
  295.                     countdownSeconds -= 60;
  296.                     countdownDuration -= 60;
  297.                 }
  298.             }
  299.         }
  300.     }
  301.  
  302.     if (buttonPressedNew(MIN_BUTTON) || buttonHeld(MIN_BUTTON, 150)) {
  303.         if (!displayCountdown) {
  304.             minutes++;
  305.             if (minutes == 60) {
  306.                 minutes = 0;
  307.             }
  308.             seconds = 0;
  309.             TCNT1 = TIMER1_SECOND_START;
  310.         }
  311.  
  312.         if (displayCountdown) {
  313.             if (!buttonPressed(ALARM_BUTTON)) {
  314.                 if (countdownSeconds < 5999) {
  315.                     countdownSeconds++;
  316.                     countdownDuration++;
  317.                 }
  318.             } else {
  319.                 if (countdownSeconds > 0) {
  320.                     countdownSeconds--;
  321.                     countdownDuration--;
  322.                 }
  323.             }
  324.         }
  325.     }
  326.  
  327.     if (buttonPressedNew(DET_BUTTON)) {
  328.         if ((displayZeros) || (isDefused)) {
  329.             isDefused = false;
  330.             displayZeros = false;
  331.             displayCountdown = false;
  332.             return;
  333.         }
  334.         // The DET button has been pressed but not released yet.
  335.         detPressed = true;
  336.         countdownSeconds = defaultCountdownSeconds;
  337.         displayCountdown = true;
  338.     }
  339.  
  340.     if (!buttonPressed(DET_BUTTON)) {
  341.         if (detPressed) {
  342.             detPressed = false;
  343.  
  344.             //Checking to see if the game time has been updated
  345.             compareSeconds = defaultCountdownSeconds;
  346.             defaultCountdownSeconds = countdownSeconds;
  347.             writeEEPROM();
  348.  
  349.             if(countdownSeconds == compareSeconds)
  350.             {
  351.                 countdown();
  352.             }
  353.         }
  354.     }
  355.  
  356. }
  357.  
  358. void countdown() {
  359.     int ledCounter = 0;
  360.     int ledCounterThreshold = 100000;
  361.     byte ledCurrentState = HIGH;
  362.     byte defusePin;
  363.     byte defusePin2;
  364.     byte defusePin3;
  365.     byte detPin;
  366.     byte DetState;
  367.     boolean defused = false;
  368.     countdownRunning = true;
  369.     int fractionalSecond;
  370.  
  371.     //GAME MODE OPTIONS
  372.     if(gameMode == 1){
  373.         // GameMode 1: Assign static defuse pins
  374.         defusePin = WIRE_1;
  375.         detPin = WIRE_3;
  376.     }
  377.     else if(gameMode == 2){
  378.         // GameMode 2: Assign random pins
  379.         defusePin = random(WIRE_1, (WIRE_4+1));
  380.         detPin = defusePin;
  381.         while (detPin == defusePin) {
  382.             detPin = random(WIRE_1, (WIRE_4+1));
  383.         }
  384.     }
  385.     else if (gameMode == 3)
  386.     {
  387.         defusePin = WIRE_2;
  388.         defusePin2 = WIRE_4;
  389.         defusePin3 = WIRE_3;
  390.         detPin = WIRE_1;
  391.  
  392.         DetState = 0;
  393.     }
  394.  
  395.     digitalWrite(LED_PM, LOW); // turn off the PM LED
  396.  
  397.     // Keep track of how far we are into the current
  398.     // second so we can correct later.
  399.     fractionalSecond = TCNT1 - TIMER1_SECOND_START;
  400.  
  401.     // Reset back to the last second boundary so we can start the countdown
  402.     // immediately and so that the first second isn't truncated
  403.     TCNT1 = TIMER1_SECOND_START;
  404.  
  405.     beep(3800, 30);
  406.     digitalWrite(LED_DET, ledCurrentState);
  407.  
  408.     if (gameMode != 3)
  409.     {
  410.         //Loop for single wire defusal
  411.         while ((countdownSeconds > 0) && (!defused)) {
  412.             for (int i = 0; i < 10000; i++) {
  413.                 // get input
  414.                 if (digitalRead(detPin) == HIGH) {
  415.                     countdownSeconds = 0;
  416.                     break;
  417.                 }
  418.                 if (digitalRead(defusePin) == HIGH) {
  419.                     defused = true;
  420.                     break;
  421.                 }
  422.             }
  423.             delay(20);
  424.             if (ledCounter++ > ledCounterThreshold) {
  425.                 ledCounter = 0;
  426.                 if (ledCurrentState == HIGH) {
  427.                     ledCurrentState = LOW;
  428.                 } else {
  429.                     ledCurrentState = HIGH;
  430.                 }
  431.                 digitalWrite(LED_DET, ledCurrentState);
  432.             }
  433.         }
  434.     }
  435.     else
  436.     {
  437.         //Loop for sequence defusal
  438.         while ((countdownSeconds > 0) && (!defused))  {
  439.             for(int i=0;i<10000;i++) {
  440.                 if (digitalRead(detPin) == HIGH) {
  441.                     countdownSeconds = 0;
  442.                     break;
  443.                 }
  444.                 // old stuff commented ;-)
  445.                 /*if (digitalRead(defusePin) == HIGH) {
  446.                 defused = true;
  447.                 break;
  448.                 }*/
  449.                 //enters the sequence:
  450.                 if ((digitalRead(defusePin) == HIGH) && (DetState == 0))
  451.                 {
  452.                     DetState++;
  453.                     beep(4200, 30); //just a noise for comfirmation :)
  454.                 }
  455.                 if ((digitalRead(defusePin2) == HIGH) && (DetState < 1))
  456.                 {
  457.                     countdownSeconds = 0;
  458.                 }
  459.                 else if ((digitalRead(defusePin2) == HIGH) && (DetState == 1))
  460.                 {
  461.                     DetState++;
  462.                     beep(4200, 30);
  463.                 }
  464.                 if ((digitalRead(defusePin3) == HIGH) && (DetState < 2))
  465.                 {
  466.                     countdownSeconds = 0;
  467.                 }
  468.                 else if ((digitalRead(defusePin3) == HIGH) && (DetState == 2))
  469.                 {
  470.                     defused = true;
  471.                 }
  472.             }
  473.         }
  474.     }
  475.  
  476.     digitalWrite(LED_DET, LOW);
  477.     countdownRunning = false;
  478.     if (!defused) {
  479.         detonate();
  480.     } else {
  481.         beep(4500, 80);
  482.         isDefused = true;
  483.         delay(2000);
  484.     }
  485.  
  486.     // Now to keep the time accurate, add back in the fractional
  487.     // second that we took off when we started the countdown sequence.
  488.     // Wait until we can add it back to TCNT1 without overflowing.
  489.     while (TCNT1 >= (65535 - fractionalSecond));
  490.     TCNT1 += fractionalSecond;
  491. }
  492.  
  493. void detonate() {
  494.     for (int i = 0; i < 8; i++) {
  495.         digitalWrite(LED_DET, HIGH);
  496.         beep(5000, 50, false);
  497.         delay(25);
  498.         digitalWrite(LED_DET, LOW);
  499.         delay(25);
  500.     }
  501.  
  502.     blank = true;
  503.  
  504.     unsigned long triggerStart = millis();
  505.     unsigned long triggerStop = triggerStart + TRIGGER_DURATION_MS;
  506.     digitalWrite(TRIGGER, HIGH);
  507.  
  508.     for (int i = 0; i < 50; i++) {
  509.         if (millis() >= triggerStop) {
  510.             digitalWrite(TRIGGER, LOW);
  511.         }
  512.         digitalWrite(random(LED_PM, LED_DET + 1), HIGH);
  513.         digitalWrite(random(LED_PM, LED_DET + 1), HIGH);
  514.         for (int j = 0; j < 5; j++) {
  515.             beep(random(100, 300), 10);
  516.         }
  517.         for (int led = LED_PM; led <= LED_DET; led++) {
  518.             digitalWrite(led, LOW);
  519.         }
  520.     }
  521.  
  522.     displayCountdown = false;
  523.     blank = false;
  524.     displayZeros = true;
  525.  
  526.     while (millis() < triggerStop) {
  527.         if (buttonPressedNew(DET_BUTTON)) {
  528.             displayZeros = false;
  529.             break;
  530.         }
  531.     }
  532.  
  533.     digitalWrite(TRIGGER, LOW);
  534. }
  535.  
  536. // return true if the button is pressed.
  537. boolean buttonPressed(byte button) {
  538.     if (digitalRead(buttonPins[button]) == LOW) {
  539.         // the button is currently pressed
  540.         if (buttonState[button] == HIGH) {
  541.             // if the button was not pressed before, update the state.
  542.             buttonChange[button] = millis();
  543.             buttonState[button] = LOW;
  544.         }
  545.         return true;
  546.     } else {
  547.         // The button is currently not pressed
  548.         if (buttonState[button] == LOW) {
  549.             // if the button was pressed before, update the state.
  550.             buttonChange[button] = millis();
  551.             buttonState[button] = HIGH;
  552.         }
  553.         return false;
  554.     }
  555. }
  556.  
  557. // return true if the button is pressed and it is a new press (not held)
  558. boolean buttonPressedNew(byte button) {
  559.     if (digitalRead(buttonPins[button]) == LOW) {
  560.         // The button is currently pressed
  561.         if (buttonState[button] == HIGH) {
  562.             // This is a new press.
  563.             buttonChange[button] = millis();
  564.             buttonState[button] = LOW;
  565.             return true;
  566.         }
  567.         // This is not a new press.
  568.         return false;
  569.     } else {
  570.         // The button is currently not pressed
  571.         if (buttonState[button] == LOW) {
  572.             buttonChange[button] = millis();
  573.             buttonState[button] = HIGH;
  574.         }
  575.         return false;
  576.     }
  577. }
  578.  
  579. // return true if the button is pressed and has been held for at least n milliseconds
  580. boolean buttonHeld(byte button, int n) {
  581.     if (digitalRead(buttonPins[button]) == LOW) {
  582.         // the button is currently pressed
  583.         if (buttonState[button] == HIGH) {
  584.             // if the button was not pressed before, update the state and return false.
  585.             buttonChange[button] = millis();
  586.             buttonState[button] = LOW;
  587.             return false;
  588.         }
  589.         if ((millis() - buttonChange[button]) >= n) {
  590.             // the button has been pressed for over n milliseconds.
  591.             // update the state change time even though the state hasn't changed.
  592.             // we update the state change time so we can start the counting over
  593.             buttonChange[button] = millis();
  594.             return true;
  595.         }
  596.         // The button is being held, but has not been held for longer than n milliseconds.
  597.         return false;
  598.     } else {
  599.         // The button is currently not pressed
  600.         if (buttonState[button] == LOW) {
  601.             // if the button was pressed before, update the state.
  602.             buttonChange[button] = millis();
  603.             buttonState[button] = HIGH;
  604.         }
  605.         return false;
  606.     }
  607. }
  608.  
  609. void beep(int frequency, int duration) {
  610.     beep(frequency, duration, true);
  611. }
  612.  
  613. void beep(int frequency, int duration, boolean disableDisplayInterrupt) {
  614.     int us = 1000000 / frequency / 2;
  615.     int loopCount = (duration * ((float)frequency / 1000.0));
  616.     if (disableDisplayInterrupt) {
  617.         TIMSK2 &= ~(1 << TOIE2);
  618.     }
  619.     for (int i = 0; i < loopCount; i++) {
  620.         if (!silent) PORTB |= (1 << 3);
  621.         delayMicroseconds(us);
  622.         if (!silent) PORTB &= ~(1 << 3);
  623.         delayMicroseconds(us);
  624.     }
  625.     TIMSK2 |= (1 << TOIE2);
  626. }
  627.  
  628. void writeEEPROM() {
  629.     setEEPROMValid();
  630.     EEPROM.write(2, hours);
  631.     EEPROM.write(3, minutes);
  632.     EEPROM.write(4, seconds);
  633.     EEPROM.write(9, alarmMode);
  634.     EEPROM.write(10, (defaultCountdownSeconds >> 8));
  635.     EEPROM.write(11, (defaultCountdownSeconds & 0xFF));
  636. }
  637.  
  638. boolean EEPROMValid() {
  639.     // determine if the EEPROM has ever been written by this firmware
  640.     // so we can determine if the values can be trusted
  641.     unsigned int magic = EEPROM.read(0);
  642.     magic = magic << 8;
  643.     magic |= EEPROM.read(1);
  644.     return (magic == EEPROM_MAGIC_NUMBER);
  645. }
  646.  
  647. void setEEPROMValid() {
  648.     EEPROM.write(0, EEPROM_MAGIC_NUMBER >> 8);
  649.     EEPROM.write(1, (EEPROM_MAGIC_NUMBER & 0xFF));
  650. }
  651.  
  652. // This is the display interrupt to implement multiplexing of the digits.
  653. ISR(TIMER2_OVF_vect) {
  654.     byte nDigits = 4;
  655.     byte data;
  656.     byte digitValue;
  657.     byte displayHours, displayMinutes;
  658.  
  659.     TCNT2 = 0;
  660.  
  661.     displayHours = hours;
  662.     displayMinutes = minutes;
  663.  
  664.     if (displayCountdown) {
  665.         displayHours = countdownSeconds / 60;
  666.         displayMinutes = countdownSeconds % 60;
  667.     }
  668.     if (displayZeros) {
  669.         displayHours = 0;
  670.         displayMinutes = 0;
  671.     }
  672.  
  673.     if ((displayHours < 10) && (!displayCountdown) && (!displayZeros)) {
  674.         nDigits = 3;
  675.     }
  676.  
  677.  
  678.     if (++currentDigit > (nDigits - 1)) {
  679.         currentDigit = 0;
  680.     }
  681.  
  682.     switch (currentDigit) {
  683.     case 0:
  684.         digitValue = displayMinutes % 10;
  685.         break;
  686.     case 1:
  687.         digitValue = displayMinutes / 10;
  688.         break;
  689.     case 2:
  690.         digitValue = displayHours % 10;
  691.         break;
  692.     case 3:
  693.         digitValue = displayHours / 10;
  694.         break;
  695.     }
  696.  
  697.     // Upper 4 bits of data are the value for the current digit.
  698.     // They are loaded into shift register outputs QA-QD
  699.     data = (digitValue << 4);
  700.  
  701.     // Lower 4 bits 3-0 represent which digit to turn on.
  702.     // 3 is most significant digit, 0 is least
  703.     // They are loaded into shift register outputs QE-QH
  704.     // Digit transistors are active low, so set them all high
  705.     data |= 0x0F;
  706.  
  707.     if (!blank) {
  708.         // now turn off the bit for digit we want illuminated.
  709.         data &= ~(1 << currentDigit);
  710.     }
  711.  
  712.     digitalWrite(LATCH, LOW);
  713.     shiftOut(DATA, CLOCK, LSBFIRST, data);
  714.     digitalWrite(LATCH, HIGH);
  715. }
  716.  
  717. // Timer 1 interrupt.  This executes every second.
  718. ISR(TIMER1_OVF_vect) {
  719.     TCNT1 = TIMER1_SECOND_START;
  720.  
  721.     ticked = true;
  722.     seconds++;
  723.     if (seconds == 60) {
  724.         seconds = 0;
  725.         minutes++;
  726.         if (minutes == 60) {
  727.             minutes = 0;
  728.             hours++;
  729.             if (hours == 12) {
  730.                 pm = !pm;
  731.             }
  732.             if (hours == 13) {
  733.                 hours = 1;
  734.             }
  735.         }
  736.     }
  737.  
  738.     if ((countdownRunning) && (countdownSeconds > 0)) {
  739.         beep(3800, 30);
  740.         countdownSeconds--;
  741.     }
  742. }
RAW Paste Data