Please critique my project

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!

For appearance, I would find a piece of red plastic to cover the display so the inactive segments don't show.

paul

Great idea Paul! I have some deep red cellophane that should be perfect.

In person, the unlit segments are not as bright as they look here, I suspect they are retro reflecting the photo lighting. But the red filter will make the words snap.

How about using a magnet glued on the lid and a change over reed switch. Then as the lid is opened the magnet deactivates the reed switch and the normally closed contacts close and supply power to the system.

Thanks Mike - I'm sure they have reed switches at Fry's. I will pick one up (they are 2 or 3 bucks) and experiment with it.

Hi ChrisTenone,

Outlook Good!

The only thing I have to say is in my experience I've never needed to pull up any of my ATtiny reset lines. I think it has a pretty decent internal pullup resistor.

Pat.

a bit off to the side, but I have lost more electronics and toys to duracell than energizer or generic.

not sure why duracell leak so much, but my experience is not pretty.

how about a capacitive sensor ?
for those odd times when yes or no needs a little help ?

Pat - thanks - one less component is a good thing!

Dave, I haven't noticed that, but something I will consider when I'm ready to wrap these up!

As to a capacitive sensor, you mean like you touch the case and it modifies the answer? Or ... what do you mean?

I love the silver mica capacitor and the vintage 10K resistor!

Heh. I have a bunch of old stuff. I like the look of the old brown cylinder resistors, as opposed to the modern bimodal blobs (like the 12c pull-ups.) I'm starting to run low though - this is one of my last 10K's.

I like the look of the old silver mica caps.
I have lots of old parts too, but most won't plug into the breadboard :frowning: .
.

I've got a couple CDS cells that are the size of human eyeballs, with long wire leads (coiled for the scifi effect) and fork connectors. I put them into a Lego robot head that turns toward the light when my office door is opened.

Update:

I made two of these, using slightly different software for each, but using the same general idea. The black version displays the I Ching, while the red version shows the magic 8 ball with an hourglass timer.

Thanks again everybody! I tried them all, and took some or your suggestions, but some did not pan out. Check the red gel over the LEDs - it really does improve the contrast substantially! I removed the reset resistor and I2C pullups, which seems to have improved the 'dark current' by a couple microamps. And I replaced the Duracells with other aaa batteries, which gives me the warm fuzzy of sticking it to the Man!

Oh, and I soldered them together, rather than using solderless breadboards:

Grumpy_Mike:
How about using a magnet glued on the lid and a change over reed switch. Then as the lid is opened the magnet deactivates the reed switch and the normally closed contacts close and supply power to the system.

A SPDT reed switch can be used to switch power on with the N.O. contacts. Eventually a transistor can provide the main current, if its too much for the reed contacts.

After reading Mike's comment, I did go buy a couple reed switches. It worked fine, no transistor was needed - the current is only a few milliamps when running. Using the switch instead of the light detecting resistor only saved a few microamps, yet added to the complexity of the device. I prefer the ldr, but I'll keep it in mind for the next one.