CIRC
15

.:Dice Simulator:.
.:1d6 on 6 LEDs:.

1d6 die simulator

(ARDX) .:Arduino Experimentation Kit:. (ARDX)

What We're Doing

When a button is pressed, display a short animation sequence on six LEDs, then light a random number of LEDs to simulate rolling a single 6 side die.

This shows a few methods that can be used to light the correct LEDs.

The Circuit

The Parts

5mm Green LED 5mm LED
x6
wire Wire resistor 560 Ohm Resistor
Green-Blue-Brown
x6
resistor 2.2k Ohm Resistor
Red-Red-Red
resistor Pushbutton

Schematic

Resources

.:download:.

Fritzing diagram
https://wcrsyyc.github.io/ardx/fritzing/CIRC15.fzz

Code (no need to type everything in just)

Download the Code from ( https://wcrsyyc.github.io/ardx/code/CIRC15-code.txt )
(and then copy the text and paste it into an empty Arduino Sketch)

/*
 Arduino Dice :)

 Simulate throwing a dice (1d6), and displaying the result using 6 LEDs.

 The circuit:
 * 6 LEDs attached to consecutive digital pins (with 560 Ohm current limiting resistors)
 * button (switch) connected to a digital pin

 Created 26 Jan 2017
 By H Phil Duby

 Adapted from https://www.hackster.io/EvdS/led-dice-885cf1
 By Esther van der Stappen

 This code is in the public domain.
 */

// set to 1 if we're debugging
#define DEBUG 0

// Set the die rolling animation speed (smaller is faster)
const long ANIM_WAIT = 100; // milliseconds (0.1 seconds)
const int IS_PRESSED = LOW; // Pullup resistor makes normal (not pressed) value HIGH

// 6 consecutive digital pins for the LEDs
const int first = 2;
const int second = 3;
const int third = 4;
const int fourth = 5;
const int fifth = 6;
const int sixth = 7;

// pin for the button to trigger a die roll
const int rollBtn = 12;

void setup() {
  // set all LED pins to OUTPUT
  for ( int  i = first; i <= sixth; i++ ) {
    pinMode ( i, OUTPUT );
  }
  // set button pin to INPUT, and use internal pullup resistor
  pinMode ( rollBtn, INPUT_PULLUP );

  // initialize random seed by noise from analog pin 0 (should be unconnected)
  randomSeed ( analogRead ( 0 ));

  // if we're debugging, connect to serial
  #ifdef DEBUG
    Serial.begin ( 9600 );
  #endif
}

void loop()
{
  // Declare local variables
  int dieResult;
  int btnState;

  btnState = digitalRead ( rollBtn ); // Check button

  if ( btnState == IS_PRESSED ) { // is button currently pressed?
    setAllLEDs ( LOW ); // remove previous number

    // Different ways to animate the wait for the roll
    animateDieRolling();
//    animateWithMemory();

    dieResult = roll1d6();

    // Different ways to turn on the LEDs that show the result
    showDieByIf ( dieResult );
//    showDieBySwitch ( dieResult );
//    showDieByFor( dieResult );
  }
}// ./void loop()

/**
 * light individual LEDs from left to right and back to build up tension while
 * waiting for the dice to be thrown.
 */
void animateDieRolling()
{
  // left to right
  for ( int i = first; i <= sixth; i++ ) {
    if ( i != first ) {
      digitalWrite ( i - 1, LOW );
    }
    digitalWrite ( i, HIGH );
    delay ( ANIM_WAIT );
  }
  // right to left
  for ( int i = sixth; i >= first; i-- ) {
    if ( i != sixth ) {
      digitalWrite ( i + 1, LOW );
    }
    digitalWrite ( i, HIGH );
    delay ( ANIM_WAIT );
  }
}// ./void animateDieRolling()

/**
 * Remember the pin number for the LED being turned ON, then use that to turn
 * it OFF again when turn the next one ON
 */
void animateWithMemory()
{
  int prevLed = sixth;
  // left to right
  for ( int i = first; i <= sixth; i++ ) {
    digitalWrite ( prevLed, LOW ); // Turn previous LED OFF
    digitalWrite ( i, HIGH ); // Turn current LED ON
    prevLed = i; // Remember the pin for the currently ON LED
    delay ( ANIM_WAIT );
  }
  // right to left
  for ( int i = sixth; i >= first; i-- ) {
    digitalWrite ( prevLed, LOW ); // Turn previous LED OFF
    digitalWrite ( i, HIGH ); // Turn current LED ON
    prevLed = i; // Remember the pin for the currently ON LED
    delay ( ANIM_WAIT );
  }
  // This leaves the final (first) LED on, but that is OK.  It will always be
  // Turned on any when displaying the roll result
//  digitalWrite ( prevLed, LOW ); // Turn final LED OFF
}// ./void animateWithMemory()

/**
 * Use if statements to decide whether to turn ON each LED.  The first is always
 * turned ON.
 *
 * @param number the 1d6 value to display
 */
void showDieByIf( int number )
{
  digitalWrite ( first, HIGH );
  if ( number >= 2 ) {
    digitalWrite(second, HIGH );
  }
  if ( number >= 3 ) {
    digitalWrite ( third, HIGH );
  }
  if ( number >= 4 ) {
    digitalWrite ( fourth, HIGH );
  }
  if ( number >= 5 ) {
    digitalWrite ( fifth, HIGH );
  }
  if ( number == 6 ) {
    digitalWrite ( sixth, HIGH );
  }
}// ./void showDieByIf( int number )

/**
 * Use a switch statement to pick the highest LED pin number to set, then turn
 * it and all lower pin numbers ON
 *
 * @param number the 1d6 value to display
 */
void showDieBySwitch( int number )
{
  // When not using 'break' at the end of each case, all of the cases following
  // the matched one are executed as well.
  switch ( number ) {
  case 6:
    digitalWrite ( sixth, HIGH );
  case 5:
    digitalWrite ( fifth, HIGH );
  case 4:
    digitalWrite ( fourth, HIGH );
  case 3:
    digitalWrite ( third, HIGH );
  case 2:
    digitalWrite ( second, HIGH );
  }
  digitalWrite ( first, HIGH ); // Always at least one
}// ./void showDieBySwitch( int number )

/**
 * Use a for loop to sequence through the LED pin numbers to be turned ON
 *
 * @param number the 1d6 value to display
 */
void showDieByFor( int number )
{
  // Turn on the first 'number' LEDs
  for ( int i = first; i < first + number; i++ ) {
    digitalWrite ( i, HIGH );
  }
}// ./void showDieByFor( int number )

/**
 * generate a random 1d6 value
 *
 * @return random 1d6 value
 */
int roll1d6()
{
  // get a random number in the range [1,6]
  int random1d6 = random ( 1, 7 );

  #ifdef DEBUG
    Serial.println ( random1d6 );
  #endif

  return random1d6;
}// ./int roll1d6()

/**
 * Set all LEDs to a single state
 *
 * @param value the state to set the pins to
 */
void setAllLEDs( int value )
{
  for ( int i = first; i <= sixth; i++ ) {
    digitalWrite ( i, value );
  }
}// ./void setAllLEDs( int value )
		

Not Working? 3 things to try

Some LEDs Fail to Light

It is easy to insert an LED backwards. Check the LEDs that aren't working and ensure they the right way around.

Check that the ground wire is install. Connecting all of the current limiting resistors to the ground (blue) line on the breadboard is not (quite) enough. The line also needs to be connected to one of the ground pins on the Arduino board.

Button does nothing

Some of the push button switches are square. Try removing it, rotating it 1 quarter turn, and inserting it again.

Some LEDs dimmer

Make sure that the value of the current limiting resistor connected to the LED is the right value. Different values will work, but using the same value for all of the LEDs should keep them about the same brightness.

Making it Better?

Better animations:

The current animation just 'runs' a single LED up and back across the string of six. See the code in CIRC-02 for ideas of other possible patterns. That has a string of 8 LEDs, but minor changes will let similar patterns be used here.

With the dice simulation code as an example, another animation could randomly blink the LEDs.

void animateRandomLed()
{
  int randomLed;
  for ( int i = 0; i < 15; i++ ) {
    randomLed = random ( 2, 8 ); // Lowest to one above highest LED pin number
    digitalWrite ( randomLed, HIGH );
    delay ( ANIM_WAIT );
    digitalWrite ( randomLed, LOW );
  }
}// ./void animateRandomLed()

Once more than one animation pattern has been define, the one to use could be selected randomly

void animateRandomPick()
{
  unsigned int animPick = random ( 0, 2 ); // 0 to number of animations to choose from
  switch ( animPick ) {
    case 0:
      animateRandomLed();
      break;
    case 1:
      animateWithMemory();
			break;
		// add more cases and animation function calls
  }
}// ./void animateRandomPick()

Change animation speed:

The time between steps of the tension building animation can be changed. Currently all of the animations use "ANIM_WAIT" to control the speed. Changing that will change the speed. The delays used though do not have to be all the same, even within a single animation. The initial simple run up and down could be change to slow down as at gets near the end. Change each of the delay calls in animateWithMemory to:

delay ( animWaIT );
animWaIT += animStep;

and after "int prevLed = sixth;" at the start of the function, add:

unsigned long animWaIT = 30;
unsigned long animStep = 30;

Each of the above values can be changed to set how fast the animation starts, and how fast it slows down as it progresses.

Simulate different dice sizes:

Add more LEDs, and change the code to simulate different numbers of dice sides. 1d8, 1d10, etc. Change the code that does the animations, as well as the code that calculates and displays the roll result. If you want to try 1d20, you probably want to look at CIRC-05 first. Using a shift register will allow more LEDs to be controlled using fewer pins. Multiple shift registers can be chained together to control even more LEDs using only the pins needed for a single 74HC595.