/* Magic8BallWithBufferClock2c in a tin ATTiny85 - 1 MHz internal clock, 3 volts Adafruit 14 segment I2C backpack (0x70) Generic DS3231 RTC board (0x68) cds on pin 2; switch on pin 6; i2c on pins 5(D) and 7(C) 072016 clh flash: 6702, ram: 271 - burn to tiny85 #4 */ // libraries #include // https://github.com/adafruit/TinyWireM #include // https://github.com/brabl2/narcoleptic #include "Adafruit_GFX.h" // https://learn.adafruit.com/adafruit-led-backpack/downloads #include "Adafruit_LEDBackpack.h" // as above ... // define the pins and i2c addresses #define cds A2 // pin --> cds --> gnd #define in A3 // unconnected #define button 1 // pin --> button --> gnd #define SDA 0 // hardware pullup 10K #define SCL 2 // " " " #define alphaAddress 0x70 // 14 segment I2C device #define rtcAddress 0x68 // DS3231 // phrases and names - first 20 are official phrases const char yes1[] PROGMEM = " WITHOUT A DOUBT"; const char yes2[] PROGMEM = " YOU MAY RELY ON IT"; const char yes3[] PROGMEM = " YES DEFINITELY"; const char yes4[] PROGMEM = " SIGNS POINT TO YES"; const char yes5[] PROGMEM = " IT IS DECIDEDLY SO"; const char yes6[] PROGMEM = " AS I SEE IT - YES"; const char yes7[] PROGMEM = " YES"; const char yes8[] PROGMEM = " MOST LIKELY"; const char yes9[] PROGMEM = " IT IS CERTAIN"; const char yes10[] PROGMEM = " OUTLOOK GOOD"; const char no1[] PROGMEM = " MY SOURCES SAY NO"; const char no2[] PROGMEM = " DONT COUNT ON IT"; const char no3[] PROGMEM = " VERY DOUBTFUL"; const char no4[] PROGMEM = " OUTLOOK NOT SO GOOD"; const char no5[] PROGMEM = " MY REPLY IS NO"; const char idk0[] PROGMEM = " BETTER NOT TELL YOU NOW"; const char idk1[] PROGMEM = " ASK AGAIN LATER"; const char idk2[] PROGMEM = " REPLY HAZY TRY AGAIN"; const char idk3[] PROGMEM = " CANNOT PREDICT NOW"; const char idk4[] PROGMEM = " CONCENTRATE AND ASK AGAIN"; const char huh1[] PROGMEM = " WITHOUT A SNOUT"; const char huh2[] PROGMEM = " YOU MIGHT THINK SO"; const char huh3[] PROGMEM = " I HEAR QUESTIONS"; const char huh4[] PROGMEM = " SIGNS POINT AROUND"; const char huh5[] PROGMEM = " WELCOME TO HELL"; const char huh6[] PROGMEM = " AS I SEE IT - HUH??"; const char huh7[] PROGMEM = " WUT WUT"; const char huh8[] PROGMEM = " YUBBA LUBBA DUB DUB"; const char huh9[] PROGMEM = " IT IS CLEARLY YOUR FAULT"; const char huh10[] PROGMEM = " OUTLOOK MURKY"; const char huh11[] PROGMEM = " MY SOURCES ARE PRIVATE"; const char huh12[] PROGMEM = " DONT KNOW - DONT CARE"; const char huh13[] PROGMEM = " I LIKE PIE"; const char huh14[] PROGMEM = " I DONT KNOW DUDE"; const char huh15[] PROGMEM = " MY REPLY IS IN THE MAIL"; const char huh16[] PROGMEM = " IM NOT GOING TO TELL YOU"; const char huh17[] PROGMEM = " ITS NOW OR NEVER"; const char huh18[] PROGMEM = " TRY HARDER"; const char huh19[] PROGMEM = " I DONT WANT TO DO THIS NOW"; const char huh20[] PROGMEM = " ASK A BETTER QUESTION"; const char* const theAnswers[] PROGMEM = { yes1, yes2, yes3, yes4, yes5, yes6, yes7, yes8, yes9, yes10, no1, no2, no3, no4, no5, idk0, idk1, idk2, idk3, idk4, huh1, huh2, huh3, huh4, huh5, huh6, huh7, huh8, huh9, huh10, huh11, huh12, huh13, huh14, huh15, huh16, huh17, huh18, huh19, huh20, }; char* const dayNames[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; char* const monthNames[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; // counters and states boolean isBlank; boolean isAfternoon; boolean originalButtonState = false; byte answer; byte scrollPosition; byte answerLength; char phrase[36]; // -->|" "|<-- // output device Adafruit_AlphaNum4 alpha = Adafruit_AlphaNum4(); void setup() { pinMode(cds, INPUT_PULLUP); pinMode(button, INPUT_PULLUP); randomSeed(analogRead(in)); pinMode(in, INPUT); alpha.begin(alphaAddress); // i2c address of the alphanumeric display //alpha.setBrightness(10); } void loop() { snooze(125); // nap while box is closed if (analogRead(cds) < 1020) { isBlank = false; scrollPosition = 0; originalButtonState = digitalRead(button); answer = random(0, 20); if (random(100) <= 10) answer = answer + 20; // mix in 10% "funny" answers while (analogRead(cds) < 1010) { // set the string: 'phrase' and the byte: 'answerLength' snooze(187); // nap while timing the scroll rate // Read the switch: if clock mode, update clock in real time if (originalButtonState != digitalRead(button)) { answerLength = 31; // get bcd data from the rtc TinyWireM.beginTransmission(rtcAddress); // 0x68 is DS3231 device address TinyWireM.write((byte)0); // start at register 0 TinyWireM.endTransmission(); TinyWireM.requestFrom(rtcAddress, 7); // request 7 bytes (seconds, minutes, hours, theDay, theDate, theMonth, theYear) int seconds = TinyWireM.read(); int minutes = TinyWireM.read(); int hours = TinyWireM.read(); int theDay = TinyWireM.read(); int theDate = TinyWireM.read(); int theMonth = TinyWireM.read(); int theYear = TinyWireM.read(); // convert BCD to decimal hours = (((hours & 0b00110000) >> 4) * 10 + (hours & 0b00001111)); minutes = (((minutes & 0b11110000) >> 4) * 10 + (minutes & 0b00001111)); seconds = (((seconds & 0b11110000) >> 4) * 10 + (seconds & 0b00001111)); theDay = (theDay & 0b00001111); // day of week, Sunday is #1 theDate = (((theDate & 0b00100000) >> 5) * 20 + ((theDate & 0b00010000) >> 4) * 10 + (theDate & 0b00001111)); theMonth = (((theMonth & 0b11110000) >> 4) * 10 + (theMonth & 0b00001111)); theYear = (((theYear & 0b00100000) >> 5) * 20 + ((theYear & 0b00010000) >> 4) * 10 + (theYear & 0b00001111)); // 12 hour clock isAfternoon = (hours >= 12); if (hours > 12) hours -= 12; if (!hours) hours = 12; // format time into a string: http://forum.arduino.cc/index.php?topic=411816.msg2834707#msg2834707 snprintf(phrase, sizeof(phrase), " %2d_%02d_%02d_%s %s %2d %s 20%02d ", hours, minutes, seconds, isAfternoon ? "PM " : "AM ", dayNames[theDay - 1], theDate, monthNames[theMonth - 1], theYear); } else { // if switch is in 8 ball mode, display the answer phrase // copy the phrase into RAM: https://www.arduino.cc/en/Reference/PROGMEM strcpy_P(phrase, (char*)pgm_read_word(&(theAnswers[answer]))); // add 4 spaces to provide a short 'all off', so it can go to sleep if the box is closed strcat(phrase, " "); answerLength = (byte)strlen(phrase) - 4; } // ambience dimming in low light int ambience = (constrain(map(analogRead(cds), 500, 0, 0, 30), 0, 11)); // values from trial-and-error alpha.setBrightness(ambience); // scroll phrase across 4 alphanumeric display digits if (scrollPosition > answerLength) scrollPosition = 0; alpha.writeDigitAscii(0, phrase[scrollPosition]); alpha.writeDigitAscii(1, phrase[scrollPosition + 1]); alpha.writeDigitAscii(2, phrase[scrollPosition + 2]); alpha.writeDigitAscii(3, phrase[scrollPosition + 3]); alpha.writeDisplay(); scrollPosition++; } } else { // turn all 14 segments off if (!isBlank) { isBlank = true; alpha.writeDigitRaw(0, 0); alpha.writeDigitRaw(1, 0); alpha.writeDigitRaw(2, 0); alpha.writeDigitRaw(3, 0); alpha.writeDisplay(); } } } // sleep with ADC off - http://forum.arduino.cc/index.php?topic=248690.msg1778100 void snooze(unsigned long int ms) { byte adcsra_save = ADCSRA; ADCSRA = 0; // turn adc off Narcoleptic.delay(ms); // Zzzzzzz. ADCSRA = adcsra_save; // adc back on }