With the system assembled, you can now upload the Arduino code to the Feather M0 for testing and configuration.
If you are new to the Feather M0, start here to set up the board for use with the Arduino IDE.
When you're comfortable uploading code, such as a basic Blink sketch, to your Feather, you can now install the libraries used in the Crypto Countdown Case.
In the Arduino IDE, click on Sketch > Include LIbrary> Manage Libraries... to open up the Library Manager. From here, search for these three libraries and then click the Install button for each:
- Adafruit GFX
- Adafruit BusIO
- Adafruit LED Backpack
- Adafruit NeoPixel
Once those are installed, close the Library Manger and download the following sketch, uncompress it, and place it in your Arduino sketches directory. Open the sketch in the Arduino IDE and upload it to your Feather M0.
Now to test it out. Disconnect the Feather from the computer USB, then plug in the battery to the Feather. Make sure the TerminalBlock FeatherWing's on-board switch is in the ON position, then press the green power button. It will light up and sent the display and buzzer into a boot sequence, blink the time at "03.00" and then start the countdown. Flip the toggles in the proper order -- red, white, blue, green yellow -- and the display will freeze, scroll "Disarming", and give the secret coded message.
Reset the board, and try it again, but enter an incorrect password this time. The display will quickly run down to 00.00 and display the "X.X.X.X." and "Boom" messages, while beeping.
There are a number of places in the code to customize things. You can:
- Change the allowReset variable from 1 to 0 in order to prevent players from turning off the box
- Use a different toggle switch order by changing the PASSWORD[] array
- Adjust the countdown duration with the gTimer variable (be sure to change the displayScroll message and blink text in the setup loop to match)
- Give the players a customized message after successfully entering the password in the section following the displayScroll(" Disarmed ");
//Crypto Countdown Case //by John Park and Usman Muzaffar //for Adafruit Industries //MIT License, include above text in redistribution // // #include <Wire.h> #include <Adafruit_GFX.h> #include "Adafruit_LEDBackpack.h" #include <Adafruit_NeoPixel.h> #define NEOPIN A2 //NeoPixel attached to pin A2 of the Feather #define BUZZPIN A0 //Piezo buzzer attached to Feather pin A0 //dev hack, set to A1 for quiet const int LEDPIN = 13; int allowReset = 1; //set to 0 to disable user reset with the power button once started //if set to 0, wait until end of game, turn off all toggles, then turn off power Adafruit_NeoPixel pixel = Adafruit_NeoPixel(1, NEOPIN, NEO_RGB + NEO_KHZ800); Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4(); // Password combo variables const int PASSWORD[5]={2,1,5,4,3}; //stores the password set int inputCode[5]; //stores the input code set int entered = 0; //indicates a full code set has been entered int over = 0; //state of game for escaping while loop int blinker = 0; //for decimal point blinking in updateDisplay function // Switch variables const int WHITESWITCHPIN = 12; // using illuminated toggle switch, Pin to Headlamp, 3v3 to +, GND to GND, use INPUT_PULLDOWN const int REDSWITCHPIN = 11; const int YELLOWSWITCHPIN = 10; const int GREENSWITCHPIN = 6; const int BLUESWITCHPIN = 5; int whiteSwitchState = 0; //variable to read switch state, off/0 or on/1 int redSwitchState = 0; int yellowSwitchState = 0; int greenSwitchState = 0; int blueSwitchState = 0; int whiteSwitchPriorState = 0; //variable to store switch last state int redSwitchPriorState = 0; int yellowSwitchPriorState = 0; int greenSwitchPriorState = 0; int blueSwitchPriorState = 0; int fail = 0; // if fail != 0, the combination failed int success = 0; // counter for successfull entry of combination int count = 0; // number of switches flipped // thousand millis per second unsigned int gTimer; const unsigned long NORMAL = 1000; const unsigned long FAST = 30;//100 this is the rate for fast countdown when combo fails, smaller is faster unsigned int gDuration = NORMAL; bool updateAndCheckTimer() { static unsigned long now, lastUpdated = 0; now = millis(); if (gTimer && now - lastUpdated > gDuration) { gTimer--; lastUpdated = now; return true; } return false; } void updateDisplay() { // Given gTimer, update the alpha4 display char minutesStr[10], secondsStr[10]; int minutes = gTimer / 60; int seconds = gTimer - (minutes * 60); sprintf(minutesStr, "%02d", minutes); sprintf(secondsStr, "%02d", seconds); Serial.print(minutesStr[0]); Serial.print(minutesStr[1]); Serial.print('.'); Serial.print(secondsStr[0]); Serial.print(secondsStr[1]); Serial.println(); alpha4.writeDigitAscii(0, minutesStr[0], 0); //blinking the dot on second character if(blinker==0){ alpha4.writeDigitAscii(1, minutesStr[1], 0); blinker=1; noTone(BUZZPIN); } else if (blinker==1){ alpha4.writeDigitAscii(1, minutesStr[1], 1); blinker=0; tone(BUZZPIN, 350); } alpha4.writeDigitAscii(2, secondsStr[0], 0); alpha4.writeDigitAscii(3, secondsStr[1], 0); alpha4.writeDisplay(); if (gDuration==FAST){ tone(BUZZPIN, 700); } if ((minutes==0)&&(seconds==0)){//time ran out fail=1; } } void displayScroll(const char*s) { const int NUMCHARS = 4; int scrollRate = 400; //delay time in milis for character fill in rate int len = strlen(s); for (int i=0; i < len - NUMCHARS; i++) { for (int j=0; j < NUMCHARS; j++) { alpha4.writeDigitAscii(j, s[i+j]); } alpha4.writeDisplay(); tone(BUZZPIN, 100); delay(scrollRate); //noTone(BUZZPIN); } } void setup() { if (allowReset==0){ pinMode(A5, OUTPUT);//disables the on/off button digitalWrite(A5, LOW);//disables the on/off button } //gTimer = 180; //how much time the player has to enter the code gTimer = 180 ; //countdown time in seconds pixel.begin(); pixel.setBrightness(5); pixel.setPixelColor(0, 200, 0, 0);//starts red pixel.show(); pinMode(LEDPIN, OUTPUT); pinMode(WHITESWITCHPIN, INPUT_PULLDOWN); //this is for M0 SAMD boards, on other boards use 10K resistor and INPUT mode pinMode(REDSWITCHPIN, INPUT_PULLDOWN); pinMode(YELLOWSWITCHPIN, INPUT_PULLDOWN); pinMode(GREENSWITCHPIN, INPUT_PULLDOWN); pinMode(BLUESWITCHPIN, INPUT_PULLDOWN); Serial.begin(9600); //for debugging only alpha4.begin(0x70); // pass in the address //fill the characters with a flicker int b = 0; for(b==1; b<=16; b=b+5){ alpha4.clear(); alpha4.writeDisplay(); delay(50); alpha4.setBrightness(b); alpha4.writeDigitRaw(0, 0xFFFF); alpha4.writeDigitRaw(1, 0xFFFF); alpha4.writeDigitRaw(2, 0xFFFF); alpha4.writeDigitRaw(3, 0xFFFF); alpha4.writeDisplay(); delay(200); } delay(1500); int fillRate = 200; //delay time in millis for character fill-in rate //scroll "---Arming---" on display displayScroll("---Arming----- **** 0300 "); delay(1000); alpha4.clear(); //wipe the display alpha4.writeDisplay(); delay(500); //blink the time 3 times while beeping for (int i=0; i<3; i++) { alpha4.clear(); alpha4.writeDisplay(); delay(300); alpha4.writeDigitAscii(0, '0', 0); alpha4.writeDigitAscii(1, '3', 1); alpha4.writeDigitAscii(2, '0', 0); alpha4.writeDigitAscii(3, '0', 0); alpha4.writeDisplay(); tone(BUZZPIN, 240); delay(625); noTone(BUZZPIN); } //hold time before countdown begins alpha4.clear(); alpha4.writeDisplay(); delay(300); alpha4.writeDigitAscii(0, '0', 0); alpha4.writeDigitAscii(1, '3', 1); alpha4.writeDigitAscii(2, '0', 0); alpha4.writeDigitAscii(3, '0', 0); alpha4.writeDisplay(); tone(BUZZPIN, 480); delay(2000); noTone(BUZZPIN); pixel.setBrightness(20); pixel.setPixelColor(0, 255, 153, 0);//goes to yellow pixel.show(); } void loop() { if (updateAndCheckTimer()) { updateDisplay(); } //check the switches to see if they're toggled whiteSwitchState = digitalRead(WHITESWITCHPIN); redSwitchState = digitalRead(REDSWITCHPIN); yellowSwitchState = digitalRead(YELLOWSWITCHPIN); greenSwitchState = digitalRead(GREENSWITCHPIN); blueSwitchState = digitalRead(BLUESWITCHPIN); if ((whiteSwitchState==HIGH)&&(whiteSwitchPriorState==0)){ inputCode[(count)]=1; count=count+1; whiteSwitchPriorState=1; Serial.print("white flipped, count is "); Serial.println(count); pixel.setPixelColor(0, 255, 255, 255);//white pixel.show(); tone(BUZZPIN, 260); delay(150); noTone(BUZZPIN); } if ((redSwitchState==HIGH)&&(redSwitchPriorState==0)){ inputCode[(count)]=2; count=count+1; redSwitchPriorState=1; Serial.print("red flipped, count is "); Serial.println(count); pixel.setPixelColor(0, 255, 0, 0);//white pixel.show(); tone(BUZZPIN, 260); delay(150); noTone(BUZZPIN); } if ((yellowSwitchState==HIGH)&&(yellowSwitchPriorState==0)){ inputCode[(count)]=3; count=count+1; yellowSwitchPriorState=1; Serial.print("yellow flipped, count is "); Serial.println(count); Serial.println(success); pixel.setPixelColor(0, 255, 255, 0);//white pixel.show(); tone(BUZZPIN, 260); delay(150); noTone(BUZZPIN); } if ((greenSwitchState==HIGH)&&(greenSwitchPriorState==0)){ inputCode[(count)]=4; count=count+1; greenSwitchPriorState=1; Serial.print("green flipped, count is "); Serial.println(count); pixel.setPixelColor(0, 0, 255, 0);//white pixel.show(); tone(BUZZPIN, 260); delay(150); noTone(BUZZPIN); } if ((blueSwitchState==HIGH)&&(blueSwitchPriorState==0)){ inputCode[(count)]=5; count=count+1; blueSwitchPriorState=1; Serial.print("blue flipped, count is "); Serial.println(count); pixel.setPixelColor(0, 0, 0, 255);//white pixel.show(); tone(BUZZPIN, 260); delay(150); noTone(BUZZPIN); } if (count==5){ entered=1; } while ((entered!=0)&&(over==0)) { if (inputCode[0]==PASSWORD[0]&& inputCode[1]==PASSWORD[1]&& inputCode[2]==PASSWORD[2]&& inputCode[3]==PASSWORD[3]&& inputCode[4]==PASSWORD[4]) { success=1; //flash the final number for(int j=0;j<3;j++){ Serial.println("You Did It"); Serial.println(gTimer); tone(BUZZPIN, 349); updateDisplay(); delay(700); noTone(BUZZPIN); alpha4.clear(); alpha4.writeDisplay(); delay(700); } over=1; } else { fail=1; over=1; Serial.println("failed, fast timer now"); gDuration = FAST; } } while (success==1){//after the correct code has been entered, do this //updateDisplay(); delay(2000); pixel.setBrightness(30); pixel.setPixelColor(0, 0, 225, 0);//goes to green pixel.show(); alpha4.clear(); alpha4.writeDisplay(); int fillRate = 200; //delay time in milis for character fill in rate displayScroll(" Disarmed "); noTone(BUZZPIN); alpha4.clear(); //wipe the display alpha4.writeDisplay(); delay(500); //scroll L to R filled symbols while beeping with each landing // change each character for a different message, use writeDigitAscii for regular alphanumerics //scroll "ZHE" alpha4.writeDigitRaw(3, 0x0); alpha4.writeDigitRaw(0, 0x3F00); alpha4.writeDisplay(); delay(500); alpha4.writeDigitRaw(0, 0x0); alpha4.writeDigitRaw(1, 0x3F00); alpha4.writeDisplay(); delay(500); alpha4.writeDigitRaw(1, 0x0); alpha4.writeDigitRaw(2, 0x3F00); alpha4.writeDisplay(); delay(500); alpha4.writeDigitRaw(2, 0x0); alpha4.writeDigitRaw(3, 0x7F00); //add decimal point alpha4.writeDisplay(); tone(BUZZPIN, 400); delay(500); noTone(BUZZPIN); delay(500); //scroll "B" alpha4.writeDigitRaw(0, 0xFD); alpha4.writeDisplay(); delay(500); alpha4.writeDigitRaw(0, 0x0); alpha4.writeDigitRaw(1, 0xFD); alpha4.writeDisplay(); delay(500); alpha4.writeDigitRaw(1, 0x0); alpha4.writeDigitRaw(2, 0x40FD);//add decimal point alpha4.writeDisplay(); tone(BUZZPIN, 400); delay(500); noTone(BUZZPIN); delay(500); //scroll "G" alpha4.writeDigitRaw(0, 0x31); alpha4.writeDisplay(); delay(500); alpha4.writeDigitRaw(0, 0x0); alpha4.writeDigitRaw(1, 0x4031); alpha4.writeDisplay(); tone(BUZZPIN, 400); delay(500); noTone(BUZZPIN); delay(500); //"K" alpha4.writeDigitAscii(0, 'K', 1); alpha4.writeDisplay(); tone(BUZZPIN, 400); delay(1000); noTone(BUZZPIN); delay(4000); //check the switches re-enable power switch to turn it off whiteSwitchState = digitalRead(WHITESWITCHPIN); redSwitchState = digitalRead(REDSWITCHPIN); yellowSwitchState = digitalRead(YELLOWSWITCHPIN); greenSwitchState = digitalRead(GREENSWITCHPIN); blueSwitchState = digitalRead(BLUESWITCHPIN); if ((whiteSwitchState==LOW)&&(redSwitchState==LOW)&& (yellowSwitchState==LOW)&&(greenSwitchState==LOW)&& (blueSwitchState==LOW)){ digitalWrite(A5, HIGH);//re-enable the on/off button } } while (!gTimer && fail==1){ //after incorrect code is entered, do this pixel.setBrightness(50); pixel.setPixelColor(0, 255, 0, 0);//set to red pixel.show(); Serial.println("failed"); alpha4.writeDigitAscii(0, 'X', 1); alpha4.writeDigitAscii(1, 'X', 1); alpha4.writeDigitAscii(2, 'X', 1); alpha4.writeDigitAscii(3, 'X', 1); alpha4.writeDisplay(); tone(BUZZPIN, 900); delay(500); over=1; pixel.setBrightness(100); pixel.setPixelColor(0, 255, 0, 0); pixel.show(); alpha4.writeDigitAscii(0,'B'); alpha4.writeDigitAscii(1,'o'); alpha4.writeDigitAscii(2,'o'); alpha4.writeDigitAscii(3,'m'); alpha4.writeDisplay(); delay(200); pixel.setPixelColor(0, 0, 0, 0); pixel.show(); alpha4.clear(); alpha4.writeDisplay(); tone(BUZZPIN, 800); delay(500); noTone(BUZZPIN); //check the switches re-enable power switch to turn it off whiteSwitchState = digitalRead(WHITESWITCHPIN); redSwitchState = digitalRead(REDSWITCHPIN); yellowSwitchState = digitalRead(YELLOWSWITCHPIN); greenSwitchState = digitalRead(GREENSWITCHPIN); blueSwitchState = digitalRead(BLUESWITCHPIN); if ((whiteSwitchState==LOW)&&(redSwitchState==LOW)&& (yellowSwitchState==LOW)&&(greenSwitchState==LOW)&& (blueSwitchState==LOW)){ digitalWrite(A5, HIGH);//re-enable the on/off button } } }
Next, let's put it all inside a suitably themed, Cold War-era style enclosure.
Text editor powered by tinymce.