Created
February 11, 2017 21:09
-
-
Save NormalUniverse/f128cf3609d7d4a3cca49d6996569539 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//***VARIABLES AND SUCH*** | |
#include <Time.h> | |
#include <TimeLib.h> | |
#include <Adafruit_NeoPixel.h> | |
//Variables associated with Clock FSM | |
int t_hour = 20; | |
int t_minute = 29; | |
int t_second = 50; | |
int last_second = 0; | |
int a_hour =20; | |
int a_minute = 30; | |
int a_extent = 42; | |
bool a_engage = 0; | |
int clockState = 0; //state for the clock FSM | |
//variables associated with display FSM | |
int led_pin = 6; | |
int led_count = 60; | |
int led_val = 40; //brightness | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(led_count, led_pin, NEO_GRB + NEO_KHZ800); | |
int displayState = 0; | |
int extent = 0; | |
int r = 0; | |
int g = 0; | |
int b = 0; | |
int k_d = 0; //k thing for animations, for the display | |
unsigned long t_s_d = 0; | |
int t_climb1_d = 3; | |
int t_wait_d = 300; | |
int t_alarm_d = 600; | |
int score = 0; | |
//debug variables | |
bool debug1 = false; | |
//set up Inputs | |
class SWITCH { | |
private: | |
//hardware related | |
int _pin; | |
//used in finite state machine | |
int _state; | |
int _value; | |
//necessary timing variables | |
unsigned long _t_0; | |
unsigned long _t_bounce; | |
unsigned long _t; | |
unsigned long _t_hold; | |
public: | |
//constructor funciton | |
SWITCH(int pin, unsigned long t_bounce, unsigned long t_hold) { | |
//read in the pin assignment, set pin to INPUT w/ pullup resistor | |
_pin = pin; | |
pinMode(_pin,INPUT_PULLUP); | |
//initialize the FSM | |
_state = 0; | |
_value = 1; //switch value, nomorally 1 because of pullup resistor | |
//initialize _t and _T_0, read in debaounce time; | |
_t = millis(); | |
_t_0 = millis(); | |
_t_bounce = t_bounce; | |
_t_hold = t_hold; | |
} | |
void FSM() { | |
//record the button reading and the time. | |
_value = digitalRead(_pin); | |
_t = millis(); | |
switch(_state) { //Finite State Machine, see diagram | |
case 0: | |
if (_value == 0) {_state = 1;} | |
break; | |
case 1: | |
_t_0 = millis(); | |
_state = 2; | |
break; | |
case 2: | |
//record current time for comparison | |
if (_value == 1) { //if the user releases button, go back to start | |
_state = 0; | |
} | |
if (_t - _t_0 > _t_bounce) { //if the debounce buffer expires, arm | |
_state = 3; | |
} | |
break; | |
case 3: //armed, if button goes high, trigger, if button is held, HOLD | |
if (_value == 1) { //TRIGGERED! | |
_state = 4; | |
} | |
if (_t - _t_0 > _t_hold) { | |
_state = 5; | |
} | |
break; | |
case 4: //Triggered! | |
_state = 0; | |
break; | |
case 5: //HOLD! go back home | |
if(_value == 1) {_state = 0;} | |
break; | |
} | |
} | |
bool isTriggered() { | |
if (_state == 4) { | |
return true; | |
} | |
else { | |
return false; | |
} | |
} | |
bool isHeld() { | |
if (_state == 5) { | |
return true; | |
} | |
else { | |
return false; | |
} | |
} | |
int getState() { | |
return _state; | |
} | |
bool getVal() { | |
return digitalRead(_pin); | |
} | |
}; | |
class ROTARY { | |
private: | |
SWITCH _switch1; | |
SWITCH _switch2; | |
//FSM variables | |
int _state; | |
int _val; | |
public: | |
ROTARY(int pin1, int pin2, int t_bounce,int t_hold) : _switch1(pin1,t_bounce,t_hold) , _switch2(pin2,t_bounce,t_hold) { | |
_state = 0; | |
_val = 0; | |
} | |
void FSM() { | |
_switch1.FSM(); | |
switch (_state) { | |
case 0: //reset | |
_val = 0; | |
if (_switch1.isTriggered()) { | |
if (_switch2.getVal()) { | |
_state = 1; | |
} | |
else { | |
_state = 2; | |
} | |
} | |
break; | |
case 1: //right turn | |
_val = 1; | |
_state = 0; | |
break; | |
case 2: //left turn | |
_val = -1; | |
_state = 0; | |
break; | |
} | |
} | |
int getVal() { | |
return _val; | |
} | |
}; | |
ROTARY rotary1(10,11,10,20000); | |
SWITCH switch1(12,3,1500); | |
//set up Piezo Nerf Detector | |
class PIEZO { | |
private: | |
//private variables | |
int pz_pin; //piezo pin | |
int pz_val; //piezo val | |
int th_h; //high threshhold | |
int th_l; //low threshhold | |
int th_s; //score threshold | |
int state; //state of FSM | |
int score; | |
unsigned long t_s; //time at start of state | |
unsigned long t; //current time | |
unsigned long delay_timeout; //timeout delay | |
public: | |
//public variables | |
//public methods | |
//constructor function | |
PIEZO(int pin, int h, int l, int timeout, int threshold_score) { | |
pz_pin = pin; | |
th_h = h; | |
th_l = l; | |
delay_timeout = timeout; | |
th_s = threshold_score; | |
//declare everthing | |
pz_val = 0; | |
state = 0; | |
score = 0; | |
t_s = millis(); | |
t = millis(); | |
} | |
//get score function | |
int getScore() { | |
return score; | |
} | |
//get state function | |
int getState(){ | |
return state; | |
} | |
void FSM() { | |
pz_val = analogRead(pz_pin); | |
//Serial.println(state); | |
switch (state){ | |
case 0: //RESET! | |
score = 0; | |
if (pz_val < th_l) { | |
state = 2; | |
} | |
break; | |
case 2: //ARM | |
if (pz_val > th_h) { | |
state = 4; | |
t_s = millis(); | |
} | |
break; | |
case 4: //HIGH | |
t = millis(); | |
if(t - t_s > delay_timeout) { | |
state = 0; | |
} | |
if(pz_val < th_l) { | |
state = 5; | |
score++; | |
t_s = millis(); | |
state = 6; | |
} | |
break; | |
case 6: //LOW | |
t = millis(); | |
if(t - t_s > delay_timeout) { | |
state = 7; | |
} | |
if(pz_val > th_h) { | |
state = 4; | |
} | |
break; | |
case 7: //TRIGGER! | |
state = 0; | |
break; | |
} | |
} | |
bool isTriggered() { | |
if ( (state == 7) && (score > th_s) ){ | |
return true; | |
} | |
else { | |
return false; | |
} | |
} | |
}; | |
PIEZO piezo1(5,300,200,10,4); //pin, high thresh, low thresh, timeout, score-thresh | |
//set up Buzzer | |
class BUZZER { | |
private: | |
int _pin; //buzzer pin | |
unsigned long _t_s; //state time | |
int _state = 0; | |
int _t_beep; //beep duration | |
int _t_a1; //on time | |
int _t_a2; //off time | |
public: | |
BUZZER(int pin, int t_beep, int t_a1, int t_a2) { | |
_pin = pin; | |
_t_beep = t_beep; | |
_t_a1 = t_a1; | |
_t_a2 = t_a2; | |
pinMode(_pin,OUTPUT); | |
} | |
void FSM() { | |
switch (_state) { | |
case 0: | |
break; | |
case 1: //beep then go home | |
if (millis() - _t_s > _t_beep) { | |
digitalWrite(_pin,LOW); | |
_state = 0; | |
} | |
break; | |
case 2: //high portion of alarm | |
if (millis() - _t_s > _t_a1) { | |
digitalWrite(_pin,LOW); | |
_state = 3; | |
_t_s = millis(); | |
} | |
break; | |
case 3: //low portion of alarm | |
if (millis() - _t_s > _t_a2) { | |
digitalWrite(_pin,HIGH); | |
_state = 2; | |
_t_s = millis(); | |
} | |
} | |
} | |
void beep() { | |
_t_s = millis(); | |
digitalWrite(_pin,HIGH); | |
_state = 1; | |
} | |
void on() { | |
digitalWrite(_pin,HIGH); | |
_state = 3; | |
_t_s = millis(); | |
} | |
void off() { | |
digitalWrite(_pin,LOW); | |
_state = 0; | |
} | |
}; | |
BUZZER buzzer1(9, 100, 600, 600); //pin, t_beep, t_a1, t_a2 | |
//***PROGRAM START*** | |
void setup() { | |
Serial.begin(230400); //begin serial | |
strip.begin(); //begin strip | |
setTime(t_hour, t_minute, t_second, 0, 0, 0); | |
//first wipes the display, then displays the time | |
displayState = 0; | |
displayFSM(); | |
} | |
void loop() { | |
// put your main code here, to run repeatedly: | |
rotary1.FSM(); | |
switch1.FSM(); | |
piezo1.FSM(); | |
buzzer1.FSM(); | |
clockFSM(); | |
if (debug1) { | |
Serial.print("clockState = "); | |
Serial.print(clockState); | |
Serial.print(" | displayState = "); | |
Serial.print(displayState); | |
Serial.print(" | time = "); | |
Serial.print(hour()); | |
Serial.print(":"); | |
Serial.print(minute()); | |
Serial.print(":"); | |
Serial.print(second()); | |
Serial.print(" | alarm = "); | |
Serial.print(a_hour); | |
Serial.print(":"); | |
Serial.print(a_minute); | |
Serial.print(" | engage = "); | |
Serial.println(a_engage); | |
} | |
displayFSM(); | |
if (piezo1.isTriggered()) { | |
buzzer1.beep(); | |
} | |
} | |
void clockFSM() { | |
switch(clockState) { | |
case 0: //HOME | |
if ((minute() % 12 ==0) && (second() == 0) && (millis() % 1000 == 0)) {displayState = 0;} //every 12 minutes update clock | |
if (switch1.isTriggered()) {clockState = 1; displayState = 3;} | |
if (piezo1.isTriggered()) { | |
clockState = 5; | |
displayState = 7; | |
buzzer1.beep(); | |
score=piezo1.getScore(); | |
Serial.println(score);} | |
if (switch1.isHeld()) { //turn on alarm if button is held | |
buzzer1.on(); | |
displayState = 9; | |
clockState = 6; | |
} | |
if (a_engage == 1 && a_hour == hour() && a_minute == minute()) { //turn on alarm if alarm happens | |
a_engage = 0; | |
buzzer1.on(); | |
displayState = 9; | |
clockState = 6; | |
} | |
break; | |
case 1: //SET HOUR: in this state we adjust the hour | |
setHour(); //uses encoder to adjust hour setting | |
if (!(rotary1.getVal()==0)) {displayState = 3;} //if hour changes, refresh display | |
if (switch1.isTriggered()) {clockState = 2; displayState = 4;} //if button is pushed, proceed to set minute | |
break; | |
case 2: //SET MINUTE: | |
setMinute(); //adjusts minute value using rotary encoder | |
if (!(rotary1.getVal()==0)) {displayState = 4;} //set display to displayMinute | |
if (switch1.isTriggered()) {clockState = 3; displayState = 5;} //if button is pressed, go home and refresh display | |
break; | |
case 3: //SET ALARM | |
setAlarm(); //adjust alarm val | |
if (!(rotary1.getVal()==0)) {displayState = 5;} //update display if alarm val changes | |
if (switch1.isTriggered()) {clockState = 4; displayState = 6;} //if button is pressed, switch to engage | |
break; | |
case 4: //SET ENGAGE | |
setEngage(); | |
if (!(rotary1.getVal()==0)) {displayState = 6;} //update display if alarm val changes | |
if (switch1.isTriggered()) {clockState = 0; displayState = 0;} | |
break; | |
case 5: //HIT! | |
if (displayState==0) {clockState = 0;} | |
break; | |
case 6: //Alarm! | |
if (switch1.isTriggered() || piezo1.isTriggered()) {buzzer1.off() ; clockState = 5; displayState = 7;} | |
break; | |
} | |
} | |
void displayFSM() { | |
switch(displayState) { | |
case 0: //RESET: shows the time then starts ticToc-ing | |
displayTime(); | |
displayState = 2; | |
strip.show(); | |
break; | |
case 1: //WAIT | |
break; | |
case 2: //DISPLAY TIME: shows time, ticks 12, shows alarm info | |
if(millis() % 1000 == 0) { ticToc();} | |
break; | |
case 3: //DISPLAY HOUR: describes hour when setting time | |
displayHour(); | |
displayState = 1; //after updating display, go back to wait | |
strip.show(); | |
break; | |
case 4: //DISPLAY MINUTE: display minute when setting time | |
displayMinute(); | |
displayState = 1; //after updating display, go back to wait | |
strip.show(); | |
break; | |
case 5: //DISPLAY ARAM SET: shows alarm setting | |
displayAlarm(); | |
displayState = 1; | |
strip.show(); | |
break; | |
case 6: //DISPLAY ENGAGE: shows alarm engage state | |
displayEngage(); | |
displayState = 1; | |
strip.show(); | |
break; | |
case 7: //HIT ANIMATION: congratulatory animation | |
displayClear(); | |
k_d = 0; | |
t_s_d = millis(); | |
displayState = 8; | |
break; | |
case 8: //HIT ANIMATION CLIM | |
if (millis() - t_s_d > t_climb1_d) {strip.setPixelColor(k_d,led_val,0,led_val); t_s_d = millis();strip.show();k_d++;} | |
if (k_d==(60)) {displayState = 11; t_s_d = millis();} | |
break; | |
case 9: //ALARM ANIMATION BRIGHT | |
if (millis() - t_s_d > t_alarm_d) {t_s_d = millis(); displayFlood(0.5); displayState = 10;} | |
break; | |
case 10: | |
if (millis() - t_s_d > t_alarm_d) {t_s_d = millis(); displayFlood(3); displayState = 9;} | |
break; | |
case 11: //wait a bit | |
if (millis() - t_s_d > t_wait_d) {displayState = 0;} | |
break; | |
} | |
} | |
void setHour() { | |
//add the encoder value to the hour value | |
t_hour = hour() + rotary1.getVal(); | |
//account for overflow of hour | |
if (t_hour == -1) { | |
t_hour = 23; | |
} | |
if (t_hour == 24) { | |
t_hour = 0; | |
} | |
//assign hour to time | |
setTime(t_hour, t_minute, t_second, 0, 0, 0); | |
} | |
void setMinute() { | |
//add the encoder value to the minute | |
t_minute = minute(); | |
t_minute = t_minute + rotary1.getVal(); | |
//adjust t_minute in the event of a rollover | |
if (t_minute == -1) {t_minute = 59;} | |
if (t_minute == 60) {t_minute = 0;} | |
//assign minute to time | |
setTime(t_hour, t_minute, t_second,0, 0, 0); | |
} | |
void setAlarm() { | |
a_minute = a_minute + rotary1.getVal() * 12; | |
if(a_minute == 60) { a_hour++; a_minute = 0;} //account for houroverflow | |
if(a_minute == -12) { a_hour--; a_minute = 48;} //account for hour underflow | |
if(a_hour == -1) {a_hour = 23;} //account for hour underflow | |
if(a_hour == 24) {a_hour = 0;} //account for hour overflow | |
} | |
void setEngage() { | |
if (rotary1.getVal() != 0) {a_engage = 1 - a_engage;} //flip a_engage | |
} | |
void displayTime() { | |
//extent should be 5 times the hour, plus the minute / 12.5, if hour is 12, bump it back to 0 | |
extent = (5 * (hourFormat12()%12)) + (minute() / 12); | |
if ( isAM() ) { //clock should be blue in AM and red in PM | |
r = 0; | |
g = 0; | |
b = led_val; | |
} | |
else {r = led_val * 1.2; g = 0; b = 0;} // | |
for (int k = 0 ; k <= extent ; k++) { //iterate thru the loop and set pixel colors, hours should be white | |
if ((k % 5) == 0) { | |
strip.setPixelColor(k,led_val,led_val,led_val); | |
} | |
else { | |
strip.setPixelColor(k,r,g,b); | |
} | |
} | |
for (int k = extent + 1 ; k < led_count ; k++) {strip.setPixelColor(k,0,0,0);} //trun the rest of the pixel blank | |
//add alarm pixel | |
if(a_engage) { | |
if( a_hour < 12) {strip.setPixelColor(a_extent,0,0,led_val*1.5);} | |
else {strip.setPixelColor(a_extent,led_val*1.5,0,0);} | |
} | |
} | |
void displayHour() { | |
//extent should be 5 times the hour, plus the minute / 12.5 | |
extent = (5 * hourFormat12()); | |
if ( isAM() ) { //clock should be blue in AM and red in PM | |
r = 0; | |
g = 0; | |
b = led_val * 1.2; | |
} | |
else { | |
r = led_val * 1.2; | |
g = 0; | |
b = 0; | |
} | |
for (int k = 0 ; k <= extent ; k++) { //iterate thru the loop and set pixel colors, hours should be white | |
if ((k % 5) == 0) { | |
strip.setPixelColor(k,led_val,led_val,led_val); | |
} | |
else { | |
strip.setPixelColor(k,r,g,b); | |
} | |
} | |
for (int k = extent + 1 ; k < led_count ; k++) { | |
strip.setPixelColor(k,0,0,0); | |
} | |
//if hour lands on 12, invoke special case | |
if (hourFormat12() == 12) { | |
for (int k = 0 ; k < led_count ; k++) { | |
strip.setPixelColor(k,0,0,0); | |
} | |
strip.setPixelColor(59,r,g,b); | |
strip.setPixelColor(1,r,g,b); | |
strip.setPixelColor(0,led_val,led_val,led_val); | |
} | |
} | |
void displayAlarm() { | |
//extent should be 5 times the alarm hour, plus the minute / 12, if hour is 12, bump it back to 0 | |
a_extent = 5 * (a_hour % 12) + (a_minute / 12); | |
if ( a_hour < 12 ) { r = 0; g = 0; b = led_val; }//clock should be blue in AM and red in PM | |
else {r = led_val;g = 0;b = 0; } | |
for (int k = 1 ; k <= a_extent ; k++) { //iterate thru the loop and set pixel colors, hours should be white | |
if ((k % 5) == 0) {strip.setPixelColor(k,led_val,led_val,led_val);} | |
else {strip.setPixelColor(k,r,g,b);} | |
} | |
for (int k = a_extent + 1 ; k < led_count ; k++) {strip.setPixelColor(k,0,0,0);} //blank out excess pixels | |
strip.setPixelColor(0 , led_val*1.2 , 0 , led_val*1.2); //sets top pixel purple | |
} | |
void displayMinute() { | |
//extent is equal to # of minutes | |
extent = minute(); | |
r = 0; | |
g = led_val * 1.2; | |
b = 0; | |
for (int k = 1 ; k <= extent ; k++) { //iterate thru the loop and set pixel colors, hours should be white | |
if ((k % 5) == 0) { | |
strip.setPixelColor(k,led_val,led_val,led_val); | |
} | |
else { | |
strip.setPixelColor(k,r,g,b); | |
} | |
} | |
for (int k = extent + 1; k < led_count; k++) { | |
strip.setPixelColor(k,0,0,0); | |
} | |
strip.setPixelColor(0,0,0,0); | |
strip.show(); | |
} | |
void displayEngage() { | |
displayClear(); | |
for (int k = 42; k <= 48; k++) {strip.setPixelColor(k,led_val*1.2,0,led_val*1.2);} | |
for (int k = 12; k <= 18; k++) {strip.setPixelColor(k,led_val*1.2,0,led_val*1.2);} | |
if (a_engage) { | |
for (int k = 57; k <= 63; k++) {strip.setPixelColor((k % 60),led_val*1.2,0,led_val*1.2);} | |
for (int k = 27; k <= 33; k++) {strip.setPixelColor(k,led_val*1.2,0,led_val*1.2);} | |
} | |
} | |
void displayClear() { | |
for (int k = 0; k < led_count; k++) {strip.setPixelColor(k,0,0,0);} | |
} | |
void displayFlood(int intensity) { | |
for(int k = 0 ; k < led_count ; k++){ strip.setPixelColor(k,led_val * intensity,led_val * intensity,led_val * intensity);} | |
strip.show(); | |
} | |
void ticToc() { //this function ticks the LED at the top of the ring every second | |
if (!(second() % 2)) { | |
strip.setPixelColor(0,led_val,led_val,led_val); | |
strip.show(); | |
} | |
else { | |
strip.setPixelColor(0,0,0,0); | |
strip.show(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment