You can read this and other amazing tutorials onElectroPeak's official website
OverviewHave you ever played board games? Do you like to play with dices? We use dices in many board games, but sometimes they cause problems. For example, when I play a thriller with friends, sometimes we forget the turns. Do you want to know how you can solve this problem? If so, follow this article.
We want to show how you can build a smart assistant with electronic components, such as the KY-037 sound detection module, RGB LEDs, TFT LCD shield and of course an Arduino UNO.
What You Will Learn- What a dice tower is, and how we can make one
- How to use sound detection module to know when dices are falling
- How to use an RGB LED to show turns and add a light effect
- How to use an LCD to display more information and create a virtual dice
Many board games use dices. To those who prefer real games to computer ones, it is essential to hold and toss the dice(s). But there is no guarantee for justice and players might cheat! Besides, some board games have a lot of dices. Tossing several dices at the same time can be difficult, and some might even get lost. A dice tower is an excellent idea to solve these problems. Dices enter from above the tower, touch inner plates and spiral down to settle in the bottom.
No matter the game, cheating is always a possibility; especially games with dices. Thrill and pace of the game might confuse players about turns. Therefore, the presence of a fair judge can be helpful. With some electronic innovation, we can make a smart dice tower to help keep turns and display it in colorful lights.
You might lose a dice during the game. So you are obliged to use a different object (a stone!) instead of dice. A smart dice Tower gives you the best option. Even if there’s nothing around to use as a dice, have no fear, our tower has a virtual dice.
Required MaterialsSee the list of required materials at beginning of the page.
How to Assemble Dice Tower’s BodyTo make a Smart Dice Tower, first, we need to build the body. It can be made of 2.8mm MDF or Plexiglass. Feel free to download the laser cutting draft here (You can also download it from the attachments section in this page).
Dice Tower Mechanical Assembly Video
Note
Some draft parts are spare parts and won’t be used.
We use an Arduino TFT LCD shield in this project. To operate this module, just mount it onto Arduino UNO (note pins position and orientation). In order to set up the KY-037 module, connect the supply pins of the module to the VCC and the GND pins and the digital output pin to pin D13 of the Arduino.
To use RGB LED, connect the cathode pin to the GND pin of the Arduino and connect the red, green, and blue pins to D5, D6 and, D7 on the Arduino board.
See the following video to see how to assemble the electronics parts:
Watch the following for Electronics parts assembly:
How to Use Sound Detection Module to Know When Dice Is FallingWe can use a or sound detection module to know when a dice is falling. If we put the knock sensor under one of the inner plates, the given shock won’t be enough. Putting the sensor directly in the path of dice is not right either. So a sound module is a proper choice. We can setup the KY-037 sound module simply according to picture 4. Since there is just one tone to detect in this project, we just use the digital pin of the sound module. To recognize dice sound, we can read the D13 pin of the Arduino (which is connected to the digital output of the sound module) with the digitalRead() command. The Digital pin is pulled up in this module, and when a sound reaches the threshold, the digital pin voltage will become zero. We can change the sound threshold by turning the potentiometer on the board. To calibrate this sensor precisely, follow these steps:
Step 1: Upload the following code to your Arduino board:
void setup() {
Serial.begin(9600); // setup serial
pinMode(13,INPUT);
}
void loop() {
Serial.println(digitalRead(13));
delay(100);
}
Step 2: Open Serial Monitor Now frequently drop the dice in the tower, while turning the potentiometer until you see number zero in the Serial Monitor window. Throw in the dice a few more time to make sure module is well adjusted. It should be tuned so that other noises in the environment wouldn’t activate the sensor.
For more information on KY-037, visit this article.
How to Use an RGB LED to Show Turns and Add Light EffectThere are various RGB LED types. We use the 4-pin common cathode RGB LED in this project. To turn on the LED, we should connect the cathode to the GND. And adding voltage to the other pins will turn LED red, green or blue. If all three pins are set to high, LED will glow white.
Tip: You can use the PWM signal with the analogWrite command to create different color spectrums with RGB LED.
Using the following code, you can periodically change LED color to red, green, blue, and white.
#define rLED 10
#define rLED 11
#define rLED 12
Void setup(){
pinMode(rLED,OUTPUT);
pinMode(gLED,OUTPUT);
pinMode(bLED,OUTPUT);
void loop(){
//LED equalizer
digitalWrite(rLED,HIGH);digitalWrite(gLED,LOW);digitalWrite(bLED,LOW);
delay(100);
digitalWrite(rLED,LOW);digitalWrite(gLED,HIGH);digitalWrite(bLED,LOW);
delay(100);
digitalWrite(rLED,LOW);digitalWrite(gLED,LOW);digitalWrite(bLED,HIGH);
delay(100);
digitalWrite(rLED,HIGH);digitalWrite(gLED,HIGH);digitalWrite(bLED,HIGH);
delay(100);
}
Using a TFT LCD to Show More Information and build a Virtual DiceTo show a player’s turn, we should know the number of players and their corresponding color. We can use a TFT LCD with a touch screen. The 2.4-inch Adafruit LCD shield for Arduino is an excellent simple choice.
See the full tutorial for this LCD here.
In the following code when starting up the LCD, first the number of players is asked and the user can choose it from 1 to 4 by touching the dice on the screen. Based on the number of players, it asks a color for each player. At the end of this part, the color sequence is displayed and then the game starts.
*/
Smart Dice Tower – main code
modified on 25 May 2019
by Arash Abarghooei
https://electropeak.com/learn/
*/
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include <TouchScreen.h>
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4
#define YP A3
#define XM A2
#define YM 9
#define XP 8
#define rLED 5
#define gLED 6
#define bLED 7
#define ss 13
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
//find these number through “SDT_TS_calibration.ino” code
#define TSx_dices 600
#define Tsy_1st_dice 825
#define Tsy_2nd_dice 625
#define Tsy_3th_dice 425
#define Tsy_4th_dice 225
#define Tsy_virtual_dice 760
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define PURPLE 0x780F
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
int n=1,a=1,t=0,count=0;
int c[4];
bool pres=false,vd=false;
void setup() {
Serial.begin(9600);
Serial.println(F(“TFT LCD test”));
tft.reset();
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
Serial.println(F(“Using Adafruit 2.4\” TFT Arduino Shield Pinout”));
#else
Serial.println(F(“Using Adafruit 2.4\” TFT Breakout Board Pinout”));
#endif
Serial.print(“TFT size is “);
Serial.print(tft.width());
Serial.print(“x");
Serial.println(tft.height());
tft.reset();
delay(1000);
uint16_t identifier = tft.readID();
if (identifier == 0x9325){
Serial.println(F(“Found ILI9325 LCD driver”));
} else if (identifier == 0x9328){
Serial.println(F(“Found ILI9328 LCD driver”));
} else if (identifier == 0x7575){
Serial.println(F(“Found HX8347G LCD driver”));
} else if (identifier == 0x9341){
Serial.println(F(“Found ILI9341 LCD driver”));
} else if (identifier == 0x8357){
Serial.println(F(“Found HX8357D LCD driver”));
} else {
Serial.print(F(“Unknown LCD driver chip: “));
Serial.println(identifier, HEX);
Serial.println(F(“If using the Adafruit 2.4\” TFT Arduino shield, the line:”));
Serial.println(F(“ #define USE_ADAFRUIT_SHIELD_PINOUT”));
Serial.println(F(“should appear in the library header (Adafruit_TFT.h).”));
Serial.println(F(“If using the breakout board, it should NOT be #defined!”));
Serial.println(F(“Also if using the breakout, double-check that all wiring”));
Serial.println(F(“matches the tutorial.”));
return;
}
pinMode(13, OUTPUT);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
tft.begin(identifier);
Serial.println(F(“Benchmark Time (microseconds)”));
//-------------------------------------------------------------------------------------
//LCD starting:
tft.fillScreen(PURPLE);
tft.setTextColor(YELLOW);
tft.setRotation(1);
tft.setCursor(30, 100);
tft.setTextSize(4);
tft.println(“Electropeak”);
tft.setCursor(60, 150);
tft.setTextSize(2);
tft.println(“Smart Dice Tower”);
delay(1000);
//-------------------------------------------------------------------------------------
//asking number of player
tft.fillScreen(PURPLE);
tft.setRotation(1);
tft.setCursor(5, 50);
tft.setTextSize(3);
tft.println(“number of player?”)
delay(200);
tft.fillRoundRect(20,110,60,60,5,WHITE);
tft.fillCircle(50,140,10,RED);
tft.fillRoundRect(90,110,60,60,5,WHITE);
tft.fillCircle(120,125,8,BLACK);
tft.fillCircle(120,155,8,BLACK);
tft.fillRoundRect(160,110,60,60,5,WHITE);
tft.fillCircle(170,120,8,BLACK);
tft.fillCircle(190,140,8,BLACK);
tft.fillCircle(210,160,8,BLACK);
tft.fillRoundRect(230,110,60,60,5,WHITE);
tft.fillCircle(245,125,8,BLACK);
tft.fillCircle(275,125,8,BLACK);
tft.fillCircle(245,155,8,BLACK);
tft.fillCircle(275,155,8,BLACK);
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
// Serial.print(p.x); Serial.print(“ “); Serial.println(p.y);
if (p.x>TSx_dices-100 && p.x<TSx_dices+100){
if(p.y>Tsy_1st_dice-75 && p.y<Tsy_1st_dice+75)
n=1;
else if(p.y>Tsy_2nd_dice-75 && p.y<Tsy_2nd_dice+75)
n=2;
else if(p.y>Tsy_3th_dice-75 && p.y<Tsy_3th_dice+75)
n=3;
else if(p.y>Tsy_4th_dice-75 && p.y<Tsy_4th_dice+75)
n=4;
}
}
}
//-------------------------------------------------------------------------------------
//asking players colors
for(int j=0;j<n;j++){
pres=false;
tft.fillScreen(PURPLE);
tft.setRotation(1);
tft.setCursor(20, 50);
tft.setTextSize(3);
tft.print(“player”);tft.print(j+1);tft.print(“ color?”);
delay(200);
tft.fillRoundRect(20,110,60,60,5,WHITE);
tft.fillCircle(50,140,10,BLACK);
tft.fillRoundRect(90,110,60,60,5,RED);
tft.fillCircle(120,140,10,BLACK);
tft.fillRoundRect(160,110,60,60,5,GREEN);
tft.fillCircle(190,140,10,BLACK);
tft.fillRoundRect(230,110,60,60,5,BLUE);
tft.fillCircle(260,140,10,BLACK);
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
if (p.x>TSx_dices-100 && p.x<TSx_dices+100){
if(p.y>Tsy_1st_dice-75 && p.y<Tsy_1st_dice+75)
c[j]=WHITE;
else if(p.y>Tsy_2nd_dice-75 && p.y<Tsy_2nd_dice+75)
c[j]=RED;
else if(p.y>Tsy_3th_dice-75 && p.y<Tsy_3th_dice+75)
c[j]=GREEN;
else if(p.y>Tsy_4th_dice-75 && p.y<Tsy_4th_dice+75)
c[j]=BLUE;
}
}
}
}
for(int i=0;i<n;i++){
tft.fillScreen(c[i]);
delay(200);
}
}
After the program receives the number of players and their colors, it starts the main code. With the KY-037 sound module, dice falls are counted and stored in the count variable. The count will then be divided by the number of players, and the remainder will show the next turn. Each turn, LCD displays the player’s color and waits until he/she throws the dice. When dice falls, the RGB LED shows random colors, and LCD plays a simple dice animation.
LCD right side displays theoverall toss-drop count.
int j=1;
void loop() {
//calculation of players turn
t=count%n;
tft.fillScreen(c[t]);
tft.setTextColor(YELLOW);
tft.setRotation(1);
tft.setCursor(0, 50);
tft.setTextSize(3);
tft.print("it's player");tft.print(t+1);tft.print(" turn");
//showing number of dice fallen
tft.fillRoundRect(225,110,60,60,5,BLACK);
tft.setTextColor(YELLOW);
tft.setRotation(1);
tft.setTextSize(2);
tft.setCursor(245, 135);
tft.print(count);
//sensing with microphone
while(j==0){
pinMode(13,INPUT);
int a=digitalRead(ss);
if(a==0)j=1;
//showing the color of player whose turn is
if(c[t]==RED){
digitalWrite(rLED,HIGH);digitalWrite(gLED,LOW);digitalWrite(bLED,LOW);}
if(c[t]==BLUE){
digitalWrite(rLED,LOW);digitalWrite(gLED,LOW);digitalWrite(bLED,HIGH);}
if(c[t]==GREEN){
digitalWrite(rLED,LOW);digitalWrite(gLED,HIGH);digitalWrite(bLED,LOW);}
if(t==WHITE){
digitalWrite(rLED,HIGH);digitalWrite(gLED,HIGH);digitalWrite(bLED,HIGH);}
}
//LED equalizer
if(j==1){
for(int i=0;i<6;i==){
digitalWrite(rLED,LOW);digitalWrite(gLED,HIGH);digitalWrite(bLED,HIGH);
delay(100);
digitalWrite(rLED,HIGH);digitalWrite(gLED,LOW);digitalWrite(bLED,HIGH);
delay(100);
digitalWrite(rLED,HIGH);digitalWrite(gLED,HIGH);digitalWrite(bLED,LOW);
delay(100);
digitalWrite(rLED,LOW);digitalWrite(gLED,LOW);digitalWrite(bLED,LOW);
delay(100);
//LCD dice animation
tft.setTextColor(YELLOW);
tft.setRotation(1);
tft.setCursor(20, 200);
tft.setTextSize(2);
tft.print("Dice is falling...”);
tft.fillRoundRect(130,110,60,60,5,WHITE);
delay(200);
Dice(random(6)+1);
}
a=1;
j=0;
}
count++;
}
//-------------------------------------------------------------------------------------
//dice drawing function
void Dice(int d){
if(d==1){
tft.fillRoundRect(130,110,60,60,5,WHITE);
tft.drawRoundRect(130,110,60,60,5,BLACK);
tft.fillCircle(160,140,10,RED);
}
else if(d==2){
tft.fillRoundRect(130,110,60,60,5,WHITE);
tft.drawRoundRect(130,110,60,60,5,BLACK);
tft.fillCircle(160,125,8,BLACK);
tft.fillCircle(160,155,8,BLACK);
}
else if(d==3){
tft.fillRoundRect(130,110,60,60,5,WHITE);
tft.drawRoundRect(130,110,60,60,5,BLACK);
tft.fillCircle(140,120,8,BLACK);
tft.fillCircle(160,140,8,BLACK);
tft.fillCircle(180,160,8,BLACK);
}
else if(d==4){
tft.fillRoundRect(130,110,60,60,5,WHITE);
tft.drawRoundRect(130,110,60,60,5,BLACK);
tft.fillCircle(145,125,8,BLACK);
tft.fillCircle(175,125,8,BLACK);
tft.fillCircle(145,155,8,BLACK);
tft.fillCircle(175,155,8,BLACK);
}
else if(d==5){
tft.fillRoundRect(130,110,60,60,5,WHITE);
tft.drawRoundRect(130,110,60,60,5,BLACK);
tft.fillCircle(145,125,8,BLACK);
tft.fillCircle(175,125,8,BLACK);
tft.fillCircle(145,155,8,BLACK);
tft.fillCircle(175,155,8,BLACK);
tft.fillCircle(160,140,8,BLACK);
}
else if(d==6){
tft.fillRoundRect(130,110,60,60,5,WHITE);
tft.drawRoundRect(130,110,60,60,5,BLACK);
tft.fillCircle(145,125,6,BLACK);
tft.fillCircle(175,125,6,BLACK);
tft.fillCircle(145,140,6,BLACK);
tft.fillCircle(175,140,6,BLACK);
tft.fillCircle(145,155,6,BLACK);
tft.fillCircle(175,155,6,BLACK);
}
}
This part of the code shows a dice number using Dice (number) function.
To make the game more interesting, you can use pictures instead of colors. Save the images you like in a micro SD card and put it into an SD card slot. The following code reads images from the SD card.
void bmpDraw(String filename, int x, int y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t lcdidx = 0;
boolean first = true;
if ((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print(F("Loading image ‘ ‘’));
Serial.print(filename);
Serial.println(‘\’’);
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL){
Serial.println(F("File not found”));
return;
}
// Parse BMP header
if (read16(bmpFile) == 0x4D42) { // BMP signature
Serial.println(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if (read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print(F("Image size:”));
Serial.print(bmpWidth);
Serial.print('x’);
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if (bmpHeight < 0){
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if ((x + w - 1) >= tft.width()) w = tft.width() - x;
if ((y + h - 1) >= tft.height()) h = tft.height() - y;
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x + w - 1, y + h – 1);
for (row = 0; row < h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col = 0; col < w; col++) { // For each column...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
// Push LCD buffer to the display first
if (lcdidx > 0) {
tft.pushColors(lcdbuffer, lcdidx, first);
lcdidx = 0;
first = false;
}
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
lcdbuffer[lcdidx++] = tft.color565(r, g, b);
}// end pixel
}// end scanline
// Write any remaining data to LCD
if (lcdidx > 0){
tft.pushColors(lcdbuffer, lcdidx, first);
}
Serial.print(F("Loaded in “));
Serial.print(millis() – startTime);
Serial.println(" ms”);
}// end goodBmp
{
{
bmpFile.close();
if (!goodBmp) Serial.println(F("BMP format not recognized.”));
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
Put this functions at the end of main code and replace bmpDraw(c[t], 0, 0); line with tft.fillScreen(c[t]); throughout the code. Then, by each turn, LCD shows player’s image instead of a color.
Variable c[t] should be a string with a length of at least 10 characters. It contains the names of the pictures on the SD card.
All pictures on the SD card must be 320×240 pixel and bitmap 24-bit format. For example, you can use photos in this zip file for your dice tower.
Add Virtual Dice and upload final codeNow that our LCD shows several dices, we can have a virtual dice. Add the following code at the beginning of the void loop().
//Virtual Dice option
if(vd){
tft.fillRoundRect(35,110,60,60,5,YELLOW);
tft.setTextColor(BLACK);
tft.setRotation(1);
tft.setTextSize(1);
tft.setCursor(45, 130);
tft.print("Virtual”);
tft.setCursor(55, 145);
tft.print("Dice”);}
else{
tft.fillRoundRect(35,110,60,60,5,BLACK);
tft.setTextColor(YELLOW);
tft.setRotation(1);
tft.setTextSize(1);
tft.setCursor(45, 130);
tft.print("Virtual”);
tft.setCursor(55, 145);
tft.print("Dice”);
}
//sensing with microphone
while(j==0){
pinMode(13,INPUT);
int a=digitalRead(ss);
//Serial.println(a);
if(a==0)j=1;
pinMode(13,OUTPUT);
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
if(p.x>TSx_dices-100 && p.x<TSx_dices+100 && p.y>TSy_virtual_dice-90 && p.y<TSy_virtual_dice+90){vd=!vd; pres=true;}
}
//Virtual Dice option
if(pres){
if(vd){
tft.fillRoundRect(35,110,60,60,5,YELLOW);
tft.setTextColor(BLACK);
// tft.setRotation(1);
// tft.setTextSize(1);
tft.setCursor(45, 130);
tft.print("Virtual");
tft.setCursor(55, 145);
tft.print("Dice");}
else{
tft.fillRoundRect(35,110,60,60,5,BLACK);
tft.setTextColor(YELLOW);
// tft.setRotation(1);
// tft.setTextSize(1);
tft.setCursor(45, 130);
tft.print("Virtual");
tft.setCursor(55, 145);
tft.print("Dice");
}
pres=false;
}
Once code is copied, a new button named as virtual dice appears on the left side of the LCD. Touch the button to activate virtual dice. At the center of LCD, dice starts to change randomly and then pauses for 2 seconds. To insert this pause into code, replace the code of LCD dice animation section with the following code:
//LCD dice animation
tft.setTextColor(YELLOW);
tft.setRotation(1);
tft.setCursor(20, 200);
tft.setTextSize(2);
tft.print("Dice is falling...”);
tft.fillRoundRect(130,110,60,60,5,WHITE);
delay(200);
Dice(random(6)+1);
}
if(vd){
tft.fillRect(10,180,250,60,c[t]);
tft.setCursor(20, 200);
tft.print("Dice fell!”);
delay(2000);
}
a=1;
j=0;
}
Note: You can download the complete code for the dice tower from here or the attachments section of this page. You must calibrate the touch screen before uploading this code to the Arduino board.
Touch Screen CalibrationTo calibrate the touch screen, upload the following code to your Arduino board.This code will ask the user to touch certain areas displayed on LCD to calibrate the touch screen. After you touch all red dots, LCD will give the marked area coordinates to insert into the main code. You can view these coordinates in the serial monitor window too.
/*
Smart Dice Tower - touchscreen calibration code
modified on 25 May 2019
by Arash Abarghooei
https://electropeak.com/learn/
*/
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include <TouchScreen.h>
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4
#define YP A3
#define XM A2
#define YM 9
#define XP 8
#define rLED 10
#define gLED 11
#define bLED 12
#define ss 13
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
int TSx_dices;
int TSy_1st_dice;
int TSy_2nd_dice;
int TSy_3th_dice;
int TSy_4th_dice;
int TSy_virtual_dice;
#define BLACK 0x0000
#define RED 0xF800
#define WHITE 0xFFFF
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
bool pres=false;
void setup(){
Serial.begin(9600);
Serial.println(F("TFT LCD test”));
tft.reset();
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
Serial.println(F("Using Adafruit 2.4\" TFT Arduino Shield Pinout”));
#else
Serial.println(F("Using Adafruit 2.4\" TFT Breakout Board Pinout”));
#endif
Serial.print("TFT size is “);
Serial.print(tft.width());
Serial.print("x”);
Serial.println(tft.height());
tft.reset();
delay(1000);
uint16_t identifier = tft.readID();
if (identifier == 0x9325){
Serial.println(F("Found ILI9325 LCD driver”));
} else if (identifier == 0x9328){
Serial.println(F("Found ILI9328 LCD driver”));
} else if (identifier == 0x7575){
Serial.println(F("Found HX8347G LCD driver”));
} else if (identifier == 0x9341){
Serial.println(F("Found ILI9341 LCD driver”));
} else if (identifier == 0x8357) {
Serial.println(F("Found HX8357D LCD driver”));
} else {
Serial.print(F("Unknown LCD driver chip: “));
Serial.println(identifier, HEX);
Serial.println(F("If using the Adafruit 2.4\" TFT Arduino shield, the line:”));
Serial.println(F(" #define USE_ADAFRUIT_SHIELD_PINOUT”));
Serial.println(F("should appear in the library header (Adafruit_TFT.h).”));
Serial.println(F("If using the breakout board, it should NOT be #defined!”));
Serial.println(F("Also if using the breakout, double-check that all wiring”));
Serial.println(F("matches the tutorial.”));
return;
}
pinMode(13, OUTPUT);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
tft.begin(identifier);
Serial.println(F("Benchmark Time (microseconds)”));
tft.fillScreen(BLACK);
tft.setRotation(1);
tft.setCursor(0, 50);
tft.setTextSize(2);
tft.println("Smart Dice Tower touchscreen calibration”);
delay(1000);
Serial.println("touchscreen calibration started”);
tft.println("please open Serial monitor”);
delay(1000);
tft.setTextColor(RED);
tft.setCursor(0, 100);
tft.println("please touch the red areas”);
Serial.println("please touch the red areas”);
for (uint16_t a=0; a<5; a++){
tft.drawFastHLine(0, 140+a, 320, RED);}
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
Serial.print("TSx_dices is “);
Serial.println(p.x);
TSx_dices=p.x;
}
}
for (uint16_t a=0; a<5; a++){
tft.drawFastHLine(0, 140+a, 320, BLACK);}
delay(500);
tft.fillCircle(50,140,10,RED);
pres=false;
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
Serial.print("TSy_1st_dice is “);
Serial.println(p.y);
TSy_1st_dice=p.y;
}
}
tft.fillCircle(50,140,10,BLACK);
delay(500);
tft.fillCircle(120,140,10,RED);
pres=false;
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
Serial.print("TSy_2nd_dice is “);
Serial.println(p.y);
TSy_2nd_dice=p.y;
}
}
tft.fillCircle(120,140,10,BLACK);
delay(500);
tft.fillCircle(190,140,10,RED);
pres=false;
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
Serial.print("TSy_3th_dice is “);
Serial.println(p.y);
TSy_3th_dice=p.y;
}
}
tft.fillCircle(190,140,10,BLACK);
delay(500);
tft.fillCircle(260,140,10,RED);
pres=false;
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
Serial.print("TSy_4th_dice is “);
Serial.println(p.y);
TSy_4th_dice=p.y;
}
}
tft.fillCircle(260,140,10,BLACK);
delay(500);
tft.fillCircle(65,140,10,RED);
pres=false;
while(!pres){
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
if(p.z > ts.pressureThreshhold){
pres= true;
Serial.print("TSy_virtal_dice is “);
Serial.println(p.y);
TSy_virtual_dice=p.y;
}
}
tft.fillCircle(65,140,10,BLACK);
delay(500);
tft.setTextSize(3);
tft.setTextColor(WHITE);
tft.println("please waite....”);
delay(1000);
tft.fillScreen(BLACK);
tft.setCursor(0, 20);
tft.setTextSize(3);
tft.println("DONE!”);
tft.setTextSize(3);
tft.println("put these data to main code”);
tft.setTextSize(2);
tft.print("TSx_dices is: “);
tft.println(TSx_dices);
tft.print("TSy_1st_dice is: “);
tft.println(TSy_1st_dice);
tft.print("TSy_2nd_dice is: “);
tft.println(TSy_2nd_dice);
tft.print("TSy_3th_dice is: “);
tft.println(TSy_3th_dice);
tft.print("TSy_4th_dice is: “);
tft.println(TSy_4th_dice);
tft.print("TSy_virtual_dice is: “);
tft.println(TSy_virtual_dice);
}
void loop(){}
First, upload the above code to the Arduino board. After running the code, touch the displayed red dots. Replace values for TSx_dices, TSy_1st_dice, TSy_2nd_dice, TSy_3th_dice, TSy_4th_dice, TSy_virtual_dice at the beginning of the original code with numbers in the serial monitor or on the LCD in the last step.
- Change the virtual dice program so that rolling a 6 will be rewarded with another dice roll for the player.
Comments
Please log in or sign up to comment.