I recently got a Particle Photon 2 and a Boron and wanted to work with some of the more advanced features (such as AssetOTA), but needed a platform built out and ready. I took the opportunity to make a little device that rolls a virtual die every time a button is pressed.
In this tutorial, we'll be setting up the Particle Photon2 to use the Hiletgo ILI9341 TFT display. The Hiletgo ILI9341 that we're using in this example has the pins in a different order than the Adafruit version, so be aware of this while setting up your connections later in the instructions.
Wire the BreadboardFirst, connect the Photon to the first breadboard. For demonstration purposes, I have it connected in columns B and H on the breadboard, starting at row 1. Then connect the display to the second breadboard. I found that connecting to column C worked best and allowed the display to be better supported (by leaning the SD card slot against the face of the breadboard) while also giving you two columns of access on each row.
Now we'll connect the power connectors. In this example, I have everything connected to the right-side rails of the breadboard housing the Photon2 for ease of access with the breadboard housing the ILI9341 on the right side. This puts the power rail central to both devices. Run connection A2 to the positive (+) rail of the breadboard and A4 to the negative (-) rail.
For our purpose, we can ignore rows 10-14 on the breadboard housing the display, as those are used exclusively for the touch screen features, which we don't need at the moment.
The remaining 9 connections are labeled:1.VCC 2.GND 3.CS 4.RESET 5.DC 6.SDI (MO SI)7.SCK8.LED9.SD0 (MI SO)
These are connected as follows:VCC is connected to the Positive (+) rail and powers the circuit.
GND is connected to the Negative (-) rail completes the circuit.
CS is connected to pin D18 (A10 on the breadboard). It is labeled as SS for Slave Select.
Reset is used to reset the display. It's not really used in this particular demonstration, but I have it connected to the RST connection, so that if either device recieves the reset signal, they both do.
DC is connected to pin D6 (J10 on the breadboard) and is used for data/command purposes
SDI (MOSI) is connected to pin S0/D15 (A12 on the breadboard). It is used for Serial Data In or Main Out Sub In (MOSI).
SCK is the serial clock and is connected to S2/D17 (A11 on the breadboard).
LED is the power for the backlight that controls the display's brightness. It can be connected to an analog pin to control brightness, but for our purpose, we're going to connect it to the Positive (+) rail to use full brightness all the time.
SDO (MISO) is connected to S1/D16 (A13 on the breadboard) and is the Serial Data Out or Main In Sub Out connection.
That's all there is to hooking up the display. If we didn't want anything interesting, we could just run a simple "hello, world" and be done with it. Nobody wants that. So instead, we're going to make a simple program that rolls one six-sided die (1d6 for my fellow nerds).
Start by connecting the switch to the breadboard with the Photon 2 on it, jumping the middle somewhere below the controller; I opted for rows 24 & 26. The hooks of the feet should run horizontal across the breadboard.Connect J26 to ground.Connect A24 to a digital pin -- I selected pin D1 for this purpose.
Open your Particle Web IDE or your Particle Workbench plugin in VSCode and start a new.ino file. This file consists of two parts: void setup()
(the things that run at the start of your project) and void loop(void)
the looping elements that occur after the project has begun.
BEFORE you start the setup, we have a few things to get prepared.The code begins with including the required headers:
#include <Adafruit_mfGFX.h
#include "Adafruit_ILI9341.h"
Make sure you include these libraries in your project or including the headers won't work.
Then we define the CS and DC pins we'll use:
#define TFT_CS D18
#define TFT_DC D6
Now we declare a few variables:
int buttonPin = D1;
int diceVal = 0;
int val = 0;
Here we decide which parts of the default SPI connection we're going to use:
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, 0);
You'll notice in the comments that you can use other pins if you want; this is the default hardware SPI.
SetupIt's finally time to begin the setup step. In the setup section of your project.Here we start the serial connection, set the clock speed, set the button's pinmode, start the screen's functions, and set the screen's rotation:
Serial.begin(9600);
SPI.setClockSpeed(50, MHZ);
pinMode(buttonPin, INPUT_PULLUP);
tft.begin();
tft.setRotation(2);
NOTE: Setting rotation is totally optional and, for the sake of my demonstration images, I opted to not rotate the display and just turned the breadboard.
This next part is not strictly necessary, but it's a cool feature that is negligible to implement: additional randomness to make our die roller more random! It does this by detecting the state in the analog wave and using that as the seed for the pseudo-random number generator.
randomSeed(analogRead(A1));
No app is complete without a splash screen to explain what's going on. This code will create a splash screen that loads a black background, sets the cursor to the beginning of the text area, provides instructions on use, and says where it came from:
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_MAGENTA);
tft.setTextSize(4);
tft.println(" Press");
tft.println(" Button");
tft.println(" To Roll");
tft.println("");
tft.setTextColor(ILI9341_ORANGE);
tft.setTextSize(10);
tft.println(" 1d6");
tft.setTextSize(1);
tft.println("");
tft.println("");
tft.println("");
tft.setTextColor(ILI9341_WHITE);
tft.println("POWERED BY PARTICLE.IO");
With that little declaration out of the way, we now get to the main loop of our program. This part is contained in void loop(void){}.
At the beginning we want to ensure that diceVal
is set to 0
, then tie a bool to our val
variable and set it to LOW
. This makes it so that when the button is pressed, the D1
pin, which is set to an INPUT_PULLUP,
goes HIGH
. Once val
goes HIGH
, diceVal
gets a random number between 1-6, displays the dieRoller
with the random number inserted into the appropriate place, then sets a delay for 100ms before allow another button press to register -- even if the button is held down!
diceVal = 0;
bool val = digitalRead(buttonPin) == LOW;
if (val == HIGH) {
diceVal = random(1,7);
dieRoller();
delay(100);
}
That's the end of our loop!
Dice Roller Logic"But wait..., " you may be asking. "What about dieRoller
?" That gets defined now. We start by setting the timestamp for when dieRoller
starts, then fill the screen with black and return the cursor to the top left. White text makes this part easy to read and we set it to a legible TextSize
4. The user is now presented with a text saying that they rolled, followed by the result of diceVal
. If diceVal
is a 1, typically denoting a critical failure, the text turns red. Should the roll show a 6, the high value, it turns gold (or rather, yellow). The user is then presented with a very large number denoting what the die landed on. We finish by returning the microsecond timestamp minus the value of the timestamp when the program began, resulting in a stopwatch of how long the app ran.
unsigned long dieRoller() {
unsigned long start = micros();
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextSize(4);
tft.println("You Rolled ");
if (diceVal == 1) {
tft.setTextColor(ILI9341_RED);
}
else if (diceVal == 6) {
tft.setTextColor(ILI9341_YELLOW);
}
else {
tft.setTextColor(ILI9341_GREEN);
}
tft.setTextSize(36);
tft.println(diceVal);
return micros() - start;
}
And that's it! Check your code to ensure no missing semicolons and that everything's working as intended. You can check your code against my functioning code (as of DeviceOS 5.7.0) with additional comments and insights, located at: https://github.com/MrSchism/ParticleIOT---Tutorials/blob/main/Tutorials/Photon2/Photon2_DiceRoller.ino
All that's left to do is to compile, flash, and start rolling them virtual bones! Have fun!
Example Images
Comments
Please log in or sign up to comment.