// 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 IMMEDIATE_NEW 0 // if 1 will immediately display a new message
#define USE_POT_CONTROL 1
#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::PAROLA_HW
#define MAX_DEVICES 20
#define CLK_PIN 52 // or SCK
#define DIN 51 // or MOSI
#define CS_PIN 53 // or SS
// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// Scrolling parameters
#if USE_POT_CONTROL
#define SPEED_IN A5
#else
#define SCROLL_DELAY 75 // in milliseconds
#endif // USE_POT_CONTROL
#define CHAR_SPACING 1 // pixels between characters
// Global message buffers shared by Serial and Scrolling functions
#define BUF_SIZE 880
uint8_t curMessage[BUF_SIZE] = { "Merivale Bowling Centre * Bowling Lanes * Snack Bar * Arcade * Fun Prizes * Bar * Birthday Parties * Receptions * Special Occasions * OPEN 7 DAYS A WEEK, DAY AND NIGHT, WE ARE ALWAYS AROUND FOR A DAY OR AN EVENING OUT. WE HAVE 48 LANES WITH COMPUTERIZED SCORING, AN ARCADE, AND A FULLY LICENSED RESTAURANT. * JOIN YOUR FRIENDS OR BRING YOUR FAMILY FOR GOOD TIMES TO BE HAD BY ALL! FRIDAY AND SATURDAY NIGHTS ARE ROCK AND BOWL NIGHTS! THIS IS 5 PIN BOWLING AT ITS FINEST! * REMEMBER TO LIKE US ON FACEBOOK AND FOLLOW US ON TWITTER FOR IMPORTANT UPDATES! * YES, WE ARE OPEN ON FAMILY DAY! * YES, WE ARE OPEN ON THANKS GIVING DAY! * YES, WE ARE OPEN ON EASTER! * WE CLOSE ON JULY 1ST AND JULY 2ND. * WE CLOSE ON THE 24/25TH OF DECEMBER AND REOPEN BOXING DAY THE 26TH FOR 5PM. * YES, WE ARE OPEN ON NEW YEARS EVE FROM 10AM - 10PM. NEW YEARS DAY FROM 11AM - 10PM. * WE EVEN CLOSE FOR THE STORM CLEANUP FOR 3 DAYS ONLY IF WE EVEN LOST POWER IN CASE OF STORM SUCH AS HURRICANES, TORNADOES, SEVERE THUNDERSTORMS AND ANY KIND OF NATURAL DISASTER. * We are Located in the following address: 1916 Merivale Road Ottawa, Ontario K2G 1E8 * Follow us on facebook: Merivale Bowling Centre * Call us: (613) 228-9190 Ext: 0 * ENJOY 'TIL YOU LAST! WE ARE OPEN! BOWL A STRIKE AND WIN! * Merivale Bowling Centre - Your #1 location for all your happy games. * " };
uint8_t newMessage[BUF_SIZE];
bool newMessageAvailable = false;
uint16_t scrollDelay; // in milliseconds
void readSerial(void)
{
static uint8_t putIndex = 0;
while (Serial.available())
{
newMessage[putIndex] = (char)Serial.read();
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 uint8_t* p = curMessage;
static enum { NEW_MESSAGE, LOAD_CHAR, SHOW_CHAR, BETWEEN_CHAR } state = LOAD_CHAR;
static uint8_t curLen, showLen;
static uint8_t cBuf[15];
uint8_t colData = 0; // blank column is the default
#if IMMEDIATE_NEW
if (newMessageAvailable) // there is a new message waiting
{
state = NEW_MESSAGE;
mx.clear(); // clear the display
}
#endif
// finite state machine to control what we do on the callback
switch (state)
{
case NEW_MESSAGE: // Load the new message
memcpy(curMessage, newMessage, BUF_SIZE); // copy it in
newMessageAvailable = false; // used it!
p = curMessage;
state = LOAD_CHAR;
break;
case LOAD_CHAR: // Load the next character from the font table
showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
curLen = 0;
state = SHOW_CHAR;
// if we reached end of message, opportunity to load the next
if (*p == '\0')
{
p = curMessage; // reset the pointer to start of message
#if !IMMEDIATE_NEW
if (newMessageAvailable) // there is a new message waiting
{
state = NEW_MESSAGE; // we will load it here
break;
}
#endif
}
// !! deliberately fall through to next state to start displaying
case SHOW_CHAR: // display the next part of the character
colData = cBuf[curLen++];
if (curLen == showLen)
{
showLen = CHAR_SPACING;
curLen = 0;
state = BETWEEN_CHAR;
}
break;
case BETWEEN_CHAR: // display inter-character spacing (blank columns)
colData = 0;
curLen++;
if (curLen == showLen)
state = LOAD_CHAR;
break;
default:
state = LOAD_CHAR;
}
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
}
}
uint16_t getScrollDelay(void)
{
#if USE_POT_CONTROL
uint16_t t;
t = analogRead(SPEED_IN);
t = map(t, 0, 1023, 25, 250);
return (t);
#else
return (SCROLL_DELAY);
#endif
}
void setup()
{
mx.begin();
mx.setShiftDataInCallback(scrollDataSource);
mx.setShiftDataOutCallback(scrollDataSink);
#if USE_POT_CONTROL
pinMode(SPEED_IN, INPUT);
#else
scrollDelay = SCROLL_DELAY;
#endif
newMessage[0] = '\0';
Serial.begin(57600);
Serial.print("\n[MD_MAX7219 Message Display Marquee]\nMerivale Bowling Marquee");
pinMode(12, OUTPUT);
tone(12, 880, 100);
}
void loop()
{
scrollDelay = getScrollDelay();
readSerial();
scrollText();
}
mega:SCL
mega:SDA
mega:AREF
mega:GND.1
mega:13
mega:12
mega:11
mega:10
mega:9
mega:8
mega:7
mega:6
mega:5
mega:4
mega:3
mega:2
mega:1
mega:0
mega:14
mega:15
mega:16
mega:17
mega:18
mega:19
mega:20
mega:21
mega:5V.1
mega:5V.2
mega:22
mega:23
mega:24
mega:25
mega:26
mega:27
mega:28
mega:29
mega:30
mega:31
mega:32
mega:33
mega:34
mega:35
mega:36
mega:37
mega:38
mega:39
mega:40
mega:41
mega:42
mega:43
mega:44
mega:45
mega:46
mega:47
mega:48
mega:49
mega:50
mega:51
mega:52
mega:53
mega:GND.4
mega:GND.5
mega:IOREF
mega:RESET
mega:3.3V
mega:5V
mega:GND.2
mega:GND.3
mega:VIN
mega:A0
mega:A1
mega:A2
mega:A3
mega:A4
mega:A5
mega:A6
mega:A7
mega:A8
mega:A9
mega:A10
mega:A11
mega:A12
mega:A13
mega:A14
mega:A15
matrix1:V+
matrix1:GND
matrix1:DIN
matrix1:CS
matrix1:CLK
matrix1:V+.2
matrix1:GND.2
matrix1:DOUT
matrix1:CS.2
matrix1:CLK.2
pot1:GND
pot1:SIG
pot1:VCC
bz1:1
bz1:2
matrix2:V+
matrix2:GND
matrix2:DIN
matrix2:CS
matrix2:CLK
matrix2:V+.2
matrix2:GND.2
matrix2:DOUT
matrix2:CS.2
matrix2:CLK.2