I've decided to make an electronic toy for my friends and family this year, so I'm getting a jump on it.
My idea is an electronic implementation of the classic "magic 8 ball". I know it's been done before, but I wrote this one from scratch, without looking at others, and striven for a few goals, such as powered for a long time with aaa batteries, blinking lights (I gave blinky presents 20 years ago - this is a sequel), be (relatively) inexpensive and simple to make, bullet-proof code, fit in a mint tin. (I have a limited number of tins printed with an Ouija board, that seems to be perfect!)
This device sleeps at 9 micro-amps, and only draws 6 milliamps when displaying a scrolling message. Opening and closing the tin turns it on and "off". The messages are the standard ones used in the classic Mattel toy. Right now, the device is built on a breadboard, but I will solder it on a perf-board once I'm satisfied that no further changes are needed.
Here is where I am at, starting with the code:
/*
Magic 8 ball (02c) in a tin for tiny85
Adafruit 14 segment I2C backpack (0x70)
flash/ram - 1 MHz internal clock & 3 volts: 9 ua in snooze mode
052816 clh 4082/116 - turn adc off during snooze
- burn to tiny85 #7
*/
#include <TinyWireM.h>
#include <Narcoleptic.h>
#include <avr/pgmspace.h>
#include "Adafruit_GFX.h"
#include "Adafruit_LEDBackpack.h"
// pins and addresses
#define cds A3 // pin --> cds --> gnd
#define in A2 // unconnected
#define button 1 // pin --> button --> gnd
#define SDA 0
#define SCL 2
#define alphaAddress 0x70 // 14 segment I2C device
// counters and states
boolean isBlank;
byte scrollPosition;
byte answerLength;
char phrase[36]; // -->|" "|<--
// numbers and phrases // and length-4 for stepwize scrolling
const char yes1[] PROGMEM = " WITHOUT A DOUBT "; // 17
const char yes2[] PROGMEM = " YOU MAY RELY ON IT "; // 20
const char yes3[] PROGMEM = " YES DEFINITELY "; // 16
const char yes4[] PROGMEM = " SIGNS POINT TO YES "; // 20
const char yes5[] PROGMEM = " IT IS DECIDEDLY SO "; // 20
const char yes6[] PROGMEM = " AS I SEE IT - YES "; // 19
const char yes7[] PROGMEM = " YES "; // 5
const char yes8[] PROGMEM = " MOST LIKELY "; // 13
const char yes9[] PROGMEM = " IT IS CERTAIN "; // 15
const char yesA[] PROGMEM = " OUTLOOK GOOD "; // 14
const char no1[] PROGMEM = " MY SOURCES SAY NO "; // 19
const char no2[] PROGMEM = " DONT COUNT ON IT "; // 18
const char no3[] PROGMEM = " VERY DOUBTFUL "; // 15
const char no4[] PROGMEM = " OUTLOOK NOT SO GOOD "; // 21
const char no5[] PROGMEM = " MY REPLY IS NO "; // 16
const char idk0[] PROGMEM = " BETTER NOT TELL YOU NOW "; // 25
const char idk1[] PROGMEM = " ASK AGAIN LATER "; //17
const char idk2[] PROGMEM = " REPLY HAZY TRY AGAIN "; //22
const char idk3[] PROGMEM = " CANNOT PREDICT NOW "; // 21
const char idk4[] PROGMEM = " CONCENTRATE AND ASK AGAIN "; // 28
const char* const theAnswers[] PROGMEM = { yes1, yes2, yes3, yes4, yes5, yes6, yes7, yes8, yes9, yesA,
no1, no2, no3, no4, no5, idk0, idk1, idk2, idk3, idk4, };
const byte answerLengths[] = { 17, 20, 16, 20, 20, 19, 5, 13, 15, 14, 19, 18, 15, 21, 16, 25, 17, 22, 21, 28, };
// output device and text
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
}
void loop() {
snooze(125);
if (analogRead(cds) < 1000) {
isBlank = false;
scrollPosition = 0;
int ambience = 10;
byte answer = random(0, 16);
answerLength = answerLengths[answer];
// copy the phrase into RAM: https://www.arduino.cc/en/Reference/PROGMEM
strcpy_P(phrase, (char*)pgm_read_word(&(theAnswers[answer])));
while (analogRead(cds) < 950) {
snooze(187); // nap while timing the scroll rate
// ambience dimming if switched on
if (digitalRead(button)) ambience = (constrain(map(analogRead(cds), 800, 0, 0, 10), 0, 10));
alpha.setBrightness(ambience);
if (scrollPosition > answerLengths[answer]) 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 {
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
}
... the schematic:
... and of course, a picture of the actual device.
I would really appreciate any insight or comments any of you may have that I could use to 1) improve this device, and 2) expand and refine my abilities.
THANK YOU!