Arpit
Published © GPL3+

DIY Hard-to-Snooze Alarm Clock

This 3D-printed alarm clock requires a keypad code to turn off, forcing you fully awake instead of easy snoozing.

IntermediateFull instructions provided15 hours35
DIY Hard-to-Snooze Alarm Clock

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
DS3231 RTC module
×1
I2C 16x2 Arduino LCD Display Module
DFRobot I2C 16x2 Arduino LCD Display Module
×1
4x4 keypad matrix
×1
Active buzzer
×1

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Schematics

CODING SCHEMATICS

Code

Accelerometer_Logic.ino

C/C++
void Accelerometer(){
  //Check Accelerometer Values
    lis.read();                                                                 // get X Y and Z data at once
    sensors_event_t event;
    lis.getEvent(&event);

  //Movement Indicator 
    MovementVal = abs(event.acceleration.x + event.acceleration.y);             // Movement is calculated via X and Y movement since Z is gravity
    if(Alarm_go == true && ContinuousMovement == true){                         // If the alarm is on and moving begin counting movmeent timer
      MovementTimer++;
      LastMovementVal = MovementVal;
      
      if(MovementTimer >= 15){          //10                                    // Once movement timer reaches 20, movement is confirmed
        Movement = true;
      }
         
    }else{
      Movement = false;                                                         // Otherwise it is false
    }
    
  //Checks if the acceleration is changing direction  
    if (abs(MovementVal - LastMovementVal) >= 3  && Alarm_go == true){          // To see if movement is contious the current movementval is compared to the previous movementval
      ContinuousMovement = true;
    }else{
      ContinuousMovement = false;
    }
        
/*/Accelerometer Debugging
  Serial.println("Acceleration Debugging:");
  Serial.print("X: "); 
  Serial.print(event.acceleration.x);
  Serial.print("  Y: "); 
  Serial.print(event.acceleration.y);
  Serial.print("  Z: "); 
  Serial.print(event.acceleration.z);
  Serial.print("  MovementVal: ");
  Serial.print(MovementVal);
  Serial.print("  Movement Y/N: ");
  Serial.print(Movement);
  Serial.print("  Movement Timer: ");
  Serial.print(MovementTimer);
  Serial.print("  Cont. Movement: ");
  Serial.println(ContinuousMovement);
  Serial.println(""); // */ 
  
}

Alarm_Functions.ino

C/C++
//Hour Counter Function
  void Hours(){ 
    Hour_ButtonState = digitalRead(Hour_buttonPin);                 // Grabs input from hour button
    if (Hour_ButtonState != Hour_lastButtonState) {                 // If the button has been pressed
      if (Hour_ButtonState == LOW) {                                // & if the button has been unclicked
        bPress = true;                                              // then a button press has occured making bPress true
        buttonPushCounterHours++;                                   // Adds one number to the hour counter
      } 
      delay(50);
    }                                                 
    Hour_lastButtonState = Hour_ButtonState;                        // Button State is reset
    if (buttonPushCounterHours >= 24){                              // If the counter reaches 24 hours it resets 
      buttonPushCounterHours = 0;                                   // Sets the hours counter to zero
    }
  }

//Minuites Counter Function
  void Minuites(){
    Minuite_ButtonState = digitalRead(Minuite_buttonPin);           // Grabs input from minuite button
    if (Minuite_ButtonState != Minuite_lastButtonState) {           // If the button has been pressed
      if (Minuite_ButtonState == LOW) {                             // & if the button has been unclicked
        bPress = true;                                              // then a button press has occured making bPress true
        buttonPushCounterMinuites = buttonPushCounterMinuites+5;    // Adds five numbers to the minuite counter
      }
      delay(50);
   }
    Minuite_lastButtonState = Minuite_ButtonState;                  // Button State is reset
    if (buttonPushCounterMinuites > 59){                            // Wraps the button counter to zero if minuites goes over 59 minuites
      buttonPushCounterMinuites = buttonPushCounterMinuites - 60;   // Calculates what the minuites counter ought to be
      buttonPushCounterHours++;                                     // Adds an hour to the hour counter 
    }
  }

void ResetMenu(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Current Alarm:");
  lcd.setCursor(3,1);
  lcd.print(" ");
  lcd.setCursor(4,1);
  lcd.print(":");
  if(buttonPushCounterMinuites <=9){
    lcd.setCursor(5,1);
    lcd.print("0");
    lcd.setCursor(6,1);
    lcd.print(buttonPushCounterMinuites);
  }else{
     lcd.setCursor(5,1);
     lcd.print(buttonPushCounterMinuites); 
  }
  if(buttonPushCounterHours >= 10){ 
     lcd.setCursor(2,1);
     lcd.print(buttonPushCounterHours);
  }else{
     lcd.setCursor(2,1);
     lcd.print(" "); 
     lcd.setCursor(3,1);
     lcd.print(buttonPushCounterHours); 
  }
}

void UpdateCounter(){
  if(bPress == true && AlarmDisabled == false && CheckQuestions == false){
    bPress = false;
    lcd.setCursor(3,1);
    lcd.print(" ");
    lcd.setCursor(4,1);
    lcd.print(":");

    if(buttonPushCounterMinuites <=9){
       lcd.setCursor(5,1);
       lcd.print("0");
       lcd.setCursor(6,1);
       lcd.print(buttonPushCounterMinuites);
     }else{
       lcd.setCursor(5,1);
       lcd.print(buttonPushCounterMinuites); 
    }
    
    if(buttonPushCounterHours >= 10){ 
       lcd.setCursor(2,1);
       lcd.print(buttonPushCounterHours);
    }else{
      lcd.setCursor(2,1);
      lcd.print(" "); 
      lcd.setCursor(3,1);
      lcd.print(buttonPushCounterHours); 
    }
  }
}

void AlarmMenu(){
    lcd.setCursor(0,0); 
    lcd.print("Alarm Activated");
    lcd.setCursor(0,1);
    lcd.print("Shake To Snooze");
}


void PrintQuestion(){
// LCD Preperation
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Q: ");
  lcd.setCursor(0,1);
  lcd.print("A: ");

//Question
  lcd.setCursor(3,0);
  lcd.print(x);
  lcd.print(sign1);
  lcd.print(y);
  if(sign2 != 0 && z != 0){
    lcd.print(sign2);
    lcd.print(z);
  }
  lcd.print(" = ?");
  lcd.setCursor(3, 1);

}

void CorrectAnswer(){
  lcd.clear();
  lcd.setCursor(4,0);
  delay(10);
  lcd.print("Correct");
  EqualRow();
  for (int thisNote = 0; thisNote < 8; thisNote++) {
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(8, melody[thisNote], noteDuration);
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    noTone(8);
  }
  AlarmSet = AlarmSet - SnoozeCounter;      // Removes teh extra time added to the alarm by the snooze
  if (AlarmSet < 0){                        // ... And if the new time is less than zero
    AlarmSet = 2400 - AlarmSet;             // Fix the alarm settime by wrapping it back to the maximum time
  }
  o = AlarmSet%10;                          // Seperates the ones place from the AlarmSet time
  t = (AlarmSet/10)%10;                     // Seperates the tens place from the AlarmSet time
  h = (AlarmSet/100)%10;                    // Seperates the hundreds place from the AlarmSet time   
  th = AlarmSet/1000;                       // Seperates the thousands place from the AlarmSet time
  buttonPushCounterHours = (th*10)+h;       // Updates the Alarm hours counter to the AlarmSet hours
  buttonPushCounterMinuites = (t*10)+o;     // Updates the Alarm minuites counter to the AlarmSet minuites
  ResetMenu();                              // Reset the menu 
  CheckQuestions = false;                   // Questions are no longer being answered 

}

void IncorrectAnswer(){
  lcd.clear();
  lcd.setCursor(3,0);
  delay(10);
  lcd.print("Incorrect");
  EqualRow();
  tone(8, NOTE_DS4, 300);
  delay(300);
  tone(8, NOTE_DS3, 400);
  delay(400);
  tone(8, NOTE_CS2, 400);
  delay(300);
  Questions();
}



void EqualRow(){
  lcd.setCursor(0,1);
  lcd.print("=");
  lcd.setCursor(15,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(1,1);
  lcd.print("=");
  lcd.setCursor(14,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(2,1);
  lcd.print("=");
  lcd.setCursor(13,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(3,1);
  lcd.print("=");
  lcd.setCursor(12,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(4,1);
  lcd.print("=");
  lcd.setCursor(11,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(5,1);
  lcd.print("=");
  lcd.setCursor(10,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(6,1);
  lcd.print("=");
  lcd.setCursor(9,1);
  lcd.print("=");
  delay(150);
  lcd.setCursor(7,1);
  lcd.print("=");
  lcd.setCursor(8,1);
  lcd.print("=");
}

Alarm_Logic.ino

C/C++
void Alarm(){

// Set the current time  
  DateTime now = rtc.now();                                               // The Date/Time is what the RTC currently reads
  displaytime = (now.hour() * 100) + now.minute();                        // Takes the hours and minuites and puts it in numarical form
  display.showNumberDecEx(displaytime, 0b11100000, true);                 
  
// Updates Current Alarm
  AlarmSet = (buttonPushCounterHours * 100) + buttonPushCounterMinuites;  // Sets the AlarmSet based on the button counters 
  
// Alarm
  if(AlarmSet == displaytime && SnoozeVal == false){                      // If the Alarmset equals the real time and the snoozeval is not engaged 
    if(AlarmDisabled == false){                                           // & If the alarm is not disabled
      Alarm_go = true;                                                    // The alarm is turned on
      AlarmMenu();                                                        // Inserts the Alarm Menu
      tone(8, NOTE_GS4);                                                  // Plays the Alarm Buzzer        
    }

  }
  
  if(CheckQuestions == true){                                             // If the questions are being answered
    noTone(8);                                                            // Toggles the Alarm Buzzer off
  }
  
      
// Alarm-Master Button. It forces the alarm to go off when pressed. 
  AlarmMaster_ButtonState = digitalRead(AlarmMaster_buttonPin);           // Checks if the Alarm master pin is pushed
  if(AlarmMaster_ButtonState == true || Snooze == true){                  // If the AlarmMaster button is pressed or if the snooze is true
    if(AlarmDisabled == false && CheckQuestions == false){                // & If the alarm is enabled and the questions are not currently on 
      o=displaytime%10;                                                   // Seperates the ones place from the current time
      t=(displaytime/10)%10;                                              // Seperates the tens place from the current time
      h=(displaytime/100)%10;                                             // Seperates the hundreds place from the current time
      th=displaytime/1000;                                                // Seperates the thousands place from the current time
      buttonPushCounterHours = (th*10)+h;                                 // Updates the Alarm hours counter to the current hours
      buttonPushCounterMinuites = (t*10)+o;                               // Updates the Alarm minuites counter to the current minuites
      ResetMenu();                                                        // Reset the current alarm menu
      Snooze = false;                                                     // Turns off the snooze incase it was the thing that activated the alarm
    }

  }

// If the snooze button is pressed 
  AlarmToggle_ButtonState = digitalRead(AlarmToggle_buttonPin);                           // Grabs the output from the Alarmtoggle pin
  if(AlarmToggle_ButtonState == HIGH && Alarm_go == false && CheckQuestions == false){    // If the button is pressed, the alarm isn't on, and the questions are not on
    if(AlarmToggle_ButtonState == AlarmToggle_LastButtonState){                           // & if the button state has changed 
      
      if(AlarmToggleFlipFlop == true){                                    // If the flipflop value is true
        AlarmToggleFlipFlop = false;                                      // ... Swap it to false
      } else {                                                            // Otherwise,
        AlarmToggleFlipFlop = true;                                       // ... Swap it to true
      }
      
      if(AlarmToggleFlipFlop == false){                                   // If the flipflop value is false
        lcd.clear();                                                         
        lcd.setCursor(4,0);
        lcd.print("Alarm is");
        lcd.setCursor(4,1);
        lcd.print("Disabled");
        AlarmDisabled = true;                                             // Disables the ability for the alarm to go off 
         

      }
      
      if(AlarmToggleFlipFlop == true){                                    // If the flipflop value is true
        lcd.clear();  
        lcd.setCursor(1,0);
        lcd.print("Alarm Toggled");
        EqualRow();
        delay(100);
        ResetMenu();                                                     // Resets the menu with the Alarm set counter 
        AlarmDisabled = false;                                           // Re-enables the ability for the alarm to go off 
                
      }
      
      delay(1000);
      AlarmToggle_LastButtonState = AlarmToggle_ButtonState;            // Holds onto the buttonstate to check if the button has been pressed later
      
    }
  
  } 

// Main Snooze - Accelerometer 
  if(Alarm_go == true && Movement == true){                               // If the alarm is on and the alarm is moving
    Alarm_go = false;                                                     // The alarm is turned off
    SnoozeVal = true;                                                     // and snoozebal is engaged 
    CheckQuestions = true;                                                // The questions are currently being answered 
    MovementTimer = 0;                                                    // The movement is reset back to zero                                                         
    Questions();                                                          // Runs the questions function 
  }

// Resets the SnoozeVal so the alarm can repeat on the next cycle        
  if(AlarmSet != displaytime && SnoozeVal == true){                       // If the alarm does not equal the current time and the snoozeval is true
    SnoozeVal = false;                                                    // Snoozeval is false
  }
  
/*/Alarm Debugging
  Serial.println("Alarm Debugging:");
  Serial.print("Alarm Set: ");
  Serial.print(AlarmSet);
  Serial.print("  Time: ");
  Serial.print(displaytime);
  Serial.print("  Alarm On/Off: ");
  Serial.print(Alarm_go);
  Serial.print("  Snooze ButtonState: ");
  Serial.print(Snooze_ButtonState);
  Serial.print("  SnoozeVal: ");
  Serial.print(SnoozeVal);
  Serial.print(" AlarmMaster: ");
  Serial.print(AlarmMaster_ButtonState);
  Serial.print(" Snooze Check: ");
  Serial.print(SnoozeCheck);
  Serial.print(" Snooze: ");
  Serial.print(Snooze);
  Serial.print(" CheckQuestions: ");
  Serial.print(CheckQuestions);
  Serial.print("FlipFlop: ");
  Serial.print(AlarmToggleFlipFlop);
  Serial.print(" ButtonState: ");
  Serial.print(AlarmToggle_ButtonState);
  Serial.print(" LastButtonState: ");
  Serial.println(AlarmToggle_LastButtonState);
  Serial.println("\n"); // */ 
  
//Alarm Master Snooze Debugging
  Serial.print("Alarm Set: ");
  Serial.print(AlarmSet);
  Serial.print("  Time: ");
  Serial.print(displaytime);
  Serial.print(" Thousands: ");
  Serial.print(th);
  Serial.print(" Hundreds: ");
  Serial.print(h);
  Serial.print(" Tens: ");
  Serial.print(t);
  Serial.print(" Ones: ");
  Serial.print(o);
  Serial.print(" Hours: ");
  Serial.print(buttonPushCounterHours);
  Serial.print(" Minuites: ");
  Serial.println(buttonPushCounterMinuites); // */
 
    
}

Answer_Verification.ino

C/C++
void CheckAnswer(){
  if (KeypadValue != '@'){                                                  // If a button has been pressed                                                                
    if (KeypadValue != 'A' && KeypadValue != 'B' &&  KeypadValue != 'C'){   // And if A/B/C haven't been pressed
      CurrentKeyPress = KeypadValue;                                        // The output is CurrentKeypress 
      lcd.print(CurrentKeyPress);                                           // Print the output
      delay(1000);                                                          // Delay
      KeypadValue = '@';                                                    // Reset the button press 
    }
    
    if (KeypadValue == 'B'){                                                // If B has been pressed
      PrintQuestion();                                                      // Displays the question on the LCD
      if(Negative == false){                                                // If negative is false
        Negative = true;                                                    // ... Swap it to true
        lcd.print('-');                                                     // Print a negative sign 
        if(UserResponse > 0){                                               // If there's a response 
          lcd.print(UserResponse);                                          // ... Print it
        }
      } else {                                                              // If negative is true
        Negative = false;                                                   // ... Swap it to false
        if(UserResponse > 0){                                               // If there's a response
          lcd.print(UserResponse);                                          // Print it
        }
       
      }
      
      UpdateNegative();                                                     // Updates the final answer so it has a negative sign   
      delay(1000);                                                          // Delay
      KeypadValue = '@';                                                    // Reset the keypad so it can be pressed again 
    
    }

    if (KeypadValue == 'C'){                                                // If C has been pressed
      UserResponse = 0;                                                     // Resets the response
      ResponseFinal = 0;                                                    // Resets the final response (which is negative is needed)
      Negative = false;                                                     // Resets the negative value
      lcd.clear();                                                          // Clear the LCD
      PrintQuestion();                                                      // Reprint the question
      KeypadValue = '@';                                                    // Reset the button press    
    }

    if (KeypadValue == 'A'){                                                // If A has been pressed
      if (ResponseFinal == Answer){                                         // and if the answer is correct
        CorrectAnswer();                                                    // Display correct animiation & reset alarm 
      }

      if (ResponseFinal != Answer){                                         // If the answer check is inncorect
        IncorrectAnswer();                                                  // Display the inncorrect animation & print a new question 
      }
      KeypadValue = '@';                                                    // Reset the button press 

    }

  }

  if (CurrentKeyPress != '@'){                                              // if there is a new button press response 
    UserResponse = CurrentKeyPress + (UserResponse * 10);                   // Add the button press to the already accumulated button presses 
    CurrentKeyPress = '@';                                                  // Reset the button press 
    ResponseFinal = UserResponse;                                           // Set the final response to the user response 
    UpdateNegative();    

  }
 

  if (CheckQuestions == true){                                              // If the questions are currently being answered 
    SnoozeCheck = AlarmSet + 1;                                             // Make a new var and make it the current alarm plus a minuite
    if (displaytime == SnoozeCheck){                                        // If the display time is equal to the new var
      Snooze = true;                                                        // Snooze is true (runs the alarm again)
      SnoozeCounter++;                                                      // Counts the number of times alarmset is increased 
      SnoozeCheck = SnoozeCheck + 1;                                        // Add another minuite to the var
      CheckQuestions = false;                                               // Questions are not being answered right now
      UserResponse = 0;                                                     // Resets the response
      ResponseFinal = 0;                                                    // Resets the final response (which has negative)
      Negative = false;                                                     // Resets the negative value
    }

  }

}

void UpdateNegative(){                                                      // If the update negative function is initated
  if (Negative == true){                                                    // If negative is true
    ResponseFinal = ResponseFinal * -1;                                     // The final response is equal to itself but negative
  } else {                                                                  // ... Otherwise,
    ResponseFinal = abs(ResponseFinal);                                     // The final response is equal to the absolute value of itself 
  }
  
}

Keypad_Logic.ino

C/C++
void Keypad(){

// Pulls the raw keypad output voltage
  int RawKeypadOutput = analogRead(A0);

/*/ Data Smoothing Code
  if (RawKeypadOutput > 20) {
    total = total - readings[readIndex];              // subtract the last reading
    readings[readIndex] = analogRead(Keypad_Pin);     // read from the sensor
    total = total + readings[readIndex];              // add the reading to the total
    readIndex = readIndex + 1;                        // advance to the next position in the array
    if (readIndex >= numReadings) {                   // if we're at the end of the array...
      readIndex = 0;                                  // ...wrap around to the beginning:
    }
    average = total / numReadings;                    // calculates the average
    
  } else {                                            // if the keypad is not pressed
    average = 0;                                      // the average & total is reset
    total = 0;                                
    for (int thisReading = 0; thisReading < numReadings; thisReading++) {
      readings[thisReading] = 0;
    }
    
  }

// Verifies the button press 
  if (RawKeypadOutput > 30) {
    if (average == RawKeypadOutput + - 1 || average == RawKeypadOutput + - 2 || average == RawKeypadOutput + - 3 || average == RawKeypadOutput) {
      KeypadOutput = average;
    } 

  } */


switch(RawKeypadOutput){ // KeypadOutput if using data filtering 
  
  case 228 ... 243:           // Keypad #1 
    KeypadValue = 1;
    KeypadOutput = 0;
  break;
  
  case 325 ... 331:           //Keypad #2
    KeypadValue = 2;
    KeypadOutput = 0;
  break;
  
  case 472 ... 478:           //Keypad #3 
    KeypadValue = 3;
    KeypadOutput = 0;
  break;

  case 109 ... 119:           //Keypad #4
    KeypadValue = 4;
    KeypadOutput = 0;
  break;

  case 125 ... 130:           //Keypad #5
    KeypadValue = 5;
    KeypadOutput = 0;
  break;

  case 143 ... 150:           //Keypad #6
    KeypadValue = 6;
    KeypadOutput = 0;
  break;

  case 71 ... 75:             //Keypad #7
    KeypadValue = 7;
    KeypadOutput = 0;
  break;

  case 77 ... 83:             //Keypad #8
    KeypadValue = 8;
    KeypadOutput = 0;
  break;

  case 84 ... 90:             //Keypad #9
    KeypadValue = 9;
    KeypadOutput = 0;
  break;

  case 55 ... 61:             //Keypad #0
    KeypadValue = 0;
    KeypadOutput = 0;
  break;

  case 840 ... 915:           //Keypad A
    KeypadValue = 'A';
    KeypadOutput = 0;
  break;

  case 160 ... 175:           //Keypad B
    KeypadValue = 'B';
    KeypadOutput = 0;
  break;

  case 91 ... 101:             //Keypad C
    KeypadValue = 'C';
    KeypadOutput = 0;
  break;

  /*case 65 ... 69:           //Keypad D
    KeypadValue = 'D';
    KeypadOutput = 0;
  break;

  case 52 ... 55:             //Keypad *
    KeypadValue = '*';
    KeypadOutput = 0;
  break;

  case 60 ... 63:             //Keypad #
    KeypadValue = '#';        //Removed
    KeypadOutput = 0;         //Overlap
  break;*/
}

//Keypad Debugging
  Serial.print("Raw KP: ");
  Serial.print(RawKeypadOutput);
  Serial.print(" Average: ");
  Serial.print(average);
  Serial.print(" KP Output: ");
  Serial.print(KeypadOutput); 
  Serial.print(" Final KP: ");
  Serial.print(KeypadValue); 
  Serial.print(" Current Press: ");
  Serial.print(CurrentKeyPress); 
  Serial.print(" Negative: ");
  Serial.print(Negative);
  Serial.print(" Response: ");
  Serial.print(UserResponse); 
  Serial.print(" Final: ");
  Serial.println(ResponseFinal); // */

 
}

Main7.ino

C/C++
//Libraries
  #include <Wire.h>                     // I2C communication Library 
  #include <LiquidCrystal_I2C.h>        // LCD Library
  #include <TM1637Display.h>            // 7-Segment Library 
  #include <RTClib.h>                   // Clock Module Library 
  #include <Adafruit_LIS3DH.h>          // Accelerometer 
  #include <Adafruit_Sensor.h>          // Accelerometer
  #include "pitches.h"                  //Tone Pitches For Buzzer

//Pins 
  #define CLK 2                         // 4 Digit Display
  #define DIO 3                         // 4 Digit Display
  #define Hour_buttonPin 6              // Hour Counter
  #define Minuite_buttonPin 7           // Minuite Counter
  #define AlarmToggle_buttonPin 5       // Snooze 
  #define AlarmMaster_buttonPin 4       // Foces Alarm to go off
  #define Keypad_Pin A0                 // Keypad

  
//LCD Setup
  LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); 

//I2C Setup for Accelerometer
  Adafruit_LIS3DH lis = Adafruit_LIS3DH();

// 7-Segment Display Setup
  TM1637Display display = TM1637Display(CLK, DIO); 
  const uint8_t data[] = {0xff, 0xff, 0xff, 0xff}; 
  const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00}; 
  RTC_DS3231 rtc; 

//Variables 
  int buttonPushCounterHours = 0;       // Hours Counter
  int buttonPushCounterMinuites = 0;    // Minuites Counter
  int Hour_ButtonState = 0;             // current state of the up button
  int Hour_lastButtonState = 0;         // previous state of the up button
  int Minuite_ButtonState = 0;          // current state of the up button
  int Minuite_lastButtonState = 0;      // previous state of the up button
  int AlarmMaster_ButtonState = 0;      // Forcibly turns on the Alarm 
  int AlarmToggle_LastButtonState = 1;  // Registers the button press for the alarm toggle 
  int th,h,t,o;                         // Thousands,hundreds,tens,Ones
  int AlarmSet;                         // The time the alarm will go off 
  int AlarmToggle_ButtonState = 0;      // Alarm toggle state
  int MovementTimer = 0;                // Timer which delays the snooze by holding the movement indicator
  int LastMovementVal;                  // The previous movementval stored to see if there has been a change
  int MovementVal;                      // The absoulte value of x & y axis data from the accelerometer 
  int RawKeypadOutput;                  // The voltage value coming straight from the keypad
  int KeypadOutput;                     // Refined output value from the keypad
  int KeypadValue = '@';                // Holds the keypad character/number output
  int CurrentKeyPress = '@';            // Holds the current keypad press once it has been reset
  long int UserResponse;                // Accumulated Button presses 
  long int ResponseFinal;               // Response that accounts for negative values 
  const int numReadings = 2;            // Number of values in the averaging array
  int readings[numReadings];            // Readings from the keypad
  int readIndex = 0;                    // The index of the current reading
  int total = 0;                        // The running total from the keypad array
  int average = 0;                      // The average from the keypad array
  int QuestionCase;                     // Random number generator for the questions 
  int x;                                // Random Math Question Value
  int y;                                // Random Math Question Value
  int z;                                // Random Math Question Value
  int Answer;                           // Answer to the Alarm Question
  int SnoozeCheck;                      // Its slightly more than the alarm set time to verify question completion 
  int SnoozeCounter;                    // Counts the number of snoozes so it can reset the alarmset value correctly
  int displaytime;                      // Holds the current time 
  char sign1;                           // Math sign in each question
  char sign2;                           // Math sign #2 in each question 
  boolean Negative = false;             // If the button respsonse from the keypad is negative 
  boolean ContinuousMovement = false;   // Checks if the movement is changing directions
  boolean Alarm_go = false;             // Alarm goes brr
  boolean CheckQuestions = false;       // The alarm menu is still in progress 
  boolean bPress = false;               // Hour/Minuite Button press
  boolean SnoozeVal = false;            // Used to see if alarm is toggled
  boolean Movement = false;             // Deturmines if the system has moved
  boolean MasterSupress = false;        // Keeps the SetAlarm value from updating to force the alarm on
  boolean Snooze = false;               // If the question hasn't been answered within a minuite 
  boolean AlarmToggleFlipFlop = true;   // Flip flops the alarm toggle button
  boolean AlarmDisabled = false;        // Suppresses the SnoozeVal update when the alarm is toggled off 
  
//Melody Setup  
  int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
  };
  int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
  };

void setup() {
  
//Begins Serial Communication at a baud rate of 9600
  Serial.begin(9600);                     

//LCD Setup
  lcd.init();                          
  lcd.backlight();                    

// Check if the RTC lost power and if so, set the time:
  if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 
  }
  
//7 Segment Setup
  display.setBrightness(5);
  display.clear();

//Data Smoother initialization 
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
  
//Input setup  
  pinMode( Hour_buttonPin , INPUT_PULLUP);
  pinMode( Minuite_buttonPin , INPUT_PULLUP);
  pinMode( AlarmToggle_buttonPin , INPUT_PULLUP);

//Accelerometer setup
  lis.begin(0x18);

//Preset Alarm (Military Time)
  buttonPushCounterHours = 6; 
  buttonPushCounterMinuites = 45;

//Display the preset alarm:
  ResetMenu();
}

void loop() {

//Runs the clock & Alarm
  Alarm();
       
//Print the alarm time:
  if(Alarm_go != true){
    Minuites();
    Hours();
    UpdateCounter();    
  }


//Accelerometer Data
  Accelerometer();  

//Stuff needed for the question answering process   
  if(CheckQuestions == true){
    Keypad();
    CheckAnswer();
  } 
}

pitches.h

C/C++
//All of the constant pitches for the buzzer 

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

Questions.ino

C/C++
void Questions(){
//Initilizaiton
  UserResponse = 0;                                                   
  ResponseFinal = 0;                                                    
  Negative = false;
      
//Generate A Random Question
  randomSeed(analogRead(1));
  QuestionCase = random(5);

//Generates Math Question Values
  x = random(50);
  y = random(50);
  z = random(50);

  switch(QuestionCase){
    
    case 0:
    Answer = x+y+z;
    sign1 = '+';
    sign2 = '+';
    PrintQuestion();
    break;

    case 1:
    Answer = x+y-z;
    sign1 = '+';
    sign2 = '-';
    PrintQuestion();
    break;

    case 2:
    Answer = x-y;
    z = '\0';
    sign1 = '-';
    sign2 = '\0';
    PrintQuestion();
    break;

    case 3:
    Answer = x+y;
    z = '\0';
    sign1 = '+';
    sign2 = '\0';
    PrintQuestion();
    break;

    case 4:
    x = random(20);
    y = random(11);
    Answer = x*y;
    z = '\0';
    sign1 = '*';
    sign2 = '\0';   
    PrintQuestion();
    break;

  }
  
//Debugging
  Serial.print("QuestionCase: ");
  Serial.print(QuestionCase);
  Serial.print(" x: ");
  Serial.print(x);
  Serial.print(" y: ");
  Serial.print(y);
  Serial.print(" z: ");
  Serial.print(z);
  Serial.print(" Answer: ");
  Serial.print(Answer); 
  Serial.print(" Sign1: ");
  Serial.print(sign1);
  Serial.print(" Sign2: ");
  Serial.println(sign2);
   
}

Credits

Arpit
12 projects • 6 followers
Firmware Engineer specializing in embedded systems, MCU programming, and hardware-software integration.

Comments