/* This sketch from 12/31/24 uses 4 seven segment displays and 6 momentary pushbuttons.
It reads the Pilot's and the Copilot's sidesticks to capture a die value for each player.
Each sidestick can be moved either to the left or to the right at the start of a turn in order
for that player's die value to increase. The opposite stick direction will decrease the die value.
This allows players to choose whether they feel the sidestick input makes more intuitive sense in one
direction over the other.
Once both players have input their die values via their sidesticks, the sketch will send a command over the
serial port to another board which will handle the animation of the Primary Flight Display.
The sketch spends most of it's time in the IDLE state, waiting for sidestick input from either player.
I use an Arduino Mega for the number of pins.
It's very important to use a logic level converter on the TX pin, so that the RX pin of the LilyGo T-Display S3 I use
receives only a 3.3 volt input, and not a 5 volt input signal, which is what the Arduino sends out.
Also, don't forget to connect both this Arduino Mega and the LilyGo T-Display S3 to the same Ground.
written by Jean-Luc Szach 12/31/2024
*/
// initialize variables for the die rolls to be used by the pilot & copilot for banking
int pBankDigit = 0;
int cBankDigit = 0;
int displayDigit;
// initialize variable for the calculated die difference “pilot die minus copilot die”
int dieRollDiff;
// initialize variable for the absolute value of the dieRollDiff variable, and set to zero at first
int bankAbsVal = 0;
// initialize a variable for the current state of the state machine. Is this done here????
int currState;
// initialize variables that help identify which side of which stick was activated first
int currDigit;
int currBtnA;
int currBtnB;
// initialize the counter variables for how long a sidestick left or right button is held
unsigned long startTime; // millis reading at the time that a stick 1st pushes a side button
unsigned long currTime; // variable to capture millis each time through a loop
unsigned long elapsedTime; // variable for the difference between currTime & startTime
int pStickLBtn = 2; //pin for Pilot Sidestick’s left button
int pStickRBtn = 3; //pin for Pilot Sidestick’s right button
int pStickSelBtn = 4; //pin for Pilot Sidestick’s select button
int cStickLBtn = 5; //pin for Copilot Sidestick’s left btn
int cStickRBtn = 6; //pin for Copilot Sidestick’s right btn
int cStickSelBtn = 7; //pin for Copilot Sidestick select btn
int pStickLBtnState;
int pStickRBtnState;
int cStickLBtnState;
int cStickRBtnState;
int currBtnAState;
int currBtnBState;
int pStickSelBtnState;
int cStickSelBtnState;
int pDie7SegA = 8; // 7segment pins for the indication of which die roll Pilot chose
int pDie7SegB = 9;
int pDie7SegC = 10;
int pDie7SegD = 11;
int pDie7SegE = 12;
int pDie7SegF = 13;
int pDie7SegG = 22;
int cDie7SegA = 23; // 7segment pins for the indication of which die roll Copilot chose
int cDie7SegB = 24;
int cDie7SegC = 25;
int cDie7SegD = 26;
int cDie7SegE = 27;
int cDie7SegF = 28;
int cDie7SegG = 29;
int pBank7SegA = 30; // 7segment pins for the indication of a bank to the left side
int pBank7SegB = 31;
int pBank7SegC = 32;
int pBank7SegD = 33;
int pBank7SegE = 34;
int pBank7SegF = 35;
int pBank7SegG = 36;
int cBank7SegA = 37; // 7segment pins for the indication of a bank to the right side
int cBank7SegB = 38;
int cBank7SegC = 39;
int cBank7SegD = 40;
int cBank7SegE = 41;
int cBank7SegF = 42;
int cBank7SegG = 43;
//declare custom function to check which stick is active and display appropriate DIE value on correct 7seg display
void displayDieDigit() {
if ((currBtnA == pStickLBtn) || (currBtnA == pStickRBtn)) { //if the Pilot's stick is active, display die number on Pilot's 7seg die display
digitalWrite(pDie7SegA, LOW); //blank Pilot's digit before writing new digit
digitalWrite(pDie7SegB, LOW);
digitalWrite(pDie7SegC, LOW);
digitalWrite(pDie7SegD, LOW);
digitalWrite(pDie7SegE, LOW);
digitalWrite(pDie7SegF, LOW);
digitalWrite(pDie7SegG, LOW);
if (currDigit == 0) { // if the die hasn't been chosen yet then don't do anything
}
else if (currDigit == 1) {
digitalWrite(pDie7SegB, HIGH); // display "1" on 7seg display for Pilot
digitalWrite(pDie7SegC, HIGH);
}
else if (currDigit == 2) {
digitalWrite(pDie7SegA, HIGH); // display "2"
digitalWrite(pDie7SegB, HIGH);
digitalWrite(pDie7SegD, HIGH);
digitalWrite(pDie7SegE, HIGH);
digitalWrite(pDie7SegG, HIGH);
}
else if (currDigit == 3) {
digitalWrite(pDie7SegA, HIGH); // display "3"
digitalWrite(pDie7SegB, HIGH);
digitalWrite(pDie7SegC, HIGH);
digitalWrite(pDie7SegD, HIGH);
digitalWrite(pDie7SegG, HIGH);
}
else if (currDigit == 4) {
digitalWrite(pDie7SegB, HIGH); // display "4"
digitalWrite(pDie7SegC, HIGH);
digitalWrite(pDie7SegF, HIGH);
digitalWrite(pDie7SegG, HIGH);
}
else if (currDigit == 5) {
digitalWrite(pDie7SegA, HIGH); // display "5"
digitalWrite(pDie7SegC, HIGH);
digitalWrite(pDie7SegD, HIGH);
digitalWrite(pDie7SegF, HIGH);
digitalWrite(pDie7SegG, HIGH);
}
else if (currDigit == 6) {
digitalWrite(pDie7SegA, HIGH); // display "6"
digitalWrite(pDie7SegC, HIGH);
digitalWrite(pDie7SegD, HIGH);
digitalWrite(pDie7SegE, HIGH);
digitalWrite(pDie7SegF, HIGH);
digitalWrite(pDie7SegG, HIGH);
}
}
if ((currBtnA == cStickLBtn) || (currBtnA == cStickRBtn)) { //if the COPILOT's stick is active, then display die number on copilot's 7seg die diplay
digitalWrite(cDie7SegA, LOW); //blank COPILOT's digit before writing new digit
digitalWrite(cDie7SegB, LOW);
digitalWrite(cDie7SegC, LOW);
digitalWrite(cDie7SegD, LOW);
digitalWrite(cDie7SegE, LOW);
digitalWrite(cDie7SegF, LOW);
digitalWrite(cDie7SegG, LOW);
if (currDigit == 0) { // if the die hasn't been chosen yet then don't do anything
}
else if (currDigit == 1) {
digitalWrite(cDie7SegB, HIGH); // display "1" on 7seg display for COPILOT
digitalWrite(cDie7SegC, HIGH);
}
else if (currDigit == 2) {
digitalWrite(cDie7SegA, HIGH); // display "2"
digitalWrite(cDie7SegB, HIGH);
digitalWrite(cDie7SegD, HIGH);
digitalWrite(cDie7SegE, HIGH);
digitalWrite(cDie7SegG, HIGH);
}
else if (currDigit == 3) {
digitalWrite(cDie7SegA, HIGH); // display "3"
digitalWrite(cDie7SegB, HIGH);
digitalWrite(cDie7SegC, HIGH);
digitalWrite(cDie7SegD, HIGH);
digitalWrite(cDie7SegG, HIGH);
}
else if (currDigit == 4) {
digitalWrite(cDie7SegB, HIGH); // display "4"
digitalWrite(cDie7SegC, HIGH);
digitalWrite(cDie7SegF, HIGH);
digitalWrite(cDie7SegG, HIGH);
}
else if (currDigit == 5) {
digitalWrite(cDie7SegA, HIGH); // display "5"
digitalWrite(cDie7SegC, HIGH);
digitalWrite(cDie7SegD, HIGH);
digitalWrite(cDie7SegF, HIGH);
digitalWrite(cDie7SegG, HIGH);
}
else if (currDigit == 6) {
digitalWrite(cDie7SegA, HIGH); // display "6"
digitalWrite(cDie7SegC, HIGH);
digitalWrite(cDie7SegD, HIGH);
digitalWrite(cDie7SegE, HIGH);
digitalWrite(cDie7SegF, HIGH);
digitalWrite(cDie7SegG, HIGH);
}
}
}
void displayBankDigit() { //forward declaration of function that shows the amount of bank on either left or right 7seg display
digitalWrite(pBank7SegA, LOW); //blank both left and right 7seg displays for bank angle
digitalWrite(pBank7SegB, LOW);
digitalWrite(pBank7SegC, LOW);
digitalWrite(pBank7SegD, LOW);
digitalWrite(pBank7SegE, LOW);
digitalWrite(pBank7SegF, LOW);
digitalWrite(pBank7SegG, LOW);
digitalWrite(cBank7SegA, LOW);
digitalWrite(cBank7SegB, LOW);
digitalWrite(cBank7SegC, LOW);
digitalWrite(cBank7SegD, LOW);
digitalWrite(cBank7SegE, LOW);
digitalWrite(cBank7SegF, LOW);
digitalWrite(cBank7SegG, LOW);
if (pBankDigit == cBankDigit) {
digitalWrite(pBank7SegA, HIGH); //display "0" in both 7seg displays
digitalWrite(pBank7SegB, HIGH);
digitalWrite(pBank7SegC, HIGH);
digitalWrite(pBank7SegD, HIGH);
digitalWrite(pBank7SegE, HIGH);
digitalWrite(pBank7SegF, HIGH);
digitalWrite(cBank7SegA, HIGH);
digitalWrite(cBank7SegB, HIGH);
digitalWrite(cBank7SegC, HIGH);
digitalWrite(cBank7SegD, HIGH);
digitalWrite(cBank7SegE, HIGH);
digitalWrite(cBank7SegF, HIGH);
}
else if (pBankDigit >> cBankDigit) {
if (bankAbsVal == 1) {
digitalWrite(pBank7SegB, HIGH); //display "1" on left 7seg display
digitalWrite(pBank7SegC, HIGH);
}
if (bankAbsVal == 2) {
digitalWrite(pBank7SegA, HIGH);
digitalWrite(pBank7SegC, HIGH);
digitalWrite(pBank7SegD, HIGH);
digitalWrite(pBank7SegE, HIGH);
digitalWrite(pBank7SegG, HIGH);
}
if (bankAbsVal == 3) {
digitalWrite(pBank7SegA, HIGH);
digitalWrite(pBank7SegB, HIGH);
digitalWrite(pBank7SegC, HIGH);
digitalWrite(pBank7SegD, HIGH);
digitalWrite(pBank7SegG, HIGH);
}
if (bankAbsVal == 4) {
digitalWrite(pBank7SegB, HIGH);
digitalWrite(pBank7SegC, HIGH);
digitalWrite(pBank7SegF, HIGH);
digitalWrite(pBank7SegG, HIGH);
}
}
else if (cBankDigit >> pBankDigit) {
if (bankAbsVal == 1) {
digitalWrite(cBank7SegB, HIGH); //display "1" on right 7seg display
digitalWrite(cBank7SegC, HIGH);
}
if (bankAbsVal == 2) {
digitalWrite(cBank7SegA, HIGH);
digitalWrite(cBank7SegB, HIGH);
digitalWrite(cBank7SegD, HIGH);
digitalWrite(cBank7SegE, HIGH);
digitalWrite(cBank7SegG, HIGH);
}
if (bankAbsVal == 3) {
digitalWrite(cBank7SegA, HIGH);
digitalWrite(cBank7SegB, HIGH);
digitalWrite(cBank7SegC, HIGH);
digitalWrite(cBank7SegD, HIGH);
digitalWrite(cBank7SegG, HIGH);
}
if (bankAbsVal == 4) {
digitalWrite(cBank7SegB, HIGH);
digitalWrite(cBank7SegC, HIGH);
digitalWrite(cBank7SegF, HIGH);
digitalWrite(cBank7SegG, HIGH);
}
}
else if (bankAbsVal >> 4) { //game over
digitalWrite(pBank7SegG, HIGH); //display a dash on each display
digitalWrite(cBank7SegG, HIGH);
}
}
// declare custom function to read the sticks and increment and decrement the die value
void pickBankDie() {
currBtnAState = digitalRead(currBtnA);
currBtnBState = digitalRead(currBtnB);
if (currBtnAState == LOW) { //to left 1st, checks again for press if released
startTime = millis();
}
while (digitalRead(currBtnA) == LOW) { //increases currDigit every 1.5 seconds
currTime = millis();
elapsedTime = (currTime - startTime);
if (elapsedTime >= 1500) {
currDigit++;
displayDieDigit(); // show current die value on 7seg
if (currDigit == 7) {
currDigit = 6;
}
startTime = currTime; //reset time interval to zero
}
}
if (currBtnBState == LOW) { // decreases currDigit every 1.5 secs
startTime = millis();
}
while (digitalRead(currBtnB) == LOW) {
currTime = millis();
elapsedTime = (currTime - startTime);
if (elapsedTime >= 1500) {
currDigit--;
if (currDigit == 0) {
currDigit = 1;
}
displayDieDigit(); // show current die value on 7seg
startTime = currTime; //reset time interval to zero
}
}
}
void setup() {
pinMode(pStickLBtn, INPUT_PULLUP); // sidestick buttons set for input
pinMode(pStickRBtn, INPUT_PULLUP);
pinMode(pStickSelBtn, INPUT_PULLUP);
pinMode(cStickLBtn, INPUT_PULLUP);
pinMode(cStickRBtn, INPUT_PULLUP);
pinMode(cStickSelBtn, INPUT_PULLUP);
pinMode(pDie7SegA, OUTPUT); // 4 different 7segment displays set for output
pinMode(pDie7SegB, OUTPUT);
pinMode(pDie7SegC, OUTPUT);
pinMode(pDie7SegD, OUTPUT);
pinMode(pDie7SegE, OUTPUT);
pinMode(pDie7SegF, OUTPUT);
pinMode(pDie7SegG, OUTPUT);
pinMode(cDie7SegA, OUTPUT);
pinMode(cDie7SegB, OUTPUT);
pinMode(cDie7SegC, OUTPUT);
pinMode(cDie7SegD, OUTPUT);
pinMode(cDie7SegE, OUTPUT);
pinMode(cDie7SegF, OUTPUT);
pinMode(cDie7SegG, OUTPUT);
pinMode(pBank7SegA, OUTPUT);
pinMode(pBank7SegB, OUTPUT);
pinMode(pBank7SegC, OUTPUT);
pinMode(pBank7SegD, OUTPUT);
pinMode(pBank7SegE, OUTPUT);
pinMode(pBank7SegF, OUTPUT);
pinMode(pBank7SegG, OUTPUT);
pinMode(cBank7SegA, OUTPUT);
pinMode(cBank7SegB, OUTPUT);
pinMode(cBank7SegC, OUTPUT);
pinMode(cBank7SegD, OUTPUT);
pinMode(cBank7SegE, OUTPUT);
pinMode(cBank7SegF, OUTPUT);
pinMode(cBank7SegG, OUTPUT);
Serial.begin(9600);
}
void loop() {
stickRead();
}
void stickRead() { // custom function to set up state machine to read stick inputs
enum class stickState : uint8_t {
IDLE,
PILOTBTN1ST,
PILOTSELECTBTN,
COPILOTBTN1ST,
COPILOTSELECTBTN,
TRANSMITRESET,
};
static stickState currState = stickState::IDLE;
switch (currState) {
case stickState::IDLE: // checks for 1st left or right of either stick per turn
pStickLBtnState = digitalRead(pStickLBtn);
pStickRBtnState = digitalRead(pStickRBtn);
cStickLBtnState = digitalRead(cStickLBtn);
cStickRBtnState = digitalRead(cStickRBtn);
//currBtnAState = digitalRead(currBtnA); not needed here. In pickBankDie()
//currBtnBState = digitalRead(currBtnB); not needed here. In pickBankDie()
if (pStickLBtnState == LOW) {
currBtnA = pStickLBtn;
currBtnB = pStickRBtn;
pBankDigit = 0;
displayDieDigit(); // custom function to show on 7Seg display
currDigit = pBankDigit;
currState = stickState::PILOTBTN1ST;
}
else if (pStickRBtnState == LOW) {
currBtnA = pStickRBtn;
currBtnB = pStickLBtn;
pBankDigit = 0;
displayDieDigit();
currDigit = pBankDigit;
currState = stickState::PILOTBTN1ST;
}
else if (cStickLBtnState == LOW) {
currBtnA = cStickLBtn;
currBtnB = cStickRBtn;
cBankDigit = 0;
displayDieDigit();
currDigit = cBankDigit;
currState = stickState::COPILOTBTN1ST;
}
else if (cStickRBtnState == LOW) {
currBtnA = cStickRBtn;
currBtnB = cStickLBtn;
cBankDigit = 0;
displayDieDigit();
currDigit = cBankDigit;
currState = stickState::COPILOTBTN1ST;
}
break;
case stickState::PILOTBTN1ST:
pickBankDie();
pStickSelBtnState = digitalRead(pStickSelBtn);
if (pStickSelBtnState == LOW) {
pBankDigit = currDigit;
currState = stickState::PILOTSELECTBTN;
}
break;
case stickState::PILOTSELECTBTN:
if (cBankDigit == 0) { //if the copilot's stick hasn't recorded a die value then go back to the IDLE state to wait for copilot input
currState = stickState::IDLE;
}
else if (cBankDigit >> 0) { //if copilot has already used stick then move on to the TRANSMITREST state
currState = stickState::TRANSMITRESET;
}
break;
case stickState::COPILOTBTN1ST:
pickBankDie();
cStickSelBtnState = digitalRead(cStickSelBtn);
if (cStickSelBtnState == LOW) {
cBankDigit = currDigit;
currState = stickState::COPILOTSELECTBTN;
}
break;
case stickState::COPILOTSELECTBTN:
if (pBankDigit == 0) {
currState = stickState::IDLE;
}
else if (pBankDigit >> 0) {
currState = stickState::TRANSMITRESET;
}
break;
case stickState::TRANSMITRESET:
dieRollDiff = (pBankDigit - cBankDigit);
bankAbsVal = abs(dieRollDiff);
if (bankAbsVal == 0) {
displayBankDigit(); //call custom function to display the bank amount on either left or right 7seg for "delta roll"
Serial.write(1);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE; //to reset for next turn
}
if (pBankDigit >> cBankDigit) {
if (bankAbsVal == 1) {
displayBankDigit();
Serial.write(2);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 2) {
displayBankDigit();
Serial.write(3);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 3) {
displayBankDigit();
Serial.write(4);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 4) {
displayBankDigit();
Serial.write(5);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 5) { //exceeded allowable bank amount
displayBankDigit();
delay(1000);
digitalWrite(pDie7SegA, HIGH); //animate falling line on the 4 7seg displays
digitalWrite(cDie7SegA, HIGH);
delay(500);
digitalWrite(pDie7SegG, HIGH);
digitalWrite(cDie7SegG, HIGH);
delay(500);
digitalWrite(pDie7SegD, HIGH);
digitalWrite(cDie7SegD, HIGH);
delay(500);
digitalWrite(pBank7SegA, HIGH);
digitalWrite(cBank7SegA, HIGH);
delay(500);
digitalWrite(pBank7SegG, HIGH);
digitalWrite(cBank7SegG, HIGH);
delay(500);
digitalWrite(pBank7SegD, HIGH);
digitalWrite(cBank7SegD, HIGH);
delay(500);
}
}
if (cBankDigit >> pBankDigit) {
if (bankAbsVal == 1) {
displayBankDigit();
Serial.write(6);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 2) {
displayBankDigit();
Serial.write(7);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 3) {
displayBankDigit();
Serial.write(8);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 4) {
displayBankDigit();
Serial.write(9);
pBankDigit = 0;
cBankDigit = 0;
currState = stickState::IDLE;
}
else if (bankAbsVal == 5) { //exceeded allowable bank amount
displayBankDigit();
delay(1000);
digitalWrite(pDie7SegA, HIGH); //animate falling line on the 4 7seg displays
digitalWrite(cDie7SegA, HIGH);
delay(500);
digitalWrite(pDie7SegG, HIGH);
digitalWrite(cDie7SegG, HIGH);
delay(500);
digitalWrite(pDie7SegD, HIGH);
digitalWrite(cDie7SegD, HIGH);
delay(500);
digitalWrite(pBank7SegA, HIGH);
digitalWrite(cBank7SegA, HIGH);
delay(500);
digitalWrite(pBank7SegG, HIGH);
digitalWrite(cBank7SegG, HIGH);
delay(500);
digitalWrite(pBank7SegD, HIGH);
digitalWrite(cBank7SegD, HIGH);
delay(500);
}
}
break;
}
}