Spaceballs Dot Matrix

First post for me here. I am making a holloween costume this year. I am making a dot matrix costume for my wife. I am using 5 8x8 max7219 dot matrixes and a arduino uno. The matrix will be on her chest. In the movie spaceballs dot matrix has a virgin alert mode. I have been using the example code daft punk. I modified the code so instead of daft punk it says virgin alert. What i want to do is have it run the animations while walking around but when she walks up to somebody she pushes a button and it will spell out virgin alert and activate an led. I have been trying figure it out for about a month and cant get it. Any suggestions i would appreciate it. I have a short video of what i have done so far.

Any suggestions i would appreciate it.

Start by posting your code and describing the problems that you are having

See "How to use this forum" for posting instructions.

I am trying to post pictures with my phone but its not going. I will post the code when i can get to my desktop.

Usually ppl wait until, um, October 26 or 27 to realize they need help with some Halloween electronics.

So good on you for starting with what should be plenty of time: good luck!

a7

Here is my setup.

Thank you. Last year i was that guy who waited till the week before halloween. This year i am doing it early. I finished my barf and most of dark helmet.

OK. Looks like you are using the MD_MAX72xx library and are modifying the daft punk example code for that library.

You need to implement 2 modes of operation that are changed over by the switch, and you may need to understand how to detect when the switch changes over rather than just that is is pressed or not, but you need to explain a bit more how you want this to work:

  1. Is the switch pressed once to change the the virgin mode and then switch again to change back or does virgin mode only work while the switch is pressed?

  2. What does "activate an led" mean?

You nailed it. I want the virgin alert to kick on when u press the button once run for 20-30 seconds then go back to the animations. But now that you mention it having it turn off virgin alert on second press would be pretty useful.

The led activation is because eventually i want to us an mp3 adafruit board to play the virgin alert alarm. But that would be icing on the cake. Right now i am just trying to get the virgin alert text to pop up when i want it to.

The Daft Punk example runs in cyclic mode when the #define RUN_DEMO is 1, if you set it to 0 it will change animation when you press a tact switch (momentary on). This give you a clue as to how to switch to a different animation.

When RUN_DEMO is 0, code is compiled to handle the switching. This is easy to identify as it be bracketed inside a #if RUN_DEMO == 0 (or 1) block.

That is correct. I like demo mode becuase it cycles the animation automatically. That way my wife can be walking around and people will be entertained by the animations. Then she can walk up to somebody press the button and pretend they are the reason her virgin alert goes off.

So what i am trying to figure out is how do i make it stop cycle when pressed and resume cycle when pressed.

I tried to post the code but it was over the 9000 character limit.

Whenever you detect the switch is pressed, set a global variable true or false (basically 'not' the variable with each press). In the main loop do something if the variable is true, do something else if the variable is false.

// Use the MD_MAX72XX library to Display a Daft Punk LED Helmet
//
// If RUN_DEMO is set to zero the display cycles changes triggered by a switch on
// the MODE_SWITCH pin. This can be substituted for any trigger as implemented
// by the helmet wearer.
// If RUN_DEMO is set to 1 the sketch will cycle each element of the display every
// DEMO_DELAY seconds, without the need for a switch.
//
// Uses the MD_UISwitch library found at https://github.com/MajicDesigns/MD_UISwitch

#define RUN_DEMO 0

#include <MD_MAX72xx.h>
#include <SPI.h>

#if RUN_DEMO
#define DEMO_DELAY 15 // time to show each demo element in seconds
#else
#include <MD_UISwitch.h>
#endif

#define DEBUG 0 // 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 MAX_DEVICES 5
#define CLK_PIN 13 // or SCK
#define DATA_PIN 11 // or MOSI
#define CS_PIN 10 // or SS

MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES); // SPI hardware interface
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // Arbitrary pins

#if !RUN_DEMO
// --------------------
// Mode keyswitch parameters and object
//
#define MODE_SWITCH 9 // Digital Pin

MD_UISwitch_Digital ks = MD_UISwitch_Digital(MODE_SWITCH, LOW);
#endif

// --------------------
// Constant parameters
//
// Various delays in milliseconds
#define UNIT_DELAY 25
#define SCROLL_DELAY (4 * UNIT_DELAY)
#define MIDLINE_DELAY (6 * UNIT_DELAY)
#define SCANNER_DELAY (2 * UNIT_DELAY)
#define RANDOM_DELAY (6 * UNIT_DELAY)
#define FADE_DELAY (8 * UNIT_DELAY)
#define SPECTRUM_DELAY (4 * UNIT_DELAY)
#define HEARTBEAT_DELAY (1 * UNIT_DELAY)
#define HEARTS_DELAY (28 * UNIT_DELAY)
#define EYES_DELAY (20 * UNIT_DELAY)
#define WIPER_DELAY (1 * UNIT_DELAY)
#define ARROWS_DELAY (3 * UNIT_DELAY)
#define ARROWR_DELAY (8 * UNIT_DELAY)
#define INVADER_DELAY (6 * UNIT_DELAY)
#define PACMAN_DELAY (4 * UNIT_DELAY)
#define SINE_DELAY (2 * UNIT_DELAY)

#define CHAR_SPACING 1 // pixels between characters
#define BUF_SIZE 75 // character buffer size

// ========== General Variables ===========
//
uint32_t prevTimeAnim = 0; // Used for remembering the millis() value in animations
#if RUN_DEMO
uint32_t prevTimeDemo = 0; // Used for remembering the millis() time in demo loop
uint8_t timeDemo = DEMO_DELAY; // number of seconds left in this demo loop
#endif

// ========== Text routines ===========
//
// Text Message Table
// To change messages simply reorder, add to, or delete from, this table
char *msgTab =
{
“DAFT PUNK”,
“GET LUCKY”,
“ONE MORE TIME”,
“HARDER BETTER FASTER STRONGER”,
“HUMAN AND ROBOT”,
“TECHNOLOGIC”,
};

bool scrollText(bool bInit, char *pmsg)
// Callback function for data that is required for scrolling into the display
{
static char curMessage[BUF_SIZE];
static char *p = curMessage;
static uint8_t state = 0;
static uint8_t curLen, showLen;
static uint8_t cBuf[8];
uint8_t colData;

// are we initializing?
if (bInit)
{
PRINTS("\n— Initializing ScrollText");
resetMatrix();
strcpy(curMessage, pmsg);
state = 0;
p = curMessage;
bInit = false;
}

// Is it time to scroll the text?
if (millis()-prevTimeAnim < SCROLL_DELAY)
return(bInit);

// scroll the display
mx.transform(MD_MAX72XX::TSL); // scroll along
prevTimeAnim = millis(); // starting point for next time

// now run the finite state machine to control what we do
PRINT("\nScroll FSM S:", state);
switch (state)
{
case 0: // Load the next character from the font table
PRINTC("\nLoading ", *p);
showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
curLen = 0;
state = 1;

// !! deliberately fall through to next state to start displaying

case 1: // display the next part of the character
colData = cBuf[curLen++];
mx.setColumn(0, colData);
if (curLen == showLen)
{
showLen = ((*p != ‘\0’) ? CHAR_SPACING : mx.getColumnCount()-1);
curLen = 0;
state = 2;
}
break;

case 2: // display inter-character spacing (blank column) or scroll off the display
mx.setColumn(0, 0);
if (++curLen == showLen)
{
state = 0;
bInit = (*p == ‘\0’);
}
break;

default:
state = 0;
}

return(bInit);
}

========== Control routines ===========
//
void resetMatrix(void)
{
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY/2);
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
mx.clear();
prevTimeAnim = 0;
}

void runMatrixAnimation(void)
// Schedule the animations, switching to the next one when the
// the mode switch is pressed.
{
static uint8_t state = 0;
static uint8_t mesg = 0;
static boolean bRestart = true;
static boolean bInMessages = false;
boolean changeState = false;

#if RUN_DEMO
// check if one second has passed and then count down the demo timer. Once this
// gets to zero, change the state.
if (millis()-prevTimeDemo >= 1000)
{
prevTimeDemo = millis();
if (–timeDemo == 0)
{
timeDemo = DEMO_DELAY;
changeState = true;
}
}
#else
// check if the switch is pressed and handle that first
changeState = (ks.read() == MD_UISwitch::KEY_PRESS);
#endif
if (changeState)
{
if (bInMessages) // the message display state
{
mesg++;
if (mesg >= sizeof(msgTab)/sizeof(msgTab[0]))
{
mesg = 0;
bInMessages = false;
state++;
}
}
else
state++;

bRestart = true;
};

// now do whatever we do in the current state
switch(state)
{
case 0: bInMessages = true; bRestart = scrollText(bRestart, msgTab[mesg]); break;
case 1: bRestart = graphicMidline1(bRestart); break;
case 2: bRestart = graphicMidline2(bRestart); break;
case 3: bRestart = graphicScanner(bRestart); break;
case 4: bRestart = graphicRandom(bRestart); break;
case 5: bRestart = graphicFade(bRestart); break;
case 6: bRestart = graphicSpectrum1(bRestart); break;
case 7: bRestart = graphicHeartbeat(bRestart); break;
case 8: bRestart = graphicHearts(bRestart); break;
case 9: bRestart = graphicEyes(bRestart); break;
case 10: bRestart = graphicBounceBall(bRestart); break;
case 11: bRestart = graphicArrowScroll(bRestart); break;
case 12: bRestart = graphicScroller(bRestart); break;
case 13: bRestart = graphicWiper(bRestart); break;
case 14: bRestart = graphicInvader(bRestart); break;
case 15: bRestart = graphicPacman(bRestart); break;
case 16: bRestart = graphicArrowRotate(bRestart); break;
case 17: bRestart = graphicSpectrum2(bRestart); break;
case 18: bRestart = graphicSinewave(bRestart); break;

default: state = 0;
}
}

void setup()
{
mx.begin();
prevTimeAnim = millis();
#if RUN_DEMO
prevTimeDemo = millis();
#else
ks.begin();
#endif
#if DEBUG
Serial.begin(57600);
#endif
PRINTS("\n[MD_MAX72XX DaftPunk]");
}

void loop()
{
runMatrixAnimation();
// other code to run the helmet goes here
}

I posted the beginning an the end of the code. I left out the animations to meet the 9000 character limit.

// constants won’t change. They’re used here to set pin numbers:
const int buttonPin = 3; // the number of the pushbutton pin
const int ledPin = 4; // the number of the LED pin

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

#define RUN_DEMO 1

#include <MD_MAX72xx.h>
#include <SPI.h>

#if RUN_DEMO
#define DEMO_DELAY 10 // time to show each demo element in seconds
#else
#include <MD_UISwitch.h>
#endif

#define DEBUG 0 // 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

#define MAX_DEVICES 5
#define CLK_PIN 13 // or SCK
#define DATA_PIN 11 // or MOSI
#define CS_PIN 10 // or SS

MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES); // SPI hardware interface
//MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // Arbitrary pins

#if !RUN_DEMO
// --------------------
// Mode keyswitch parameters and object
//
#define MODE_SWITCH 9 // Digital Pin

MD_UISwitch_Digital ks = MD_UISwitch_Digital(MODE_SWITCH, LOW);
#endif

// --------------------
// Constant parameters
//
// Various delays in milliseconds
#define UNIT_DELAY 25
#define SCROLL_DELAY (4 * UNIT_DELAY)
#define MIDLINE_DELAY (6 * UNIT_DELAY)
#define SCANNER_DELAY (2 * UNIT_DELAY)
#define RANDOM_DELAY (6 * UNIT_DELAY)
#define FADE_DELAY (8 * UNIT_DELAY)
#define SPECTRUM_DELAY (4 * UNIT_DELAY)
#define HEARTBEAT_DELAY (1 * UNIT_DELAY)
#define HEARTS_DELAY (28 * UNIT_DELAY)
#define EYES_DELAY (20 * UNIT_DELAY)
#define WIPER_DELAY (1 * UNIT_DELAY)
#define ARROWS_DELAY (3 * UNIT_DELAY)
#define ARROWR_DELAY (8 * UNIT_DELAY)
#define INVADER_DELAY (6 * UNIT_DELAY)
#define PACMAN_DELAY (4 * UNIT_DELAY)
#define SINE_DELAY (2 * UNIT_DELAY)

#define CHAR_SPACING 1 // pixels between characters
#define BUF_SIZE 75 // character buffer size

// ========== General Variables ===========
//
uint32_t prevTimeAnim = 0; // Used for remembering the millis() value in animations
#if RUN_DEMO
uint32_t prevTimeDemo = 0; // Used for remembering the millis() time in demo loop
uint8_t timeDemo = DEMO_DELAY; // number of seconds left in this demo loop
#endif

// ========== Text routines ===========
//
// Text Message Table
// To change messages simply reorder, add to, or delete from, this table
char *msgTab =
{
“VIRGIN ALERT”,
};

bool scrollText(bool bInit, char *pmsg)
// Callback function for data that is required for scrolling into the display
{
static char curMessage[BUF_SIZE];
static char *p = curMessage;
static uint8_t state = 0;
static uint8_t curLen, showLen;
static uint8_t cBuf[8];
uint8_t colData;

// are we initializing?
if (bInit)
{
PRINTS("\n— Initializing ScrollText");
resetMatrix();
strcpy(curMessage, pmsg);
state = 0;
p = curMessage;
bInit = false;
}

// Is it time to scroll the text?
if (millis()-prevTimeAnim < SCROLL_DELAY)
return(bInit);

// scroll the display
mx.transform(MD_MAX72XX::TSL); // scroll along
prevTimeAnim = millis(); // starting point for next time

// now run the finite state machine to control what we do
PRINT("\nScroll FSM S:", state);
switch (state)
{
case 0: // Load the next character from the font table
PRINTC("\nLoading ", *p);
showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
curLen = 0;
state = 1;

// !! deliberately fall through to next state to start displaying

case 1: // display the next part of the character
colData = cBuf[curLen++];
mx.setColumn(0, colData);
if (curLen == showLen)
{
showLen = ((*p != ‘\0’) ? CHAR_SPACING : mx.getColumnCount()-1);
curLen = 0;
state = 2;
}
break;

case 2: // display inter-character spacing (blank column) or scroll off the display
mx.setColumn(0, 0);
if (++curLen == showLen)
{
state = 0;
bInit = (*p == ‘\0’);
}
break;

default:
state = 0;
}

return(bInit);
}

// ========== Graphic routines ===========

// ========== Control routines ===========
//
void resetMatrix(void)
{
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY/2);
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
mx.clear();
prevTimeAnim = 0;
}

void runMatrixAnimation(void)
// Schedule the animations, switching to the next one when the
// the mode switch is pressed.
{
static uint8_t state = 0;
static uint8_t mesg = 0;
static boolean bRestart = true;
static boolean bInMessages = false;
boolean changeState = false;

#if RUN_DEMO
// check if one second has passed and then count down the demo timer. Once this
// gets to zero, change the state.
if (millis()-prevTimeDemo >= 1000)
{
prevTimeDemo = millis();
if (–timeDemo == 0)
{
timeDemo = DEMO_DELAY;
changeState = true;
}
}
#else
// check if the switch is pressed and handle that first
changeState = (ks.read() == MD_UISwitch::KEY_PRESS);
#endif
if (changeState)
{
if (bInMessages) // the message display state
{
mesg++;
if (mesg >= sizeof(msgTab)/sizeof(msgTab[0]))
{
mesg = 0;
bInMessages = false;
state++;
}
}
else
state++;

bRestart = true;
};

// now do whatever we do in the current state
switch(state)
{
case 0: bInMessages = true; bRestart = scrollText(bRestart, msgTab[mesg]); break;
case 1: bRestart = graphicMidline1(bRestart); break;
case 2: bRestart = graphicMidline2(bRestart); break;
case 3: bRestart = graphicScanner(bRestart); break;
case 4: bRestart = graphicRandom(bRestart); break;
case 5: bRestart = graphicFade(bRestart); break;
case 6: bRestart = graphicSpectrum1(bRestart); break;
case 7: bRestart = graphicHeartbeat(bRestart); break;
case 8: bRestart = graphicHearts(bRestart); break;
case 9: bRestart = graphicEyes(bRestart); break;
case 10: bRestart = graphicBounceBall(bRestart); break;
case 11: bRestart = graphicArrowScroll(bRestart); break;
case 12: bRestart = graphicScroller(bRestart); break;
case 13: bRestart = graphicWiper(bRestart); break;
case 14: bRestart = graphicInvader(bRestart); break;
case 15: bRestart = graphicPacman(bRestart); break;
case 16: bRestart = graphicArrowRotate(bRestart); break;
case 17: bRestart = graphicSpectrum2(bRestart); break;
case 18: bRestart = graphicSinewave(bRestart); break;

default: state = 0;
}
}

void setup()
{
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
mx.begin();
prevTimeAnim = millis();
#if RUN_DEMO
prevTimeDemo = millis();
#else
ks.begin();
#endif
#if DEBUG
Serial.begin(57600);
#endif
PRINTS("\n[MD_MAX72XX DaftPunk]");
}

void loop()
{
runMatrixAnimation();
// other code to run the helmet goes here
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
}

ok so i made some progress i added a button on pin 3 that activates a led on 4. Solved that one. How do I set it up to start back on state 1 when i press the button? I wired it up to the reset button and it would start over to virgin alert but i didnt like the delay it took to show on the display. basically i want to combine Demo 0 and 1 mode. I hope this makes sense. Thank you.

i made some progress

Not really. You still have not learned to post code properly.

Thank you for the encouragement.