WS2812 matrix dice toy

The showcase of this post is calculating the conversion of a number to a pip pattern, making it scalable for larger projects.

The trivial part of this post is lighting the WS2812 in a dice roll pattern. A "roll" would take one line, a lookup table would take one array, and a button press would take one line.

sketch.ino
// DICE FOR WS2812 3x7 MATRIX xfpd

bool debug = 1; // "1" for serial monitor output

/*
  PIXEL INDEXING FOR DICE PIPS
  DIE MULTIPLIER (d)          0 * 4           1 * 4
  ROW MULTIPLIER (r) 0 * 7 | 00 .. 02 | 03 | 04 .. 06 |
  ROW MULTIPLIER (r) 1 * 7 | 07 08 09 | 10 | 11 12 13 |
  ROW MULTIPLIER (r) 2 * 7 | 14 .. 16 | 17 | 18 .. 20 |
  COLUMN INDEX   (c)         +0 +1 +2        +4 +5 +6
*/

#include <Adafruit_NeoPixel.h> // https://github.com/adafruit/Adafruit_NeoPixel
#define PIN  4 // Neopixel pin
#define PIX 21 // Number of Neopixels
Adafruit_NeoPixel led = Adafruit_NeoPixel(PIX, PIN, NEO_GRB + NEO_KHZ800);
byte buttonPin = 2;
byte die[2]; // two dice

byte dieface[] = { // binary value for each row of pips
  0, 2, 0, // 1 000 010 000
  1, 0, 4, // 2 001 000 100
  1, 2, 4, // 3 001 010 100
  5, 0, 5, // 4 101 000 101
  5, 2, 5, // 5 101 010 101
  5, 5, 5  // 6 101 101 101
};

#define ORG 255, 128, 0
#define PIP   0, 255, 0
#define COLOR ORG

void setup() {
  if (debug) Serial.begin(115200); // initialize serial communications
  randomSeed(analogRead(A0)); // initialize pseudorandomness
  pinMode(buttonPin, INPUT_PULLUP); // button to roll dice

  led.begin(); // initialize Neopixel object/instance
  led.clear(); // clear pixel buffer
  divider(); // show dice divider
  led.show();  // display pixel buffer
}

void loop() {
  while (digitalRead(buttonPin)); // press button to roll dice
  delay(150); // debounce button
  led.clear(); // clear matrix
  divider(); // show dice divider
  roll(); // roll the dice
  led.show(); // display dice and divider
}

void divider() { // color middle column
  for (int i = 0; i < 3; i++) { // three LEDs
    led.setPixelColor(i * 7 + 3, led.Color(COLOR)); // any color
  }
}

void roll() { // d = die multiplier, r = row multiplier, c = column/bit index
  if (debug) Serial.println(); // separate rolls
  for (int d  = 0; d < 2; d++) { // roll two dice
    die[d] = random(0, 6); // face value of each die from 1 to 6
    for (int r = 0; r < 3; r++) { // three binary value rows per face
      if (debug) if (d) Serial.print("    "); // offset second die
      for (int c = 0; c < 3; c++) { // three bits per row
        bool pip = bitRead(dieface[die[d] * 3 + r], 2 - c); // each bit, MSB first
        if (debug) Serial.print(pip); // print pips
        if (pip)  // if bit is set...
          led.setPixelColor(d * 4 + r * 7 + c, led.Color(PIP)); // ...color pixel (PIXEL INDEXING)
      }
      if (debug) Serial.println(); // separate each die
    }
  }
}

diagram.json for wokwi.com
{
  "version": 1,
  "author": "foreignpigdog x",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": -4.8, "left": -0.5, "attrs": {} },
    {
      "type": "wokwi-neopixel-matrix",
      "id": "ring1",
      "top": -125.64,
      "left": 3.09,
      "attrs": { "pixleate": "1", "rows": "3", "cols": "7" }
    },
    { "type": "wokwi-vcc", "id": "vcc1", "top": -95.24, "left": -19.2, "attrs": {} },
    { "type": "wokwi-gnd", "id": "gnd1", "top": 0, "left": -19.8, "attrs": {} },
    {
      "type": "wokwi-resistor",
      "id": "r1",
      "top": -24.55,
      "left": 8.2,
      "rotate": 180,
      "attrs": { "value": "470" }
    },
    { "type": "wokwi-text", "id": "text1", "top": -48, "left": 192, "attrs": { "text": "ROLL" } },
    {
      "type": "wokwi-gate-and-2",
      "id": "and1",
      "top": -47.6,
      "left": -105.6,
      "rotate": 180,
      "attrs": {}
    },
    {
      "type": "wokwi-text",
      "id": "text3",
      "top": -38.4,
      "left": -67.2,
      "attrs": { "text": "E-cap" }
    },
    {
      "type": "wokwi-text",
      "id": "text2",
      "top": -48,
      "left": -76.8,
      "attrs": { "text": "1000uF" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn2",
      "top": -51.4,
      "left": 124.8,
      "attrs": { "color": "yellow", "xray": "1" }
    }
  ],
  "connections": [
    [ "gnd1:GND", "ring1:GND", "black", [ "v-9.6", "h-105.6" ] ],
    [ "vcc1:VCC", "ring1:VCC", "red", [ "v19.2", "h-96" ] ],
    [ "nano:4", "r1:1", "blue", [ "v0" ] ],
    [ "ring1:DIN", "r1:2", "blue", [ "v19.2", "h-95.8" ] ],
    [ "vcc1:VCC", "and1:B", "red", [ "v0" ] ],
    [ "gnd1:GND", "and1:A", "black", [ "v0" ] ],
    [ "nano:GND.2", "btn2:2.l", "black", [ "v0" ] ],
    [ "nano:2", "btn2:1.l", "yellow", [ "v0" ] ]
  ],
  "dependencies": {}
}
1 Like