Digital Dice Roller

by DhanurvedR in Circuits > Arduino

53 Views, 1 Favorites, 0 Comments

Digital Dice Roller

page.jpg

Project Overview

This project demonstrates how to build a Digital Dice Roller using an Arduino Nano and an SSD1306 OLED display. With a press of a button, a random number appears on the screen — simulating a dice roll from 1 to 6 (or higher if using a potentiometer).

Ideal for beginners, this project introduces:

  1. I²C communication
  2. OLED graphics
  3. Random number generation
  4. Analog input handling (with potentiometer)


Supplies

Supplies.png

What You Need


  1. 1 × Arduino Nano (or Uno/Mega)
  2. 1 × SSD1306 OLED Display (I²C type, 128x64)
  3. 1 × Pushbutton
  4. 1 × 10kΩ Resistor (optional if using INPUT_PULLUP)
  5. 1 × Breadboard (optional, for prototyping)
  6. 1 × Potentiometer (optional, for adjustable range)
  7. Jumper wires

Wiring the Components

wire1.png
wire2.png

Connect the SSD1306 OLED Display (I²C)

For Arduino Nano or Uno:

  1. VCC5V
  2. GNDGND
  3. SDAA4
  4. SCLA5

For Arduino Mega:

  1. VCC5V
  2. GNDGND
  3. SDAPin 20
  4. SCLPin 21


Connect the Pushbutton

  1. One terminal of buttonGND
  2. Opposite diagonal terminalD9 (Digital Pin 9)


Connect the 10kΩ Resistor

  1. One end of resistorD9
  2. Other end of resistor5V


💡 This creates a pull-up resistor for the button. You can skip the external resistor if you use INPUT_PULLUP mode in code.


(Optional) Connect the Potentiometer (for adjustable dice range)

  1. Middle pin (wiper)A0
  2. One outer pin5V
  3. Other outer pinGND

Scan the OLED's I²C Address

Most SSD1306 OLEDs use address 0x3C, but some use 0x3D. Let’s scan it just to be sure.

Upload this scanner code:

#include <Wire.h>


void setup()
{
Wire.begin();

Serial.begin(9600);
while (!Serial);
Serial.println("\nI2C Scanner");
}


void loop()
{
byte error, address;
int nDevices;

Serial.println("Scanning...");

nDevices = 0;
for(address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();

if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");

nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");

delay(5000);
}

Open Serial Monitor

Note the address it finds

Upload the Dice Roller Code

wk1.png
wk2.png

🎲 Basic Dice Roller (Fixed Range: 1 to 6)

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int buttonPin = 9;

void setup() {
pinMode(buttonPin, INPUT_PULLUP);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
//replace 0x3C with the address obtained from the scanner.

Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
randomSeed(analogRead(0)); // Seed for random number generation

}

void loop() {
if (digitalRead(buttonPin) == LOW) {
displayCircle(); // Flash a small circle
delay(500);
int diceRoll = random(1, 7); //random number between 1 and 6
displayDice(diceRoll);
delay(1000);
clearDisplay();
}
}
//display effect
void displayCircle() {
display.clearDisplay();
display.fillCircle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 10, WHITE); // Draw a white circle
display.display();
}
//display the num
void displayDice(int number) {
display.clearDisplay();
display.setTextSize(3);
display.setTextColor(WHITE);
display.setCursor(40, 20);
display.print(number);
display.display();
}
//clear the display for next turn
void clearDisplay() {
display.clearDisplay();
display.display();
}

Try this out first before moving on to the advanced version.

Add Adjustable Max Value (Potentiometer)

t1.png
t2.png
t3.png
t4.png

Now let’s add a potentiometer to dynamically control the dice’s max value. Want a D20 or D100? You got it.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int buttonPin = 9;
const int potPin = A0;

int prevMaxValue = 0;

void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
//replace 0x3C with your correct address
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}

// Show startup message
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(5, 25);
display.println("DiceRoller");
display.display();
delay(2000); // Show message for 2 seconds

randomSeed(analogRead(0)); // Seed for random number generation
}

void loop() {
int potValue = analogRead(potPin);
int maxValue = map(potValue, 0, 1023, 2, 100);
// here, instead of 100 you can set what the maximum value of potentiometer is
// and the potentiometer will be between 1 and the value set here, instead of 100.
// eg: if instead of 100, if i put 20 the potentiometer range will be 1-20 and
// the die roll range also 1-20

if (maxValue != prevMaxValue) {
prevMaxValue = maxValue;
displayMaxValue(maxValue);
}

if (digitalRead(buttonPin) == LOW) {
displayRollingSquare(); //roll die
int diceRoll = random(1, maxValue + 1); // random number between maxvalue
displayDice(diceRoll); // die result
delay(1000);
clearDisplay();
}
}

void displayRollingSquare() {
display.clearDisplay();

// Coordinates for a tilted square (diamond shape)
int cx = SCREEN_WIDTH / 2;
int cy = SCREEN_HEIGHT / 2;
int size = 20;

display.drawLine(cx, cy - size, cx + size, cy, WHITE);
display.drawLine(cx + size, cy, cx, cy + size, WHITE);
display.drawLine(cx, cy + size, cx - size, cy, WHITE);
display.drawLine(cx - size, cy, cx, cy - size, WHITE);

display.display();
delay(1500); // dice rolling
}

void displayDice(int number) {
display.clearDisplay();

int textSize = 4;
int charWidth = 6 * textSize;
int numDigits = (number < 10) ? 1 : 2;
int textWidth = charWidth * numDigits;
int x = (SCREEN_WIDTH - textWidth) / 2;
int y = (SCREEN_HEIGHT - 8 * textSize) / 2;

display.setTextSize(textSize);
display.setTextColor(WHITE);
display.setCursor(x, y);
display.print(number);
display.display();
}


void displayMaxValue(int maxVal) {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0, 20);
display.print("Max: ");
display.print(maxVal);
display.display();
}

void clearDisplay() {
display.clearDisplay();
display.display();
}

🚀 Final Tips:


  1. Add an LED or buzzer for sound/light feedback!
  2. Want animations? Use the OLED’s graphic functions.
  3. Build a dice box with a display window!


Conclusion

This project provided a hands-on learning experience by covering core topics such as I²C communication, which allows the Arduino and OLED display to exchange data with just two wires, significantly simplifying the circuit. We also explored OLED graphics, learning to programmatically control pixels to display text and shapes, from simple numbers to rolling squares.