//Libraries needed for Matrix and RTC
#include <Wire.h>
#include <LedControl.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
//defines pins used for LED matrix
#define CLK_PIN 52
#define DATA_PIN 51
#define CS_PIN 53
//boolean variable that tells if a button is pushed or not... set to false initially
boolean isPushed = false;
//integers to store the analog pins for the buttons
int waterButton = A0;
int foodButton = A1;
int attentionButton = A2;
//integers that represent the time in hours when these begin
int nightBreak = 20;
int morningTime = 8;
//integers to store the current time in minutes and the next time for animations
int nowMin = 0;
int nextWaterTime = 0;
int nextAttentionTime = 0;
int nextFoodTime = 0;
//constants to store the minimum time period in minutes between each animation
const int minWaterPeriod = 200;
const int minAttentionPeriod = 300;
const int minFoodPeriod = 550;
//an 8 by 8 matrix that has 14 different images
boolean screenImage[14][8][8] = {
//idle 1
{ {0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 1, 0, 1, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0}
},
//idle 2
{ {0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 1, 0, 1, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0, 0}
},
//idle 3
{ {0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 1, 0, 1, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0}
},
//idle 4
{ {0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 0, 1, 0, 1, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0, 0}
},
//idle 5
{ {0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 1, 0, 1, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0}
},
//idle 6
{ {0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 1, 0, 1, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0, 0}
},
//water 1
{ {0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
},
//water 2
{ {0, 0, 1, 0, 0, 1, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
},
//water 3
{ {0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 1, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
},
//water 4
{ {0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 1, 0, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
},
//food (open mouth)
{ {1, 1, 0, 0, 0, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 0, 1},
{0, 1, 1, 0, 1, 0, 1, 0},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 1, 0, 1, 1, 0, 1, 0},
{0, 1, 1, 0, 0, 1, 1, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0}
},
//food (pizza)
{ {1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 0, 1, 0, 1},
{0, 1, 0, 1, 0, 0, 1, 0},
{0, 1, 0, 0, 1, 0, 1, 0},
{0, 0, 1, 1, 0, 1, 0, 0},
{0, 0, 1, 0, 1, 1, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0}
},
//attention (big heart)
{ {0, 1, 1, 0, 0, 1, 1, 0},
{1, 0, 0, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 0, 0, 1, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0}
},
//attention (small heart)
{ {0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 0, 0, 1, 1, 0},
{1, 0, 0, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1, 0},
{0, 0, 1, 0, 0, 1, 0, 0},
{0, 0, 0, 1, 1, 0, 0, 0}
}
};
//creates an object for the LED matrix using the LedControl library
LedControl ledMatrix = LedControl(51, 52, 53, 1);
//creates an object for the real-time clock using the DS1307RTC library
DS1307RTC realClock();
void setup() {
//turns on the LED matrix
ledMatrix.shutdown(0, false);
//sets the mode of each button to pull up so they are always on
pinMode(waterButton, INPUT_PULLUP);
pinMode(foodButton, INPUT_PULLUP);
pinMode(attentionButton, INPUT_PULLUP);
//seed the random number generator with a random value read from analog pin 10
randomSeed(analogRead(10));
}
void loop() {
//stores the last time the clock was checked
tmElements_t lastTimeCheck;
//reads the current time from the real-time clock and stores it in the lastTimeCheck variable
RTC.read(lastTimeCheck);
//calculates the current time in minutes by converting the hours to minutes and adding the minutes and subtracting the morning time in minutes from the total to get the time elapsed since the morning
nowMin = (lastTimeCheck.Hour * 60) + lastTimeCheck.Minute - (morningTime * 60);
//checks if the current hour is between nightBreak(20) and morningTime (8)
if ((lastTimeCheck.Hour >= nightBreak) || (lastTimeCheck.Hour < morningTime)) {
//if yes, it is nighttime and the idle animation is played
idleAni();
//time variables, set to 0 to start over again the next day
nowMin = 0;
nextWaterTime = 0;
nextAttentionTime = 0;
nextFoodTime = 0;
//if no, the idle animation is played, and the time for the animations is set
} else {
idleAni();
//when nextWaterTime is 0 (which it will be), a random value between 0 and minWaterPeriod is created and then stored in nextWaterTime
if (nextWaterTime == 0) {
nextWaterTime = random(minWaterPeriod);
}
//when nextAttentionTime is 0 (which it will be), a random value between 0 and minAttentionPeriod is created and then stored in nextAttentionTime
if (nextAttentionTime == 0) {
nextAttentionTime = random(minAttentionPeriod);
}
//when nextFoodTime is 0 (which it will be), a random value between 0 and minFoodPeriod is created and then stored in nextFoodTime
if (nextFoodTime == 0) {
nextFoodTime = random(minFoodPeriod);
}
//checks if the current time in minutes is greater than or equal to the nextWaterTime
if (nowMin >= nextWaterTime) {
//if yes, the water animation is played and the nextWaterTime is updated by adding minWaterPeriod and a random value between 0 and 81 to nowMin
waterAni();
nextWaterTime = nowMin + minWaterPeriod + random(81);
}
//checks if the current time in minutes is greater than or equal to the nextAttentionTime
if (nowMin >= nextAttentionTime) {
//if yes, the attention animation is played and the nextAttentionTime is updated by adding minAttentionPeriod and a random value between 0 and 121 to nowMin
attentionAni();
nextAttentionTime = nowMin + minAttentionPeriod + random(121);
}
//checks if the current time in minutes is greater than or equal to the nextFoodTime
if (nowMin >= nextFoodTime) {
//if yes, the food animation is played and the nextFoodTime is updated by adding minFoodPeriod and a random value between 0 and 61 to nowMin
foodAni();
nextFoodTime = nowMin + minFoodPeriod + random(61);
}
}
}
//function that performs the idle animation
void idleAni() {
//a for loop is run from 0 to 5 and the function frameSelecter is called with the current value
for (int x = 0; x <= 5; x++) {
frameSelecter(x);
//a 1.5-second delay between each image
delay(1500);
}
}
//function that performs the water animation
void waterAni() {
//a boolean variable is created to see if the button is on or off
boolean waterButtonState;
do {
//a for loop is run from 6 to 9 and the function frameSelecter is called with the current value
for (int x = 6; x <= 9; x++) {
frameSelecter(x);
//reads the state of the button
waterButtonState = digitalRead(waterButton);
//a .1 second delay between each image
delay(100);
}
//animation keeps on running until the button is pressed
} while (waterButtonState != isPushed);
}
//function that performs the food animation
void foodAni() {
//a boolean variable is created to see if the button is on or off
boolean foodButtonState;
do {
//a for loop is run from 10 to 11 and the function frameSelecter is called with the current value
for (int x = 10; x <= 11; x++) {
frameSelecter(x);
//reads the state of the button
foodButtonState = digitalRead(foodButton);
//a 2-second delay between each image
delay(2000);
}
//animation keeps on running until the button is pressed
} while (foodButtonState != isPushed);
}
//function that performs the attention animation
void attentionAni() {
//a boolean variable is created to see if the button is on or off
boolean attentionButtonState;
do {
//a for loop is run from 12 to 13 and the function frameSelecter is called with the current value
for (int x = 12; x <= 13; x++) {
frameSelecter(x);
//reads the state of the button
attentionButtonState = digitalRead(attentionButton);
//a .2 second delay between each image
delay(200);
}
//animation keeps on running until the button is pressed
} while (attentionButtonState != isPushed);
}
//a function that selects and displays a frame on a LED matrix
void frameSelecter(int frameNum) {
//loop through the rows of the LED matrix
for (int row = 0; row <= 7; row ++) {
//loop through the columns of the LED matrix
for (int col = 0; col <= 7; col ++) {
//sets the LEDs at the current row and column to the corresponding value in the screenImage array in order to display the correct frame
ledMatrix.setLed(0, row, col, screenImage [frameNum][row][col]);
}
}
}