Skip to content

Instantly share code, notes, and snippets.

@NormalUniverse
Created February 11, 2017 21:09
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NormalUniverse/f128cf3609d7d4a3cca49d6996569539 to your computer and use it in GitHub Desktop.
Save NormalUniverse/f128cf3609d7d4a3cca49d6996569539 to your computer and use it in GitHub Desktop.
//***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