/* This code is for a combined Digital hourglass with a buzzer and two digital dice
* On start up, you choose whether you want dice or sand timer by holding the select button
* until either dice or sandtimer is displayed. Pressing the 'throw' button will either throw the
* dice or start the sand timer.
* When sand timer is selected, you can press and hold the select button and choose the time for
* the sand to run through. Possible values are 60, 50, 40, 30, 20 and 10 seconds
* in this version, the dice or sand timer will repeat until the unit is reset after which you
* choose which function you want to use.
*/
#include <LedControl.h> //Include this library to allow functional control of the MAX72XX led matrix > see http://wayoda.github.io/LedControl/pages/software for explanation of function calls for this library
LedControl ledDrive = LedControl(12, 10, 11, 1); // Set up the LedControl function instance called "ledDrive" and set up which pins are used to control
int buzzer = 8;//the pin of the active buzzer
int sandSeconds = 6 ;
int toggle = 1 ;
int sandPeriod = 15000 ;
const int sandSpeed = 50 ;
int sandOrDice = 3 ;
const int rowValue [8] = {128, 64, 32, 16, 8, 4, 2, 1} ;
const byte glassFrame [8] [1] = // declare array called "glassFrame" in byte form and declare values as constants
{
{B10000001} , /* Permanent profile shape of the hourglass */
{B01000010} ,
{B00100100},
{B00011000} ,
{B00011000} ,
{B00100100} ,
{B01000010} ,
{B10000001} ,
};
const byte sandSurface [8] [1] = // declare array called "sandSurface" in byte form and declare values as constants
{
{B11111111} , /* Permanent profile shape of the hourglass */
{B01111110} ,
{B00111100},
{B00011000} ,
{B00011000} ,
{B00111100} ,
{B01111110} ,
{B11111111} ,
};
const byte letterSorD [8] [2] = // declare array called "letterSorD" in byte form and declare values as constants
{
{B00011111 , B11111111} , /* Permanent profile shape of the letter 'S' */
{B00010001 , B10000001} ,
{B00010101 , B01000010} ,
{B11111001 , B00100100} ,
{B10001111 , B00111100} ,
{B10101000 , B01111110} ,
{B10001000 , B11111111} ,
{B11111000 , B11111111} ,
};
byte seven_seg_digits[11] = { B11111100, // = 0
B01100000, // = 1
B11011010, // = 2
B11110010, // = 3
B01100110, // = 4
B10110110, // = 5
B10111110, // = 6
B11100000, // = 7
B11111110, // = 8
B11100110, // = 9
B00000000, // = All off
};
const byte diePattern [6] [3] = // declare a 2 dimensional array called "diePattern" (6 times 3 matrix) in byte form and declare values as constants
{
{B000, B010, B000}, /* Die value "1" */
{B100, B000, B001}, /* Die value "2" */
{B100, B010, B001}, /* Die value "3" */
{B101, B000, B101}, /* Die value "4" */
{B101, B010, B101}, /* Die value "5" */
{B101, B101, B101}, /* Die value "6" */
};
// connect to the ST_CP of 74HC595 (pin 3,latch pin)
int latchPin = 3;
// connect to the SH_CP of 74HC595 (pin 4, clock pin)
int clockPin = 4;
// connect to the DS of 74HC595 (pin 2)
int dataPin = 2;
int sandTimeSelect = 9 ;
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX SET UP XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void setup() {
ledDrive.shutdown(0, false); // The MAX72XX is in power-saving mode on startup, we have to do a wakeup call
ledDrive.setIntensity(0, 0); // Set the brightness to a medium values
ledDrive.clearDisplay(0); // and clear the display
pinMode(13, INPUT_PULLUP) ;
pinMode(buzzer, OUTPUT); //initialize the buzzer pin as an output
pinMode(sandTimeSelect, INPUT_PULLUP);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
randomSeed(analogRead(0));
}
//#################################### function sandFlowOut #######################################################################
void sandFlowOut (int *u, int v, int w , int x , int y , int z ) { // *u is rowValue, v is byteConvValBegin, w is sandSpeed, x is ledStartPosBegin , y is ledWidthBegin , z is ledRowBegin
for ( int i = x ; i < x + y ; i++) { // the '*' preceding rowValue is required because rowValue is an array. see https://forum.arduino.cc/t/very-simple-question-about-array-invalid-types-int-int-for-array-subscript/114788
v = v + u [i] ;
}
ledDrive.setRow (0, z , v ) ;
delay (w) ;
for (int j = x; j <= y + x ; j++) {
ledDrive.setLed(0, z, j, 0 );
delay (w) ;
}
for (int i = 0; i < 5; i++)
{
digitalWrite(buzzer, HIGH);
delay(4);//wait for 1ms
digitalWrite(buzzer, LOW);
delay(4);//wait for 1ms
}
}
//########################################## function sandFlowIn ##################################################################
void sandFlowIn (int w, int x , int y , int z ) { // w is sandSpeed, x is ledStartPosEnd, y is ledWidthEnd, z is ledRowEnd
for (int m = x ; m <= y + x - 1 ; m++) {
ledDrive.setLed(0, z, m, 0 );
delay (w) ;
}
for (int k = x; k <= y + x - 1 ; k++) {
ledDrive.setLed(0, z, k, 1 );
delay (w) ;
}
}
//########################################## function sevenSegWrite ####################################################################
void sevenSegWrite(byte digit) { // display a number on the digital segment display
digitalWrite(latchPin, LOW); // set the latchPin to low potential, before sending data
shiftOut(dataPin, clockPin, LSBFIRST, seven_seg_digits[digit]); // Move the value of 'seven_seg_digits[digit]' in byte form via the 'dataPin' one bit at a time. https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
digitalWrite(latchPin, HIGH); // set the latchPin to high potential, after sending data
}
//######################################### function sandTimer ##################################################################
void sandTimer () {
int ledRowBegin = 1 ;
int ledRowEnd = 6 ;
int ledWidthBegin = 6 ;
int ledWidthEnd = 6 ;
int ledStartPosBegin = 1 ;
int ledStartPosEnd = 1 ;
int byteConvValBegin = 0 ;
int byteConvValEnd = 0 ;
sevenSegWrite(sandSeconds); // perform function 'sevenSeqWrite' and pass the value 'sandSeconds' to it //
for (int x = 0; x <= 7; x++ ) {
ledDrive.setRow(0, x, glassFrame [x] [0]); // Use the setRow function to light the leds according to values of array "glassFrame"
}
for (int x = 0; x <= 2; x++ ) {
ledDrive.setRow(0, x, sandSurface [x] [0]); // Use the setRow function 'fill' the sand on rows 1,2 & 3 according to values of array "sandSurface"
}
while ( digitalRead(13) == HIGH ) { // stay in this while loop as long as pin 13 button is not pressed
while (digitalRead (sandTimeSelect) == LOW) { // stay in this while loop as long as sandTimeSelect button is pressed
sandSeconds = sandSeconds - 1 ;
sevenSegWrite(sandSeconds); // perform function 'sevenSeqWrite' and pass the value 'sandSeconds' to it //
delay (1000) ;
if (sandSeconds == 0) {
sandSeconds = 7 ;
}
} // repeat the inner while loop as long as the sandTimeSelect button is pressed
} // repeat the outer while loop as long as pin 13 button isn't pressed
sandPeriod = sandSeconds * 2500 ; // calculate time for sandPeriod to make up the number of seconds sandSeconds times 10
for (int sandLevel = 0 ; sandLevel <= 2 ; sandLevel++ ) {
unsigned long flashPeriodStart = millis() ;
while ( millis() - flashPeriodStart < sandPeriod) {
sandFlowOut (rowValue, byteConvValBegin, sandSpeed, ledStartPosBegin, ledWidthBegin, sandLevel) ;
ledDrive.setRow(0, sandLevel, glassFrame [sandLevel] [0]); // Use the setRow function to light the leds according to values of array "glassFrame"
sandFlowIn (sandSpeed, ledStartPosEnd , ledWidthEnd , 7 - sandLevel ) ;
}
ledWidthBegin = ledWidthBegin - 2 ;
ledWidthEnd = ledWidthEnd - 2 ;
ledStartPosBegin = ledStartPosBegin + 1 ;
ledStartPosEnd = ledStartPosEnd + 1 ;
}
unsigned long flashPeriodStart = millis() ;
while ( millis() - flashPeriodStart < sandPeriod) {
sandFlowIn (sandSpeed, 3 , 2 , 3 ) ;
sandFlowIn (sandSpeed, 3 , 2 , 4 ) ;
for (int i = 0; i < 4; i++)
{
digitalWrite(buzzer, HIGH);
delay(4);//wait for 1ms
digitalWrite(buzzer, LOW);
delay(4);//wait for 1ms
}
delay (20) ;
for (int i = 0; i < 4; i++)
{
digitalWrite(buzzer, HIGH);
delay(4);//wait for 1ms
digitalWrite(buzzer, LOW);
delay(4);//wait for 1ms
}
}
delay (sandSpeed) ;
for (int f = 1; f <= 3 ; f++ ) {
for (int x = 0; x <= 7; x++ ) {
ledDrive.setRow(0, x, glassFrame [x] [0]); // Use the setRow function to light the leds according to values of array "glassFrame"
}
for (int i = 0; i < 80; i++)
{
digitalWrite(buzzer, HIGH);
delay(4);//wait for 4ms
digitalWrite(buzzer, LOW);
delay(4);//wait for 4ms
}
delay (250) ;
ledDrive.clearDisplay(0);
delay (200) ;
for (int x = 0; x <= 2; x++ ) {
ledDrive.setRow(0, x, sandSurface [x] [0]); // Use the setRow function 'fill' the sand on rows 1,2 & 3 according to values of array "sandSurface"
}
}
}
//######################################### function twoDice ##################################################################
void twoDice () {
int dieValue1 = 1 ; // declare local variable "dieValue1" and set it to value 1
int dieValue2 = 1 ; // declare local variable "dieValue2" and set it to value 1
int buttonPressed = digitalRead(13); // declare variable "buttonPressed" and set it to the value on Uno pin 2
if (buttonPressed == LOW) { // If the button is pressed, perform the for structure below or go to the else structure lower down.
for (int i = 0; i <= 10; i++) { // Repeat the following code ten times
int diceSpin = random(1, 7); // set variable "diceSpin" to a random value from 1 to 6
dieValue1 = diceSpin ; // set variable "dieValue1" to the value of "diceSpin
diceSpin = random(1, 7); // set variable "diceSpin" to a random value from 1 to 6
dieValue2 = diceSpin ; // set variable "dieValue2" to the value of "diceSpin
int p = dieValue1 - 1; // declare local variable "p" and set it to value of "dieValue1" minus 1
ledDrive.setRow(0, 0, diePattern [p] [0]); // Use the setRow function for row 1 of the led matrix according to the value of array "diePattern" "p"
ledDrive.setRow(0, 1, diePattern [p] [1]); // Use the setRow function for row 2 of the led matrix according to the value of array "diePattern" "p"
ledDrive.setRow(0, 2, diePattern [p] [2]); // Use the setRow function for row 3 of the led matrix according to the value of array "diePattern" "p"
int q = dieValue2 - 1; // declare local variable "q" and set it to value of "dieValue2" minus 1
ledDrive.setRow(0, 5, diePattern [q] [0]); // Use the setRow function for row 6 of the led matrix according to the value of array "diePattern" "q"
ledDrive.setRow(0, 6, diePattern [q] [1]); // Use the setRow function for row 7 of the led matrix according to the value of array "diePattern" "q"
ledDrive.setRow(0, 7, diePattern [q] [2]); // Use the setRow function for row 8 of the led matrix according to the value of array "diePattern" "q"
delay(150); // wait 200 mS
} // Once the above for code has been repeated 10 times continue with the program
int diceSpin = random(1, 7); // set variable "diceSpin" to a random value from 1 to 6
dieValue1 = diceSpin ; // set variable "dieValue1" to the value of "diceSpin
diceSpin = random(1, 7); // set variable "diceSpin" to a random value from 1 to 6
dieValue2 = diceSpin ; // set variable "dieValue2" to the value of "diceSpin
int i = dieValue1 - 1; // declare local variable "i" and set it to value of "dieValue1" minus 1
ledDrive.setRow(0, 0, diePattern [i] [0]); // Use the setRow function for row 1 of the led matrix according to the value of array "diePattern" "i"
ledDrive.setRow(0, 1, diePattern [i] [1]); // Use the setRow function for row 2 of the led matrix according to the value of array "diePattern" "i"
ledDrive.setRow(0, 2, diePattern [i] [2]); // Use the setRow function for row 3 of the led matrix according to the value of array "diePattern" "i"
int j = dieValue2 - 1; // declare local variable "j" and set it to value of "dieValue2" minus 1
ledDrive.setRow(0, 5, diePattern [j] [0]); // Use the setRow function for row 6 of the led matrix according to the value of array "diePattern" "j"
ledDrive.setRow(0, 6, diePattern [j] [1]); // Use the setRow function for row 7 of the led matrix according to the value of array "diePattern" "j"
ledDrive.setRow(0, 7, diePattern [j] [2]); // Use the setRow function for row 8 of the led matrix according to the value of array "diePattern" "j"
} else { // when the button is not pressed the code will continue from here
buttonPressed = digitalRead(2); // Set the variable "buttonPressed to the value of Uno pin 2
while (buttonPressed == HIGH) { // While the button is not pressed
buttonPressed = digitalRead(2); // Set the variable "buttonPressed to the value of Uno pin 2
} // Repeat this while loop as long as the button is not pressed
} // end of the else structure
}
//\\\\\\\\\\\\\\\\\\\\\\\\\\LOOP--------LOOP////////////////////////////////////////////////
void loop() {
sevenSegWrite(10); // perform function 'sevenSeqWrite' and pass the value '10' to it (All segments OFF//
while ( digitalRead(13) == HIGH ) { // stay in this while loop as long as pin 13 button is not pressed
while (digitalRead (sandTimeSelect) == LOW) { // stay in this while loop as long as sandTimeSelect button is pressed
toggle = toggle - 1 ;
for (int x = 0; x <= 7; x++ ) {
ledDrive.setRow(0, x, letterSorD [x] [toggle]); // Use the setRow function to light the leds according to values of array "glassFrame"
}
delay (1000) ;
if (toggle == 0) {
toggle = 2 ;
}
}
}
if (toggle == 1) {
while (toggle == 1) {
delay (500) ;
sandTimer () ;
}
}
if (toggle == 2) {
ledDrive.clearDisplay(0); // and clear the display
while (toggle == 2) {
delay (500) ;
twoDice () ;
}
}
}