// Use the MD_MAX72XX library to display a Pacman animation
// Just for fun!
#include <Button2.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#define DEBUG 1 // Enable or disable (default) debugging output
#if DEBUG
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); } // Print a string followed by a value (decimal)
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(v, HEX); } // Print a string followed by a value (hex)
#define PRINTB(s, v) { Serial.print(F(s)); Serial.print(v, BIN); } // Print a string followed by a value (binary)
#define PRINTC(s, v) { Serial.print(F(s)); Serial.print((char)v); } // Print a string followed by a value (char)
#define PRINTS(s) { Serial.print(F(s)); } // Print a string
#else
#define PRINT(s, v) // Print a string followed by a value (decimal)
#define PRINTX(s, v) // Print a string followed by a value (hex)
#define PRINTB(s, v) // Print a string followed by a value (binary)
#define PRINTC(s, v) // Print a string followed by a value (char)
#define PRINTS(s) // Print a string
#endif
// --------------------
// MD_MAX72xx hardware definitions and object
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
//
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 11
#define CLK_PIN 18 // or SCK
#define DATA_PIN 23 // or MOSI
#define CS_PIN 5 // or SS
#define BUTTON_ACTION_PIN 32
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); // SPI hardware interface
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // Arbitrary pins
Button2 buttonAction;
// --------------------
// Constant parameters
//
#define ANIMATION_DELAY 25 // milliseconds
#define MAX_FRAMES 4 // number of animation frames
uint8_t PAUSE = 0;
// ========== General Variables ===========
//
const uint8_t pacman[MAX_FRAMES][18] = // ghost pursued by a pacman
{
{ 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0x7e, 0xff, 0xe7, 0xc3, 0x81, 0x00 },
{ 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xe7, 0xe7, 0x42, 0x00 },
{ 0xfe, 0x73, 0xfb, 0x7f, 0xf3, 0x7b, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xe7, 0x66, 0x24 },
{ 0xfe, 0x7b, 0xf3, 0x7f, 0xf3, 0x7b, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c },
};
const uint8_t DATA_WIDTH = (sizeof(pacman[0]) / sizeof(pacman[0][0]));
uint32_t prevTimeAnim = 0; // remember the millis() value in animations
int16_t idx; // display index (column)
uint8_t frame; // current animation frame
uint8_t deltaFrame; // the animation frame offset for the next frame
// ========== Control routines ===========
//
void resetMatrix(void)
{
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY / 2);
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
mx.clear();
}
void click(Button2 &btn) {
PRINTS("Button clicked");
PAUSE = (PAUSE == 0) ? 1 : 0;
}
void setup()
{
Serial.begin(115200);
PRINTS("\n[MD_MAX72XX PakuPaku]");
mx.begin();
resetMatrix();
prevTimeAnim = millis();
buttonAction.begin(BUTTON_ACTION_PIN);
buttonAction.setClickHandler(click);
}
void printDots() {
// Lay out the dots
//let pi = player.x > 50 ? rndi(1, 6) : rndi(10, 15);
uint8_t playerX = 30;
uint8_t powerDotBoundary = MAX_DEVICES / 3;
uint8_t powerDot = playerX > 50 ? random(1, powerDotBoundary) : random(powerDotBoundary * 2, MAX_DEVICES);
for (uint8_t i = 0; i < MAX_DEVICES; i++) {
mx.setPoint(3, (i * COL_SIZE) + 3, true);
mx.setPoint(3, (i * COL_SIZE) + 4, true);
mx.setPoint(4, (i * COL_SIZE) + 3, true);
mx.setPoint(4, (i * COL_SIZE) + 4, true);
if (i == powerDot) {
mx.setPoint(2, (i * COL_SIZE) + 3, true);
mx.setPoint(2, (i * COL_SIZE) + 4, true);
mx.setPoint(3, (i * COL_SIZE) + 2, true);
mx.setPoint(3, (i * COL_SIZE) + 5, true);
mx.setPoint(4, (i * COL_SIZE) + 2, true);
mx.setPoint(4, (i * COL_SIZE) + 5, true);
mx.setPoint(5, (i * COL_SIZE) + 3, true);
mx.setPoint(5, (i * COL_SIZE) + 4, true);
}
}
}
void loop(void)
{
static boolean bInit = true; // initialise the animation
// Is it time to animate?
if (millis() - prevTimeAnim < ANIMATION_DELAY)
return;
prevTimeAnim = millis(); // starting point for next time
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
if (PAUSE) {
return;
}
// Initialize
if (bInit)
{
mx.clear();
idx = -DATA_WIDTH;
frame = MAX_FRAMES - 1, //0;
deltaFrame = 1;
bInit = false;
printDots();
}
// now run the animation
PRINT("\nINV I:", idx);
PRINT(" frame ", frame);
// clear old graphic
for (uint8_t i = 0; i < DATA_WIDTH; i++) {
mx.setColumn(idx - DATA_WIDTH + i, 0);
}
// move reference column and draw new graphic
idx++;
for (uint8_t i = 0; i < DATA_WIDTH; i++) {
mx.setColumn(idx - DATA_WIDTH + i, pacman[frame][i]);
}
// advance the animation frame
frame -= deltaFrame;
if (frame == 0 || frame == MAX_FRAMES - 1) {
deltaFrame = -deltaFrame;
}
// check if we are completed and set initialise for next time around
bInit = (idx == mx.getColumnCount() + DATA_WIDTH);
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
return;
}