Project showcase
The Dicer

The Dicer © GPL3+

Have some fun using this handy box with shuffle and counting abilities, supported by 8-bit sound effects.

  • 998 views
  • 0 comments
  • 4 respects

Components and supplies

Ard nano
Arduino Nano R3
×1
Shift Register 74HC595
×5
Mfr 25frf52 10k sml
Resistor 10k ohm
×40
Mfr 25frf52 1k sml
Resistor 1k ohm
×6
Resistor 2.7k ohm
×3
Resistor 3.3k ohm
×3
Resistor 5.1k ohm
×3
Mfr 25frf52 100r sml
Resistor 100 ohm
×1
Diode Led White 5mm
×35
Diode Led Red 5mm
×5
Lever arch switch
×5
Momentary button
×2
On/off button
×2
Passive Buzzer
×1

Necessary tools and machines

Soldering Station
Drill

About this project

This is my first project with Arduino onboard. This idea suddenly appeared in my head and I decided to make it happen. For the first time I was also soldering components and making a wooden box, which also has brought me a lot of joy :-) The wooden box is called "The Dicer" and is used mainly… for throwing dices.

The first step was to create wooden front panel to make holes for LEDs, arch switches and arcade ones.

Success! No failure on visible side. Next step was soldering shift registers and resistors and other elements.

On the front panel we can see 5 groups of 7 white LEDs that simulate throwing the dices. But not only that - it can also be used to count the points and shuffle bigger numbers.

The whole thing can be controlled by 5 lever arch switches, two large momentary buttons and two of ON/OFF type. Between the buttons are 5 red LEDs, which depending on the mode will inform (1) which dice is active (2) the current slot to allocate points (3) position in configuration menu

The blue button is responsible for sound. Black turns battery power. Yellow is used to change the settings or clearing results. Green is used to draw the dices and award points.

Below you can see a demonstration of rolling all 5 dices up to 3 times to get a resulting 1 pair.

Rolling a dices

You can shuffle one or two dices for most common board games. The longer the press the longer count down to finalize throw. You can press it as long as you want but buzzer at some point will generate same high frequency. So beside Random() and randomSeed() on analog pin user have control to shuffle longer to get more random result. Sound is generated without delay() function using millis() to not block any other processes.

Turning on device automatically goes into shuffle dice game mode. To change settings all lever switches must be in down position and Yellow button pressed. With Dicer we can shuffle from 1 to 5 dices, set max value on all dices from range 2-7. We can also set independent (default) or unique values. Unique values may be used to decide who will start the game without a draw. You may also do in-home lottery, e.g. get 3 balls with values of range 1-7 without repeating.

The other game mode is to score points. In this video we can score up to 7 points for 5 people. Beside video, we can also change to score 20 points per slot. We can also get up to 2 last slot to work as dice with cost of slot for players. Theoretically posibilites are limitless.

Scoring a points.

The other mode is to shuffle one number from 1 to 35. May be used to random one person from 35 (or less) to win lottery or something (no video for this mode)

On the last video you can see demo LEDs.

Demo

Code

Control Four Switches non-exclusive with just one analog pinArduino
Right use of 5 resistors combinantion allow you to detect four switches non-exclusive. Assuming you are using 3 sets of such setting covers up to 12 switches which is more than enough for this project.

Each of 3 sets works as below:
- we put positive "+" current (5V) to each resistors: 1k ohm, 2.7k ohm, 3.3k ohm and 5.1k ohm.
- each resistor is connected to switch (on/off or momentary)
- after switches we are merging all 4 lines into resistor 1k ohm
- before 1k ohm resistor we take line into analog input
- after 1k ohm resistor we put it to the ground (GND)

Pressing buttons is changing resistances in this parallel scheme in non-random way so the result can be extraced as 4-bit value.
byte fourValues[3]; //results from 3 analog pins from 0-1023 as 0-15
byte switches[12]; //easy way to access state on 12 buttons
	
//reads analog values with specified resistors set
byte analogToDecimal(int value) {
  
//those values of 0-1023 are enough unique to proper read resistance of 4 channels / switches non-exclusive.
  int data[] = {83, 202, 256, 307, 354, 390, 443, 493, 534, 567, 585, 602, 619, 632, 653, 9999};
  
  //below there is no mistake in order of 1,2,4,3 and 10,12,11,13... it's just how resistance works in this set
  int result[] = {0, 1, 2, 4, 3, 5, 6, 7, 8, 9, 10, 12, 11, 13, 14, 15};
  for (byte i = 0; i < 16; i++) if (value < data[i]) return result[i];
}

void setSwitches(byte n, byte swA, byte swB, byte swC, byte swD) {
  switches[(n - 1) * 4] = swA;
  switches[(n - 1) * 4 + 1] = swB;
  switches[(n - 1) * 4 + 2] = swC;
  switches[(n - 1) * 4 + 3] = swD;
}

void updateAnalog() {
	fourValues[0] = analogToDecimal(analogRead(buttonAnalogPin1));
	fourValues[1] = analogToDecimal(analogRead(buttonAnalogPin2));
	fourValues[2] = analogToDecimal(analogRead(buttonAnalogPin3));
		
	// 3 decimal into 12 binary
	for (int i = 1; i <= 3; i++) {
		if (fourValues[i - 1] == 0) setSwitches(i, 0, 0, 0, 0);
		if (fourValues[i - 1] == 1) setSwitches(i, 0, 0, 0, 1);
		if (fourValues[i - 1] == 2) setSwitches(i, 0, 0, 1, 0);
		if (fourValues[i - 1] == 3) setSwitches(i, 0, 0, 1, 1);
		if (fourValues[i - 1] == 4) setSwitches(i, 0, 1, 0, 0);
		if (fourValues[i - 1] == 5) setSwitches(i, 0, 1, 0, 1);
		if (fourValues[i - 1] == 6) setSwitches(i, 0, 1, 1, 0);
		if (fourValues[i - 1] == 7) setSwitches(i, 0, 1, 1, 1);
		if (fourValues[i - 1] == 8) setSwitches(i, 1, 0, 0, 0);
		if (fourValues[i - 1] == 9) setSwitches(i, 1, 0, 0, 1);
		if (fourValues[i - 1] == 10) setSwitches(i, 1, 0, 1, 0);
		if (fourValues[i - 1] == 11) setSwitches(i, 1, 0, 1, 1);
		if (fourValues[i - 1] == 12) setSwitches(i, 1, 1, 0, 0);
		if (fourValues[i - 1] == 13) setSwitches(i, 1, 1, 0, 1);
		if (fourValues[i - 1] == 14) setSwitches(i, 1, 1, 1, 0);
		if (fourValues[i - 1] == 15) setSwitches(i, 1, 1, 1, 1);
	}
		
}

void update() {
		updateAnalog();
}
5 Shift registers daisy chained to control 40 Leds.Arduino
By using 5 shift registers 74HC595 we can control 40 outputs with just 3 pins on arduino board.
When we will understand the mechanics behind it, it is very simple to reuse with another projects
#define SHIFT_REGISTERS 5
#define REGISTER_OUTPUT_PINS 8
#define SLOTS 40

byte shifterLatchPin = 8; //latch pin used to daisy chain shift registers
byte shifterClockPin = 12; //clock pin used to daisy chain shift registers
byte shifterDataPin 11; //data pin used to daisy chain shift registers

byte slots[SLOTS]; //outputs from shift registers daisy chained
	//0 - disabled
	//1 - enabled

void updateSlots() {
		
	digitalWrite(shifterLatchPin, LOW);
	for (int i = SHIFT_REGISTERS - 1; i >= 0; i--) {
		byte n = 0; //value 0-255 to send into shifter
		byte m = 1; //multiplication of 2
    
		for (byte j = 0; j < REGISTER_OUTPUT_PINS; j++) {
			byte slotValue = slots[i * 8 + j];
			if (slotValue == 1) {
				n += m;
			}
			m = m * 2;
		}
			
		shiftOut(shifterDataPin, shifterClockPin, MSBFIRST, n);
	}
	digitalWrite(shifterLatchPin, HIGH);
}

void setup() {
		pinMode(shifterLatchPin, OUTPUT);
		pinMode(shifterClockPin, OUTPUT);
		pinMode(shifterDataPin, OUTPUT);
}

void update() {
  
  //at some points we will change slots array with zeros & ones to light proper LEDs.
  for (byte i=0; i<40; i++) slots[i] = random(2); //0 or 1
  
  //after that we will update slots.
  updateSlots();
}
Blinking Leds with no delay() functionArduino
With just simple mod (%) operator we can take millis() into action and specify if this is the right time ON state, or OFF state.
//state ON for 500ms, state OFF for 500ms, repeat.
int blinkSlowInterval = 500; 

//state ON for 100ms, state OFF for 100ms, repeat.
int blinkFastInterval = 100;

//state ON for 1900ms, state OFF for 100ms, repeat.
int blinkAstillInterval = 1000;
	
bool blinkSlow;
bool blinkFast;
bool blinkAstill;

void updateBlinks() {
	unsigned long t = millis();
	blinkSlow = (t % (blinkSlowInterval * 2) < blinkSlowInterval) ? true : false;
	blinkFast = (t % (blinkFastInterval * 2) < blinkFastInterval) ? true : false;
	blinkAstill = (t % (blinkAstillInterval * 2) < (int)(blinkAstillInterval * 1.9)) ? true : false;
}

void update() {
  updateBlinks();
}
Play melody on your buzzerArduino
I have barely used this function here to emulate menu clicks but can be exhanced to give more length to it.

The idea is to create array of 2 values : note & duration.

The note represents C4-C7 frequnecy, while duration tell us for how long this should sound.
#define MAX_MELODY_LENGTH 100

byte buzzerPin = 7;

unsigned long melodyStartTime;
unsigned long melodyCurrentTime;
bool melodyStarted;
byte melodyPosition;
byte lastMelodyPosition;

int notes[37]; //stores all notes frequency from C4 to C7 inclusive
	
//current frequnecy
int buzzerFreq;

//each member of array contains two values: note & duration
int melody[MAX_MELODY_LENGTH][2];

//clear melody data
void readyMelody() {
	for(int i=0; i<MAX_MELODY_LENGTH; i++) {
		melody[i][0] = 0;
		melody[i][1] = 0;
	}
	melodyPosition = 1;
	lastMelodyPosition = -1;
}

void updateMelody() {
		if(melodyStarted == true) {
			
			melodyCurrentTime = millis();
			unsigned long elapsedTime = melodyCurrentTime - melodyStartTime;
			
			if(ENABLE_SERIAL == true) {
				Serial.print("Elapsed: ");
				Serial.println(elapsedTime);
			}
			
			int intervalStart;
			int intervalEnd;
			
			for(byte i=0; i<MAX_MELODY_LENGTH; i++) {
				if(i == 0) {
					intervalStart = 0;
					intervalEnd = melody[i][1];
				}
				else {
					intervalStart = melody[i-1][1] + 1;
					intervalEnd = melody[i][1];
				}
				
				if(melody[i][1] == 0) {
					//melody has ended
					melodyStarted = false;
					noSound();
					if(ENABLE_SERIAL == true) {
						Serial.println("Melody Finished!");
					}
					busy = false;
					break;
				}
				else {
					if(elapsedTime >= intervalStart && elapsedTime <= intervalEnd) {
						melodyPosition = i+1;
						if(lastMelodyPosition == -1 || melodyPosition != lastMelodyPosition) {
							
							if(ENABLE_SERIAL == true) {
								Serial.print("Curr Interval (");
								Serial.print(i+1);
								Serial.print("): ");
								Serial.print(intervalStart);
								Serial.print("-");
								Serial.println(intervalEnd);
							}
							
							//handle melody here
							if(melody[i][0] > 0) { //play note
							  tone(buzzerPin, getFrequncyById(melody[i][0]));
							}
							else { //play silence
								noTone(buzzerPin);
							}
							
							lastMelodyPosition = melodyPosition;
						}
						break;
					}
				}
				
				
			}
			
			
		}
	}

//filling global melody variable with predefined set of notes and it's durations {note, duration}
// if note equal 0 its stands as silence
// if duration equal 0 it's a sign to end melody
void playMelody() {
		if(melodyStarted == false) {
			readyMelody();
			int sum = 0;
			
			//yellow menu click
				int m[][2] = {
					{25, 100}, {0, 50}, {25, 100}, {0, 50}, {32, 100}
				};
				
				byte msize = sizeof(m) / sizeof(int);
				for(byte i=0; i < (int)(msize / 2); i++) { 
					melody[i][0] = m[i][0]; 
					sum += m[i][1]; 
					melody[i][1] = sum; 
				}
			}
			
			melodyStartTime = millis();
			melodyStarted = true;
		}
	}

void update() {
  updateMelody(); 
  
  
  //at some point you will want to play you melody
  //...
  playMelody();
  
  
}

void setup() {
  
  pinMode(buzzerPin, OUTPUT);
  
  notes[0] = 262; // 1 C4
  notes[1] = 277; // 2 C#4
  notes[2] = 294; // 3 D4
  notes[3] = 311; // 4 D#4
  notes[4] = 330; // 5 E4
  notes[5] = 349; // 6 F4
  notes[6] = 370; // 7 F#4
  notes[7] = 392; // 8 G4
  notes[8] = 415; // 9 G#4
  notes[9] = 440; // 10 A4
  notes[10] = 466; // 11 A#4
  notes[11] = 494; // 12 H4
  notes[12] = 523; // 13 C5
  notes[13] = 554; // 14 C#5
  notes[14] = 587; // 15 D5
  notes[15] = 622; // 16 D#5
  notes[16] = 659; // 17 E5
  notes[17] = 698; // 18 F5
  notes[18] = 740; // 19 F#5
  notes[19] = 784; // 20 G5
  notes[20] = 831; // 21 G#5
  notes[21] = 880; // 22 A5
  notes[22] = 932; // 23 A#5
  notes[23] = 988; // 24 H5
  notes[24] = 1047; // 25 C6
  notes[25] = 1109; // 26 C#6
  notes[26] = 1175; // 27 D6
  notes[27] = 1245; // 28 D#6
  notes[28] = 1319; // 29 E6
  notes[29] = 1397; // 30 F6
  notes[30] = 1480; // 31 F#6
  notes[31] = 1568; // 32 G6
  notes[32] = 1661; // 33 G#6
  notes[33] = 1760; // 34 A6
  notes[34] = 1865; // 35 A#6
  notes[35] = 1976; // 36 H6
  notes[36] = 2093; // 37 C7
  
  currNote = 13; //1-37
	buzzerFreq = getFrequncyById(currNote);
}

int getFrequncyById(byte id) {
	return notes[id-1];
}

Schematics

Dicer Schematic
Describes used connections
Dicer fedyun39lr

Comments

Similar projects you might like

Soldering Iron Controller for Hakko 907

Project tutorial by Alexander

  • 30,914 views
  • 22 comments
  • 69 respects

Arduino-Based Shower Cabin FM Radio

Project tutorial by Saulius Bandzevičius

  • 7,708 views
  • 2 comments
  • 31 respects

Cockroach Laser Killer

Project showcase by NerdFatherRJ

  • 7,607 views
  • 4 comments
  • 12 respects

RCar | Robots for All!

Project tutorial by Luís Rita

  • 5,611 views
  • 1 comment
  • 38 respects

Arduino Variable Gain Amplifier

Project showcase by lucian_vdo

  • 2,016 views
  • 1 comment
  • 6 respects

sC00p-4-b1l1tY Meter

Project showcase by Team sC00p-4-b1l1tY

  • 686 views
  • 2 comments
  • 1 respect
Add projectSign up / Login