Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 2 | ||||
| × | 1 |
For years I've had many people come to see me in my office and struggle with understanding that I'm on a video call with someone from my computer. So when I started working on Arduino for my chicken coop - more to come later - I came across the 8x8 LED matrix and the ability to gang them together. No I have a 64x8 scrolling marquee that allows me to announce to my visitors that I'm on a call, or out to lunch, or anything else that I have pre-programmed into my RS232 interface to control the marquee. Depending on the length of the message it may even scroll!
I used the examples from the MD_MAX72XX library to help me piece these together.
Here's a video of one scrolling message:
My Scrolling Marquee
ArduinoMy first public posting of code. Please feel free to comment back with suggestions. I used 2 samples and pieced them together based on the status of D2 for controlling of scrolling the message.
// kayaking_t
// my office marquee - currently connected via Contact Closure and RS232 to a Crestron MP3E for message control.
//
// Use the MD_MAX72XX library to scroll text on the display
//
// Demonstrates the use of the callback function to control what
// is scrolled on the display text.
//
// User can enter text on the serial monitor and this will display as a
// scrolling message on the display.
// Speed for the display is controlled by a pot on SPEED_IN analog in.
#include <MD_MAX72xx.h>
#include <SPI.h>
#define PRINT_CALLBACK 0
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
// 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::FC16_HW
#define MAX_DEVICES 8
#define CLK_PIN 13 // Digital or SCK - // originally pin 13
#define DATA_PIN 11 // PWM or MOSI - // originally pin 11
#define CS_PIN 10 // PWM or SS - // originally pin 10
// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Scrolling parameters
#define SCROLL_DELAY 75 // in milliseconds
#define CHAR_SPACING 1 // pixels between characters
// Global message buffers shared by Serial and Scrolling functions
#define BUF_SIZE 75
char curMessage[BUF_SIZE];
char newMessage[BUF_SIZE];
bool newMessageAvailable = false;
uint16_t scrollDelay; // in milliseconds
// scrolling/static switch status
const int scrollSwitch = 2;
int scrollYes = 0;
void readSerial(void)
{
static uint8_t putIndex = 0;
while (Serial.available())
{
newMessage[putIndex] = (char)Serial.read();
//Serial.println(newMessage);
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
putIndex++;
}
}
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
// Callback function for data that is being scrolled off the display
{
#if PRINT_CALLBACK
Serial.print("\n cb ");
Serial.print(dev);
Serial.print(' ');
Serial.print(t);
Serial.print(' ');
Serial.println(col);
#endif
}
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
// Callback function for data that is required for scrolling into the display
{
static char *p = curMessage;
static uint8_t state = 0;
static uint8_t curLen, showLen;
static uint8_t cBuf[8];
uint8_t colData;
// finite state machine to control what we do on the callback
switch(state)
{
case 0: // Load the next character from the font table
showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
curLen = 0;
state++;
// if we reached end of message, reset the message pointer
if (*p == '\0')
{
p = curMessage; // reset the pointer to start of message
if (newMessageAvailable) // there is a new message waiting
{
strcpy(curMessage, newMessage); // copy it in
newMessageAvailable = false;
}
}
// !! deliberately fall through to next state to start displaying
case 1: // display the next part of the character
colData = cBuf[curLen++];
if (curLen == showLen)
{
showLen = CHAR_SPACING;
curLen = 0;
state = 2;
}
break;
case 2: // display inter-character spacing (blank column)
colData = 0;
curLen++;
if (curLen == showLen)
state = 0;
break;
default:
state = 0;
}
return(colData);
}
void scrollText(void)
{
static uint32_t prevTime = 0;
// Is it time to scroll the text?
if (millis()-prevTime >= scrollDelay)
{
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
prevTime = millis(); // starting point for next time
}
}
void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
// Print the text string to the LED matrix modules specified.
// Message area is padded with blank columns after printing.
{
uint8_t state = 0;
uint8_t curLen;
uint16_t showLen;
uint8_t cBuf[8];
int16_t col = ((modEnd + 1) * COL_SIZE) - 1;
mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
do // finite state machine to print the characters in the space available
{
switch(state)
{
case 0: // Load the next character from the font table
// if we reached end of message, reset the message pointer
if (*pMsg == '\0')
{
showLen = col - (modEnd * COL_SIZE); // padding characters
state = 2;
break;
}
// retrieve the next character form the font file
showLen = mx.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
curLen = 0;
state++;
// !! deliberately fall through to next state to start displaying
case 1: // display the next part of the character
mx.setColumn(col--, cBuf[curLen++]);
// done with font character, now display the space between chars
if (curLen == showLen)
{
showLen = CHAR_SPACING;
state = 2;
}
break;
case 2: // initialize state for displaying empty columns
curLen = 0;
state++;
// fall through
case 3: // display inter-character spacing or end of message padding (blank columns)
mx.setColumn(col--, 0);
curLen++;
if (curLen == showLen)
state = 0;
break;
default:
col = -1; // this definitely ends the do loop
}
} while (col >= (modStart * COL_SIZE));
mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}
void setup()
{
mx.begin();
mx.setShiftDataInCallback(scrollDataSource);
mx.setShiftDataOutCallback(scrollDataSink);
scrollDelay = SCROLL_DELAY;
strcpy(curMessage, "AV Rocks! ");
newMessage[0] = '\0';
Serial.begin(57600);
Serial.print("\n[MD_MAX72XX Message Display]\nType a message for the scrolling display\nEnd message line with a newline");
}
void loop()
{
scrollYes = digitalRead(scrollSwitch);
readSerial();
if (scrollYes == 0){
printText(0, MAX_DEVICES-1, newMessage);
} else {
scrollText();
}
}
Comments
Please log in or sign up to comment.