Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 1 | ||||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
Hand tools and fabrication machines | ||||||
![]() |
| |||||
The inspiration is the same painful morning struggle — hitting snooze too easily. This version is a custom 3D-printed alarm clock that requires entering a short code on a keypad to silence the alarm. No more half-asleep button mashing! It uses an Arduino-compatible board, RTC module, LCD, 7-segment display, buzzer, and keypad for a fully functional (and frustratingly effective) wake-up device.
Difficulty: Intermediate (3D printing, soldering/electronics, basic coding)Time: 10-15 hours + print timeCost: ~$30-50 depending on parts you already have.
Materials
- 3D printer + filament (black/charcoal PLA or PETG)
- Arduino Nano / Uno (or compatible)
- DS3231 RTC module
- 16x2 LCD display
- 4-digit 7-segment display (TM1637 or similar)
- 4x4 keypad matrix
- Active buzzer or speaker
- Buttons/switches for testing
- Jumper wires, protoboard or perfboard
- Power supply (5V USB)
- Optional: enclosure hardware, hot glue, etc.
Start with a compact rectangular box design to house all electronics. Include cutouts for the displays, keypad on top, and access ports on the sides/back. Slightly rounded edges for a modern look, with space for wiring.
I modeled it in Fusion 360, then tweaked the original concept with minor dimension changes for better fit and aesthetics.
Export as STL and slice for printing (0.2mm layer height recommended for clean results).
Step 2: 3D Print the CasePrint the main body and any lid/top plate. Use supports where needed for overhangs. Post-process with light sanding for a smooth finish and to hide layer lines slightly (but leave some visible for that handmade look).
Step 3: Electronics Prototyping and AssemblyWire up the components:
- Keypad to Arduino pins for matrix scanning.
- LCD and 7-segment to appropriate I2C/SPI pins.
- RTC for accurate timekeeping.
- Buzzer to a PWM pin for alarm tones.
Prototype on a breadboard first, then solder to perfboard for permanence. Mount everything securely inside the case with hot glue or standoffs. Test connections thoroughly before closing it up.
Step 4: Coding
Use the Arduino IDE. You'll need libraries for the keypad, LCD, TM1637/7-segment, DS3231, and buzzer tones.
Key features in the code:
- Set current time and alarm time.
- Display current time on 7-segment + alarm info on LCD.
- When alarm triggers: loud buzzer + flashing displays.
- To turn off: enter a specific code (e.g., 1-3-5-7 or whatever you set) on the keypad.
- Add a snooze option that requires a longer/different code or multiple steps.
Step 5: Final Assembly and Testing
Fit all parts into the printed case. Secure the keypad on top, displays in front cutouts. Add strain relief for any external power cable. Close it up and test the full system — set an alarm and practice disabling it (while fully awake!).
Place it across the room so you have to get out of bed. Customize the disable code to something you won't remember half-asleep. Future ideas: add motion sensor to verify you're up, or multiple alarm stages.
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(""); // */
}
//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("=");
}
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); // */
}
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
}
}
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); // */
}
//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();
}
}
//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
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);
}










Comments