//
// ESP32 64x8 64x8 Static, Scroll & Fade Four Messages - this script uses 4 sets of
// two 32x8 panels to create a four 64x8 message boards. It included the capability
// to both scroll and fade each of the messages independently.
//
// _SCROLL_ENABLED - set to true or false to enable/disable message scrolling
// _NON_SCROLL_POSITION - message position in pixels from left side starting with 0 when message isn't scrolling
// _FADE_ENABLED - set to true or false to enable/disable message fading in and out
// _FADE_RATE - an integer value from 0 to 8 defining the fade rate where 0 is the slowest and 8 is the fastest
// this value specifies the number of steps when the message fades in or out
// 0 = 256 steps 1 = 128 step 2 = 64 steps 3 = 32 steps 4 = 16 steps
// 5 = 8 steps 6 = 4 step 7 = 2 steps 8 = 1 step
// _FULL_ON_PAUSE_COUNT - an integer value from 0 to 100 defining the number of steps to pause during the fade
// when message is at completely on at full brightness
// _FULL_OFF_PAUSE_COUNT - an integer value from 0 to 100 defining the number of steps to pause during the fade
// when message is completely off
//
// -- Message Definitions ----------------------------------------------------------
#define MESSAGE_A "TITANIUM"
#define MESSAGE_A_SCROLL_ENABLED false // false or true
#define MESSAGE_A_NON_SCROLL_POSITION 21 // Pixels from left side starting with 0
#define MESSAGE_A_FADE_ENABLED true // false or true
#define MESSAGE_A_FADE_RATE 8 // Integer 0 to 8 for fade rate
#define MESSAGE_A_FULL_ON_PAUSE_COUNT 0 // Integer 0 to 100 for pause at fade full brightness
#define MESSAGE_A_FULL_OFF_PAUSE_COUNT 0 // Integer 0 to 100 for pause at fade completely off
#define MESSAGE_B "ELECTRICAL"
#define MESSAGE_B_SCROLL_ENABLED false
#define MESSAGE_B_NON_SCROLL_POSITION 15
#define MESSAGE_B_FADE_ENABLED true
#define MESSAGE_B_FADE_RATE 7
#define MESSAGE_B_FULL_ON_PAUSE_COUNT 2
#define MESSAGE_B_FULL_OFF_PAUSE_COUNT 2
#define MESSAGE_C "SOLUTIONS"
#define MESSAGE_C_SCROLL_ENABLED false
#define MESSAGE_C_NON_SCROLL_POSITION 18
#define MESSAGE_C_FADE_ENABLED true
#define MESSAGE_C_FADE_RATE 6
#define MESSAGE_C_FULL_ON_PAUSE_COUNT 0
#define MESSAGE_C_FULL_OFF_PAUSE_COUNT 0
#define MESSAGE_D "(512) 560-9551"
#define MESSAGE_D_SCROLL_ENABLED false
#define MESSAGE_D_NON_SCROLL_POSITION 2
#define MESSAGE_D_FADE_ENABLED true
#define MESSAGE_D_FADE_RATE 5
#define MESSAGE_D_FULL_ON_PAUSE_COUNT 0
#define MESSAGE_D_FULL_OFF_PAUSE_COUNT 0
#define SCROLL_DELAY 1000
#define VERTICAL_CHAR_POSITION 2 // Pixels from top starting with 0
// -- End of Message Defintions------------------------------------------------------
// Include libraries
#include <Adafruit_NeoPixel.h>
#include <Adafruit_NeoMatrix.h>
// Define the four message panels
#define PANEL_A_PIN 15
#define PANEL_B_PIN 2
#define PANEL_C_PIN 0
#define PANEL_D_PIN 4
Adafruit_NeoMatrix messagePanelA = Adafruit_NeoMatrix(44, 11, 2, 1, PANEL_A_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE +
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
Adafruit_NeoMatrix messagePanelB = Adafruit_NeoMatrix(44, 11, 2, 1, PANEL_B_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE +
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
Adafruit_NeoMatrix messagePanelC = Adafruit_NeoMatrix(44, 11, 2, 1, PANEL_C_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE +
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
Adafruit_NeoMatrix messagePanelD = Adafruit_NeoMatrix(44, 11, 2, 1, PANEL_D_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE +
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
// Color declarations
const uint16_t black = messagePanelA.Color( 0, 0, 0);
const uint16_t red = messagePanelA.Color(255, 0, 0);
const uint16_t white = messagePanelA.Color(255, 255, 255);
const uint16_t blue = messagePanelA.Color(0, 0, 255);
const uint16_t orange = messagePanelA.Color(255, 90, 0);
//
// Setup function
//
void setup() {
Serial.begin(115200);
Serial.println("setup function started.");
messagePanelA.begin();
messagePanelA.setTextWrap(false);
messagePanelA.setBrightness(255);
messagePanelA.setTextColor(red);
messagePanelB.begin();
messagePanelB.setTextWrap(false);
messagePanelB.setBrightness(255);
messagePanelB.setTextColor(white);
messagePanelC.begin();
messagePanelC.setTextWrap(false);
messagePanelC.setBrightness(255);
messagePanelC.setTextColor(blue);
messagePanelD.begin();
messagePanelD.setTextWrap(false);
messagePanelD.setBrightness(255);
messagePanelD.setTextColor(orange);
Serial.println("setup function complete");
}
//
// Other declarations
//
const char messageA[] = MESSAGE_A;
const char messageB[] = MESSAGE_B;
const char messageC[] = MESSAGE_C;
const char messageD[] = MESSAGE_D;
const int messageACharCount = (sizeof(messageA)/sizeof(messageA[0])) - 1;
const int messageBCharCount = (sizeof(messageB)/sizeof(messageB[0])) - 1;
const int messageCCharCount = (sizeof(messageC)/sizeof(messageC[0])) - 1;
const int messageDCharCount = (sizeof(messageD)/sizeof(messageD[0])) - 1;
const int displayWidth = messagePanelA.width(); // Assumes all four panels are the same width
// Starting charPosition is the rightmost pixel on the display which is
// where the start of the first character is initially displayed.
int messagePanelACharPosition = messagePanelA.width();
int messagePanelBCharPosition = messagePanelA.width();
int messagePanelCCharPosition = messagePanelA.width();
int messagePanelDCharPosition = messagePanelA.width();
// restartPosition is the "virtual" position of the first character when
// the last character scrolls of the leftmost pixel of the display. This
// position assumes each character is 6 pixels wide.
int messageARestartPosition = -((messageACharCount) * 6);
int messageBRestartPosition = -((messageBCharCount) * 6);
int messageCRestartPosition = -((messageCCharCount) * 6);
int messageDRestartPosition = -((messageDCharCount) * 6);
int messageABrightnessCount = 0;
int messageBBrightnessCount = 0;
int messageCBrightnessCount = 0;
int messageDBrightnessCount = 0;
const int messageAFadeIncrementor = ((1 << MESSAGE_A_FADE_RATE) % 257);
const int messageBFadeIncrementor = ((1 << MESSAGE_B_FADE_RATE) % 257);
const int messageCFadeIncrementor = ((1 << MESSAGE_C_FADE_RATE) % 257);
const int messageDFadeIncrementor = ((1 << MESSAGE_D_FADE_RATE) % 257);
long iterationCount = 0;
//
// Loop function
//
void loop() {
//Serial.print("messageAFadeIncrementor = ");
//Serial.print(messageAFadeIncrementor);
//Serial.print(" || messageABrightnessCount = ");
//Serial.println(messageABrightnessCount);
Serial.print("loop function started. iterationCount = ");
Serial.println(iterationCount++);
//
// Panel A processing
//
messagePanelA.fillScreen(black);
if (MESSAGE_A_SCROLL_ENABLED) {
messagePanelA.setCursor(messagePanelACharPosition, VERTICAL_CHAR_POSITION);
if (--messagePanelACharPosition <= messageARestartPosition) {
messagePanelACharPosition = messagePanelA.width();
}
} else {
messagePanelA.setCursor(MESSAGE_A_NON_SCROLL_POSITION, VERTICAL_CHAR_POSITION);
}
if (MESSAGE_A_FADE_ENABLED) {
messageABrightnessCount = updateBrightnessCount(messageABrightnessCount,
messageAFadeIncrementor,
MESSAGE_A_FULL_ON_PAUSE_COUNT,
MESSAGE_A_FULL_OFF_PAUSE_COUNT);
messagePanelA.setBrightness( getBrightnessValue(messageABrightnessCount,
messageAFadeIncrementor,
MESSAGE_A_FULL_ON_PAUSE_COUNT,
MESSAGE_A_FULL_OFF_PAUSE_COUNT) );
}
messagePanelA.print(messageA);
//
// Panel B processing
//
messagePanelB.fillScreen(black);
if (MESSAGE_B_SCROLL_ENABLED) {
messagePanelB.setCursor(messagePanelBCharPosition, VERTICAL_CHAR_POSITION);
if (--messagePanelBCharPosition <= messageBRestartPosition) {
messagePanelBCharPosition = messagePanelB.width();
}
} else {
messagePanelB.setCursor(MESSAGE_B_NON_SCROLL_POSITION, VERTICAL_CHAR_POSITION);
}
if (MESSAGE_B_FADE_ENABLED) {
messageBBrightnessCount = updateBrightnessCount(messageBBrightnessCount,
messageBFadeIncrementor,
MESSAGE_B_FULL_ON_PAUSE_COUNT,
MESSAGE_B_FULL_OFF_PAUSE_COUNT);
messagePanelB.setBrightness( getBrightnessValue(messageBBrightnessCount,
messageBFadeIncrementor,
MESSAGE_B_FULL_ON_PAUSE_COUNT,
MESSAGE_B_FULL_OFF_PAUSE_COUNT) );
}
messagePanelB.print(messageB);
//
// Panel C processing
//
messagePanelC.fillScreen(black);
if (MESSAGE_C_SCROLL_ENABLED) {
messagePanelC.setCursor(messagePanelCCharPosition, VERTICAL_CHAR_POSITION);
if (--messagePanelCCharPosition <= messageCRestartPosition) {
messagePanelCCharPosition = messagePanelC.width();
}
} else {
messagePanelC.setCursor(MESSAGE_C_NON_SCROLL_POSITION, VERTICAL_CHAR_POSITION);
}
if (MESSAGE_C_FADE_ENABLED) {
messageCBrightnessCount = updateBrightnessCount(messageCBrightnessCount,
messageCFadeIncrementor,
MESSAGE_C_FULL_ON_PAUSE_COUNT,
MESSAGE_C_FULL_OFF_PAUSE_COUNT);
messagePanelC.setBrightness( getBrightnessValue(messageCBrightnessCount,
messageCFadeIncrementor,
MESSAGE_C_FULL_ON_PAUSE_COUNT,
MESSAGE_C_FULL_OFF_PAUSE_COUNT) );
}
messagePanelC.print(messageC);
//
// Panel D processing
//
messagePanelD.fillScreen(black);
if (MESSAGE_D_SCROLL_ENABLED) {
messagePanelD.setCursor(messagePanelDCharPosition, VERTICAL_CHAR_POSITION);
if (--messagePanelDCharPosition <= messageDRestartPosition) {
messagePanelDCharPosition = messagePanelD.width();
}
} else {
messagePanelD.setCursor(MESSAGE_D_NON_SCROLL_POSITION, VERTICAL_CHAR_POSITION);
}
if (MESSAGE_D_FADE_ENABLED) {
messageDBrightnessCount = updateBrightnessCount(messageDBrightnessCount,
messageDFadeIncrementor,
MESSAGE_D_FULL_ON_PAUSE_COUNT,
MESSAGE_D_FULL_OFF_PAUSE_COUNT);
messagePanelD.setBrightness( getBrightnessValue(messageDBrightnessCount,
messageDFadeIncrementor,
MESSAGE_D_FULL_ON_PAUSE_COUNT,
MESSAGE_D_FULL_OFF_PAUSE_COUNT) );
}
messagePanelD.print(messageD);
// Update all four panels
messagePanelA.show();
messagePanelB.show();
messagePanelC.show();
messagePanelD.show();
Serial.println("loop function completed.");
// Delay
delay(SCROLL_DELAY);
}
//
// Support functions
//
int updateBrightnessCount(int currentCount, int fadeIncrementor, int fullOnPause, int fullOffPause) {
long additionalIterations = (fullOnPause * fadeIncrementor) + (fullOffPause * fadeIncrementor);
return (currentCount+fadeIncrementor) % (512+additionalIterations);
}
int getBrightnessValue(int brightnessCount, int fadeIncrementor, int fullOnPause, int fullOffPause) {
int brightness = 0;
long fullOnCounts = fullOnPause * fadeIncrementor;
long fullOffCounts = fullOffPause * fadeIncrementor;
// Determine brightness value
if ((brightnessCount >= 0) && (brightnessCount <= (256+fullOnCounts))) {
brightness = brightnessCount-1;
} else if (brightnessCount <= (512+fullOnCounts+fullOffCounts)) {
brightness = (512-1+fullOnCounts) - brightnessCount;
}
// Limit brightness to values in range 0..255
if (brightness < 0) {brightness = 0;}
if (brightness > 255) {brightness = 255;}
return brightness;
}