CIRC
15
.:Dice Simulator:.
.:1d6 on 6 LEDs:.
(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 LED x6 |
Wire | 560 Ohm Resistor Green-Blue-Brown x6 |
2.2k Ohm Resistor Red-Red-Red |
||||
Pushbutton |
Schematic
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.