Projects

Toss The Dice

Movement Detecting Electronic Dice

Johann Wyss

Issue 19, February 2019

This article includes additional downloadable resources.
Please log in to access.

Log in

Retire your low-tech dice for this effective electronic dice, and learn about Arduino at the same time.

BUILD TIME: 3 HOURS
DIFFICULTY RATING: Intermediate

An electronic dice isn’t something hard to come by in today’s electronically enabled “there’s an app for that” age. However, there is a lot of fun and learning experiences to be had by taking the time to DIY. With this simple project, we make a movement detecting electronic dice that you can show off to your fellow board game enthusiasts.

THE BROAD OVERVIEW

There are many circuits around for building an electronic dice. Many of these, however, use discreet components on a large PCB, and don’t have any smarts to keep the results truly random. Many also just use a simple momentary action switch to activate the circuit.

The idea behind this electronic dice was to create something a little more interactive, both in how it is triggered and in its appearance. A 3D printed enclosure provides a tactile feel. To make it easy to pick-up, the enclosure needs to be compact, which is why there are two PCBs used.

By using a Mercury switch, we are able to trigger the circuit when you lift the dice, which is a lot more interactive than simply pressing a button. An ATtiny microcontroller was chosen because of its tiny size and low power requirements. It also makes it possible to power from a button cell battery to keep space to a minimum.

HOW IT WORKS

The device is very simple. It uses a microcontroller to randomly pick a number between 1 and 6 and then displays the result on an array of 7 LEDs arranged in a dice pattern. As an added feature, rather than using a button, I opted to incorporate a tilt switch, so when the user shakes or otherwise disrupts the dice it triggers a new result. This is done using a Mercury filled switch. When tilted, the liquid ball of mercury comes into contact with the two leads of the device, creating a circuit. This circuit is connected to ground and a pin of the microcontroller with an internal pull-up resistor activated.

Avoid breaking the glass as Mercury is a poison.

Random Function

In a previous project, I found using the analogue read to seed the random function appeared to favour higher numbers. To counter this, I created a small PCB antenna that will help to pick up the random “noise” on the floating pin, which is needed for the analogue read random seeding to work correctly. This does indeed seem to significantly increase the randomisation of the output.

To confirm this, I created a small program that uses the antenna and the analogue read seed function to record 500 loops of the results and display them to the serial output. From there, I created a histogram to check the spread of the data. This resulted in data that appears as if the result has a high level of randomisation and a fairly even distribution. Therefore, I’m fairly confident to say this device will be as random as one would expect from a dice roll.

histogram

LED Outputs

My first design used one pin of the microcontroller for each LED, which meant I needed 7 pins just for the LEDs, another pin for the Mercury switch, and another for the random seed function. This would mean I needed a microcontroller with 9 GPIO pins.

Since I wanted the final build to be compact and low power, I planned to use an ATtiny microcontroller. This meant I needed to get the pin count down to a maximum of 6 GPIO pins. To do this, I grouped the LEDs so that all six combinations can be produced using only 4 pins of a microcontroller. The following table describes which pins need to be high in order to get the associated display.

DisplayPin High
1 1
2 2
3 1 & 2
4 2 & 3
5 1, 2 & 3
6 2, 3 & 4

Power Considerations

Lower voltage versions of the ATtiny85 or ATtiny13 are recommended, which can comfortably run on input voltages down to 1.8V. Since we are running the device on a small disposable lithium coin cell, having the ability to run down to this low voltage is ideal.

It’s also important that you use standard red LEDs, as they have a forward voltage of around 1.8 volts whereas, in contrast, blue LEDs can have a forward voltage of over 3 volts. This could mean that even though your microcontroller functions happily, there is not enough voltage to illuminate the LEDs.

The Fundamental Build:

Electronic Dice Prototype

protoype
Parts Required:JaycarAltronicsCore Electronics
1 × Arduino Compatible NanoXC4414Z6372CE05101
7 × 330Ω 1/4W Resistors*RR0560R7040PRT-14490
7 × Red 5mm LEDsZD0150Z0800COM-09590
1 × Mercury Tilt SwitchSM1035S3073SEN-10289

Parts Required:

Before coming up with a PCB design, I first wanted to test the circuit on a breadboard. I chose the Arduino Nano microcontroller development platform for a few reasons.

It has a small form factor, which makes it easy to plug straight into a breadboard, and it is also relatively easy to program.

BUILDING THE PROTOTYPE

Follow the Fritzing diagram shown below to build your prototype. Be sure to insert the LEDs with the correct orientation, paying attention that the negative leg (short leg) goes to the resistor. The resistors and Mercury switch can go into the breadboard either way.

schematic

In the digital resources on our website, you’ll find the “prototype.ino” file. Load this file onto your Arduino and let it boot.

Power will be provided to the circuit via the onboard Nano, so keep it plugged into the computer or an available USB power adaptor.

For the Dice function to work you will need to tilt the breadboard to activate the Mercury switch.

THE CODE

The code is very simple for this project. It waits until the tilt switch pin is high. Once it detects this it randomly selects a number between 1 and 6 inclusive, and then it displays the results on the 7 LEDs.

Setup

int result = 1;
int trigger = 6;
int triggerState = 0;
void setup() {
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(trigger, INPUT_PULLUP);
randomSeed(analogRead(0));

Loop

void loop() {
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  triggerState = digitalRead(trigger);
  if (triggerState == HIGH){
    result = (random(1, 7));
  }
  switch(result){
    case 1:
    digitalWrite(2, HIGH);
    break;
    case 2:
    digitalWrite(3, HIGH);
    break;
    case 3:
    digitalWrite(2, HIGH);
    digitalWrite(4, HIGH);
    break;
    case 4:
    digitalWrite(4, HIGH);
    digitalWrite(3, HIGH);
    break;
    case 5:
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
    digitalWrite(4, HIGH);
    break;
    case 6:
    digitalWrite(5, HIGH);
    digitalWrite(4, HIGH);
    digitalWrite(3, HIGH);
    break;
  }
  delay(50);

The Main Build:

Electronic Dice

dice housing
Additional Parts Required:JaycarAltronicsCore Electronics
1 × ATtiny85ZZ8721Z5105COM-09378
1 × CR2032 Lithium BatterySB2944S4999BCE00276
1 × CR2032 Battery Holder-S5056PRT-00783
1 × 8-pin IC SocketPI6500P0550PRT-07937
1 × Header Terminal StripHM3212P5430FIT0084
1 × Header Socket StripHM3230P5390ADA3008
1 × Miniature Slide SwitchSS0852S2010PRT-14330
1 × Pack of Mixed Jumper LeadsWC6027P1017PRT-14284

Additional Parts Required:

Note 1: For this device, I used the CR2032 holder from Core Electronics. Whilst the distance between the pins is the same between the components, I can’t confirm the item from Altronics will fit the PCB layout.

Note 2: This device will work with either the ATtiny85 or the ATtiny13 and the program works on both without modification. However, to ensure the maximum possible runtime from the small CR2032 battery I highly recommend using the low power variants such as the ATtiny85v or the ATtiny13a. Either will work perfectly fine with the code but have the added benefit of running on voltages as low as 1.8V (at 1MHz) which is also the CR2032’s dropout voltage.

The final build has two PCBs to keep it compact. These are single sided to keep things easy as well.

I opted to design the PCBs so they can easily be etched using the toner transfer method, sent to a professional PCB manufacturing company or, in our case, milled using a Bantam Tools Desktop PCB Milling Machine. The Eagle board files, along with custom Gerber files, can be found in the Resources section on our website.

The boards were designed using EagleCAD and consist of two single sided 45mm PCBs designed to stack on top of each other. This makes it easy to etch and mill.

milled boards

If you mill your own, or you’re having your PCBs commercially produced, you will need to check your PCB for broken tracks, corrosion, or other manufacturing defects. Give it a good clean with some isopropyl alcohol or circuit board cleaner, to help remove any grease or residue that may exist. This will help reduce the incidence of dry joints and other problems.

Use the lowest temperature possible for the solder you’re using, to help avoid overheating the PCB and components, which can be easily damaged with excessive heat. Using a little extra flux can also aid in making a reliable solder joint. I used the NS3036 flux pen from Jaycar, which is easy to clean with isopropyl alcohol once you've finished.

As with all PCB builds, we follow a hardware, passives, semiconductors type construction pattern. Installing the headers on the boards will be a little different though seeing that these go under the board, in order for the boards to sandwich together.

TOP BOARD

top board

For the top PCB, install the resistors, followed by the 7 LEDs. Pay attention to the polarity of the LEDs, making sure they are in the correct way.

5 pin header

Next, we need to solder the two 5-pin header strips onto the tracks side of the board. Carefully solder those on the board by installing them in reverse (longer side towards the board) so you have room to solder. Using a small screwdriver you can gently push the plastic part down towards the solder pads. Repeat this for the second 5-pin header strip.

schematic

BOTTOM BOARD

bottom board

Start with the IC socket, battery holder, and the 2 pin header. Next, carefully solder in the Mercury switch.

The Mercury switch I used had a lot of oxidation on the leads, and as such, wouldn’t take solder. I needed to use fine sandpaper to scuff the oxidation off the surface before soldering. If you don’t have sandpaper you could carefully use a hobby knife or 3M scotch pad to scrape the leads.

Next, we need to solder the two 5-pin socket strips onto the tracks side of the board. Carefully hold them up a few millimetres so you can get solder onto the pins and solder pad. Repeat this for the second 5-pin socket strip.

Now that both boards have been soldered, you need to check for accidental solder bridges or poor solder joints. The solder joints should be smooth and clean, and not look dry or cracked. Ensure that you haven’t accidentally bridged any solder pads or tracks together. Using a multimeter in continuity mode is a great way to check. Remove any solder bridges using a clean hot iron, but be careful not to lift any tracks.

schematic

SLIDE SWITCH

slide switch

We next need to prepare the slide switch wiring.

Take two jumper leads with sockets at one end and cut them to about 60mm long. Strip the end about 5mm to expose the inner conductor, which you can solder to the switch. One wire to the centre pin, and the other to an outside pin.

You will need to put the switch with its wiring aside until you construct the case.

PROGRAM

Finally, you need to program the ATtiny using the following code, and then insert into the IC socket, paying attention to put it in the correct orientation.

If you are unfamiliar with how to program the ATtiny, we recommend you build our 'ATDEV for ATtiny' project described in Issue 14. Our 'Programming the ATtiny85' article in Issue 9 is another great source of information.

THE CODE

The code for the final device is almost identical to the prototype with only a couple of small changes. Firstly, the output pins need to change to reflect the ATtiny output pins.

In our prototype, the mercury switch was pointing up, but since the mercury switch points down on the PCB we need to change the code so that it triggers when the trigger pin is pulled low instead of high.

Setup

int result = 1;
int trigger = 0;
int triggerState = 0;
int seed = 1;
void setup() {
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(trigger, INPUT_PULLUP);
  randomSeed(analogRead(0));

Loop

void loop() {
  digitalWrite(1, LOW);
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  triggerState = digitalRead(trigger);
  if (triggerState == LOW){
    result = (random(1, 7));
  }
  switch(result){
    case 1:
    digitalWrite(1, HIGH); 
    break;
    case 2: 
    digitalWrite(2, HIGH); 
    break;
    case 3: digitalWrite(2, HIGH); 
    digitalWrite(1, HIGH); 
    break;
    case 4: digitalWrite(2, HIGH); 
    digitalWrite(4, HIGH); 
    break;
    case 5: digitalWrite(2, HIGH); 
    digitalWrite(1, HIGH); 
    digitalWrite(4, HIGH); 
    break;
    case 6: 
    digitalWrite(2, HIGH); 
    digitalWrite(3, HIGH);
    digitalWrite(4, HIGH);
    break;
  }
  delay(50);
all the parts

3D PRINTED ENCLOSURE

3d enclosure

The 3D print files for the base and top pieces are available for download from the Resources section of our website.

The case has been designed to allow both pieces to connect to one another by means of a friction fit. This enables the user to easily remove the bottom cover to gain access to the battery compartment and replace the CR2032 lithium cell. Both pieces should be printed face down and neither requires any support material when printed in this orientation.

Given the device is designed to be opened many times, I would suggest using an ABS material. I find PLA tends to be too brittle for functional parts unless you use strength modifiers. Of course, your mileage may vary depending on the 3D printing filament you use and your temperatures, etc.

FINAL ASSEMBLY

put together

Align the header pins and sockets on the top and bottom boards and gently push the boards together.

The switch is designed to friction fit in the slot on the case with the bottom PCB sitting just under the switch's legs.

Gently slide in the joined PCBs into the housing. These should friction fit into place.

Insert the button battery and check that the dice works. If it works you can close the lid. It should friction fit.

TESTING

There is no way to actually test this device without using it for real. Lucky for me, I have a nice collection of board games at my disposal, and can confirm that after several games the dice worked perfectly well. I trust your dice does as well. If not, you will need to double-check that you have a fresh battery, that the components are in correctly, and that the solder joints are reliable. Then gently close the lid.

dice working

WHERE TO FROM HERE?

There are a few things that come to mind that could easily improve the design.

To make the dice more “realistic”, you could modify the code to simulate a rolling die before landing on the final number. Rather than stopping at the final result in the current design, have it display 4 or so results for a short duration before showing the final number.

You could switch out the button cell for a rechargeable lithium cell and a TP4056 charger. Whilst CR2032’s batteries are not expensive they are limited in power because of their size.

You could consider replacing the LEDs with a small LCD or OLED screen, and reprogram to toggle between a single or multiple dice, or even dice with more than 6 sides.

Happy gaming!

AN IMPORTANT NOTE ABOUT BUTTON CELLS: Coin cell lithium batteries can be lethal if ingested, so please keep this device out of reach from young children. If you suspect a child has ingested a lithium cell seek emergency medical treatment immediately!