#include <LedControl.h>
#include <Encoder.h>
// Pin configuration
const int DIN_PIN = 11;
const int CLK_PIN = 13;
const int CS_PIN = 10;
// Encoder pins
const int ENCODER_PIN_A = 2;
const int ENCODER_PIN_B = 3;
const int ENCODER_BTN_PIN = 4; // Add this line for the encoder button
// Create an LedControl object
LedControl lc = LedControl(DIN_PIN, CLK_PIN, CS_PIN, 1);
// Create an Encoder object
Encoder myEncoder(ENCODER_PIN_A, ENCODER_PIN_B);
// Animation state
int currentAnimation = 0;
const int NUM_ANIMATIONS = 7; // Total number of animations
// Encoder variables
long encoderPosition = 0;
const int ENCODER_DETENT = 4; // Number of encoder steps per animation change
int encoderValue = 0;
// Animation timing variables
unsigned long previousMillis = 0;
const long animationInterval = 100; // Interval at which to run animation steps (milliseconds)
// Animation state variables
int animationStep = 0;
// Demo mode variables
bool demoMode = false;
unsigned long lastDemoChange = 0;
const unsigned long DEMO_INTERVAL = 5000; // Change animations every 5 seconds in demo mode
void setup() {
// Initialize the MAX7219 chip
lc.shutdown(0, false); // Wake up the MAX7219
lc.setIntensity(0, 8); // Set brightness (0-15)
lc.clearDisplay(0); // Clear the display
randomSeed(analogRead(0)); // Initialize random number generator
pinMode(ENCODER_BTN_PIN, INPUT_PULLUP); // Set up the encoder button pin
Serial.begin(9600); // Initialize serial communication for debugging
}
void loop() {
checkEncoderButton(); // Check if the encoder button is pressed
if (!demoMode) {
checkEncoder(); // Only check encoder if not in demo mode
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= animationInterval) {
previousMillis = currentMillis;
// Run the current animation step
runAnimationStep();
}
// Check if it's time to change animations in demo mode
if (demoMode && (currentMillis - lastDemoChange >= DEMO_INTERVAL)) {
lastDemoChange = currentMillis;
currentAnimation = (currentAnimation + 1) % NUM_ANIMATIONS;
animationStep = 0;
lc.clearDisplay(0);
Serial.print("Demo: Switched to animation ");
Serial.println(currentAnimation);
}
}
void checkEncoderButton() {
static bool lastButtonState = HIGH;
bool buttonState = digitalRead(ENCODER_BTN_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
// Button is pressed
demoMode = !demoMode; // Toggle demo mode
if (demoMode) {
Serial.println("Entering Demo Mode");
lastDemoChange = millis(); // Reset the demo change timer
} else {
Serial.println("Exiting Demo Mode");
}
delay(50); // Simple debounce
}
lastButtonState = buttonState;
}
void checkEncoder() {
long newPosition = myEncoder.read();
if (newPosition != encoderPosition) {
if (demoMode) {
// Exit demo mode if encoder is turned
demoMode = false;
Serial.println("Exiting Demo Mode (Encoder turned)");
}
encoderValue += (newPosition > encoderPosition) ? 1 : -1;
if (abs(encoderValue) >= ENCODER_DETENT) {
int direction = encoderValue > 0 ? 1 : -1;
currentAnimation = (currentAnimation + direction + NUM_ANIMATIONS) % NUM_ANIMATIONS;
lc.clearDisplay(0); // Clear display when changing animations
animationStep = 0; // Reset animation step
Serial.print("Switched to animation: ");
Serial.println(currentAnimation);
encoderValue = 0; // Reset the encoder value
}
encoderPosition = newPosition;
}
}
void runAnimationStep() {
switch (currentAnimation) {
case 0:
allOnOffStep();
break;
case 1:
chasingLedStep();
break;
case 2:
flashingPatternStep();
break;
case 3:
randomDotsStep();
break;
case 4:
rowChaseStep();
break;
case 5:
spectrumAnalyzerStep();
break;
case 6:
sequentialRowsStep();
break;
}
}
// Non-blocking animation functions
void allOnOffStep() {
if (animationStep == 0) {
for (int row = 0; row < 8; row++) {
lc.setRow(0, row, B11111111);
}
} else if (animationStep == 10) { // 1 second on (10 * 100ms)
lc.clearDisplay(0);
} else if (animationStep > 11) { // Reset after 1.1 seconds
animationStep = -1;
}
animationStep++;
}
void chasingLedStep() {
static int row = 0;
static int col = 0;
lc.setLed(0, row, col, false);
col++;
if (col > 7) {
col = 0;
row++;
if (row > 7) {
row = 0;
}
}
lc.setLed(0, row, col, true);
animationStep++;
if (animationStep >= 64) {
animationStep = 0;
}
}
void flashingPatternStep() {
byte pattern1 = B10101010;
byte pattern2 = B01010101;
for (int row = 0; row < 8; row++) {
lc.setRow(0, row, (animationStep % 2 == 0) ?
(row % 2 == 0 ? pattern1 : pattern2) :
(row % 2 == 0 ? pattern2 : pattern1));
}
animationStep++;
if (animationStep >= 10) { // Change pattern every 1 second (10 * 100ms)
animationStep = 0;
}
}
void randomDotsStep() {
if (animationStep % 2 == 0) {
int row = random(8);
int col = random(8);
lc.setLed(0, row, col, true);
} else {
lc.clearDisplay(0);
}
animationStep++;
if (animationStep >= 100) { // Reset after 10 seconds
animationStep = 0;
}
}
void rowChaseStep() {
static bool goingDown = true;
static int currentRow = 0;
lc.setRow(0, currentRow, B00000000); // Clear previous row
if (goingDown) {
currentRow++;
if (currentRow > 7) {
currentRow = 6;
goingDown = false;
}
} else {
currentRow--;
if (currentRow < 0) {
currentRow = 1;
goingDown = true;
}
}
lc.setRow(0, currentRow, B11111111); // Light up current row
animationStep++;
if (animationStep >= 16) { // Complete cycle
animationStep = 0;
}
}
void spectrumAnalyzerStep() {
for (int col = 0; col < 8; col++) {
int height = random(9); // Random height (0-8)
for (int row = 0; row < 8; row++) {
lc.setLed(0, row, col, row >= (8 - height));
}
}
animationStep++;
if (animationStep >= 20) { // New pattern every 2 seconds
animationStep = 0;
}
}
void sequentialRowsStep() {
static bool lightingUp = true;
if (lightingUp) {
lc.setRow(0, animationStep, B11111111);
animationStep++;
if (animationStep >= 8) {
lightingUp = false;
animationStep = 7;
}
} else {
lc.setRow(0, animationStep, B00000000);
animationStep--;
if (animationStep < 0) {
lightingUp = true;
animationStep = 0;
}
}
}