Hi,
Any recommendations for LED scrolling text on led strips or matrixes. I’m looking for the cheapest and easiest project
Mike
Hi,
Any recommendations for LED scrolling text on led strips or matrixes. I’m looking for the cheapest and easiest project
Mike
I did one of those.
Can’t guarantee it works, didn’t do it as a publishable project, just as a Christmas message display. Device still works, setting via bluetooth was impressive to guests. LOL
Text messages scroll across the LED matrix.
Might give you a starting point.
Cheers
Jim
/* LED Matrix 3 8x8 Displays
*
*
*
* created by James Grigg 07 Dec 2017
*
* Special for Christmas message.
*
* To Do :-
* Add ASCII special characters
* Blue tooth to change meassage
*/
#include <LedControl.h>
#include <SoftwareSerial.h>
#define MSG_MAX_CHARS 30
#define NUM_MSGS 10 // the number of built in message, message 11 is custom message
#define DELAY_TIME 500
#define DEVICES 3
#define BT_STATE 2 // D2 shows state of blue tooth connection, high = connected.
#define BT_RXD 5 // D5 RXD from HC-05 device
#define BT_TXD 6 // D6 TXD to HC-05 device
#define MOSI 11 // D11 data to displays
#define SS 12 // D12 load to displays
#define SCK 13 // D13 clock to displays
LedControl lc = LedControl(MOSI, SCK, SS, DEVICES); // (MOSI, SCK, SS, Devices)
SoftwareSerial BTSerial(BT_RXD, BT_TXD); // RX | TX RX is input, TX is output.
byte currentCols[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // holder for current columns display. 3 x 8x8.
byte BitPattern[8] = {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}; // holder for current character read from Program memory.
char msg[][MSG_MAX_CHARS] = {"MERRY CHRISTMAS",
"HAVE A NICE DAY",
"LOVE YOU ALL",
"IM SORRY DAVE I CANT DO THAT",
"OPEN THE POD BAY DOORS HAL",
"STAY POSITIVE",
"THINK AND GROW RICH",
"HOPE IS A WAKING DREAM",
"DONT PANIC",
"SEEK THE BEAUTY IN ALL THINGS",
"<custom message>"}; // holder for custom message
bool RandomMsg = true; // display a random message
bool SentMenu = false; // true when menu has been sent to bluetooth device, intial contact with device
char MenuOption = 0x00;
int messageNum = 0;
int Last5messages[5] = {99,99,99,99,99};
byte msg_ok = false;
// arrays stored in Program Memory to save dynamic memory space, variables do not change
const byte Icons[][8] PROGMEM = {
{B00000000,B00010000,B00100100,B00100000,B00100000,B00100100,B00010000,B00000000}, // smiley face
{B00000000,B00100000,B00110000,B11011100,B11111111,B11011100,B00110000,B00100000}, // Christmas Tree Right
{B00100000,B00110000,B11011100,B11111111,B11011100,B00110000,B00100000,B00000000}}; // Christmas Tree Left
const byte ASCII_Table[][8] PROGMEM = {
{B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}, // 32 space 0
{B00000000,B00000000,B00001100,B10111110,B10111110,B00001100,B00000000,B00000000}, // 33 !
{B00000000,B00000000,B00001110,B00001110,B00000000,B00001110,B00001110,B00000000}, // 34 "
{B00000000,B00101000,B11111110,B11111110,B00101000,B11111110,B11111110,B00101000}, // 35 #
{B00000000,B00000000,B01001000,B01010100,B11010110,B01010100,B00100100,B00000000}, // 36 $
{B00000000,B01000110,B01100110,B00110000,B00011000,B11001100,B11000100,B00000000}, // 37 %
{B00000000,B01100100,B11111110,B10001010,B10011010,B11101110,B11000100,B10100000}, // 38 &
{B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,B00001110,B00000000}, // 39 '
{B00000000,B00000000,B00000000,B00111000,B01111100,B11000110,B10000010,B00000000}, // 40 (
{B00000000,B10000010,B11000110,B01111100,B00111000,B00000000,B00000000,B00000000}, // 41 )
{B00000000,B00010000,B01010100,B01111100,B00111000,B01111100,B01010100,B00010000}, // 42 *
{B00000000,B00000000,B00010000,B00010000,B01111100,B00010000,B00010000,B00000000}, // 43 +
{B00000000,B10000000,B11110000,B01110000,B00000000,B00000000,B00000000,B00000000}, // 44 ,
{B00000000,B00000000,B00010000,B00010000,B00010000,B00010000,B00000000,B00000000}, // 45 -
{B00000000,B11000000,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000}, // 46 .
{B00000000,B01000000,B01100000,B00110000,B00011000,B00001100,B00000100,B00000000}, // 47 /
{B00000000,B01111100,B11111110,B10010010,B10001010,B11111110,B01111100,B00000000}, // 48 0
{B00000000,B10000000,B10001000,B11111110,B11111110,B10000000,B10000000,B00000000}, // 49 1
{B00000000,B11000100,B11100110,B10100010,B10010010,B10011110,B10001100,B00000000}, // 50 2
{B00000000,B01000100,B11000110,B10010010,B10010010,B11111110,B01101100,B00000000}, // 51 3
{B00000000,B00110000,B00101000,B00100100,B11111110,B11111110,B00100000,B00000000}, // 52 4
{B00000000,B01001110,B11001110,B10001010,B10001010,B11111010,B01110010,B00000000}, // 53 5
{B00000000,B01111100,B11111110,B10010010,B10010010,B11110110,B01100100,B00000000}, // 54 6
{B00000000,B00000110,B00000110,B11100010,B11111010,B00011110,B00000110,B00000000}, // 55 7
{B00000000,B01101100,B11111110,B10010010,B10010010,B11111110,B01101100,B00000000}, // 56 8
{B00000000,B01001100,B11011110,B10010010,B10010010,B11111110,B01111100,B00000000}, // 57 9
{B00000000,B00000000,B00000000,B01101100,B01101100,B00000000,B00000000,B00000000}, // 58 :
{B00000000,B00000000,B10000000,B11101100,B01101100,B00000000,B00000000,B00000000}, // 59 ;
{B00000000,B00000000,B00010000,B00111000,B01101100,B11000110,B10000010,B00000000}, // 60 <
{B00000000,B00000000,B00101000,B00101000,B00101000,B00101000,B00000000,B00000000}, // 61 =
{B00000000,B10000010,B11000110,B01101100,B00111000,B00010000,B00000000,B00000000}, // 62 >
{B00000000,B00000100,B00000110,B10110010,B10110010,B00011110,B00001100,B00000000}, // 63 ?
{B00000000,B00111100,B01000010,B01011010,B01011010,B01001100,B00100000,B00000000}, // 64 @
{B00000000,B11111100,B11111110,B00010010,B00010010,B11111110,B11111100,B00000000}, // 65 A
{B00000000,B11111110,B11111110,B10010010,B10010010,B11111110,B01101100,B00000000}, // 66 B
{B00000000,B01111100,B11111110,B10000010,B10000010,B11000110,B01000100,B00000000}, // 67 C
{B00000000,B11111110,B11111110,B10000010,B10000010,B11111110,B01111100,B00000000}, // 68 D
{B00000000,B11111110,B11111110,B10010010,B10010010,B10010010,B10000010,B00000000}, // 69 E
{B00000000,B11111110,B11111110,B00010010,B00010010,B00010010,B00000010,B00000000}, // 70 F
{B00000000,B01111100,B11111110,B10000010,B10100010,B11100110,B01100100,B00000000}, // 71 G
{B00000000,B11111110,B11111110,B00010000,B00010000,B11111110,B11111110,B00000000}, // 72 H
{B00000000,B00000000,B10000010,B11111110,B11111110,B10000010,B00000000,B00000000}, // 73 I
{B00000000,B01100000,B11100000,B10000010,B11111110,B01111110,B00000010,B00000000}, // 74 J
{B00000000,B11111110,B11111110,B00111000,B01101100,B11000110,B10000010,B00000000}, // 75 K
{B00000000,B11111110,B11111110,B10000000,B10000000,B10000000,B10000000,B00000000}, // 76 L
{B00000000,B11111110,B11111110,B00001100,B00011000,B00001100,B11111110,B11111110}, // 77 M
{B00000000,B11111110,B11111110,B00001100,B00011000,B00110000,B11111110,B11111110}, // 78 N
{B00000000,B01111100,B11111110,B10000010,B10000010,B11111110,B01111100,B00000000}, // 79 O
{B00000000,B11111110,B11111110,B00100010,B00100010,B00111110,B00011100,B00000000}, // 80 P
{B00000000,B00111100,B01111110,B01000010,B01100010,B11111110,B10111100,B00000000}, // 81 Q
{B00000000,B11111110,B11111110,B00110010,B01110010,B11011110,B10001100,B00000000}, // 82 R
{B00000000,B01001100,B11011110,B10010010,B10010010,B11110110,B01100100,B00000000}, // 83 S
{B00000000,B00000110,B00000010,B11111110,B11111110,B00000010,B00000110,B00000000}, // 84 T
{B00000000,B01111110,B11111110,B10000000,B10000000,B11111110,B11111110,B00000000}, // 85 U
{B00000000,B00111110,B01111110,B11000000,B11000000,B01111110,B00111110,B00000000}, // 86 V
{B00000000,B11111110,B11111110,B01100000,B00110000,B01100000,B11111110,B11111110}, // 87 W
{B00000000,B11000110,B11101110,B00111000,B00010000,B00111000,B11101110,B11000110}, // 88 X
{B00000000,B00001110,B00011110,B11110000,B11110000,B00011110,B00001110,B00000000}, // 89 Y
{B00000000,B11000010,B11100010,B10110010,B10011010,B10001110,B10000110,B00000000}, // 90 Z
{B00000000,B00000000,B00000000,B11111110,B11111110,B10000010,B10000010,B00000000}, // 91 [
{B00000000,B00000100,B00001100,B00011000,B00110000,B01100000,B01000000,B00000000}, // 92 \
{B00000000,B10000010,B10000010,B11111110,B11111110,B00000000,B00000000,B00000000}, // 93 ]
{B00000000,B00010000,B00001000,B00000100,B00000010,B00000100,B00001000,B00010000}, // 94 ^
{B00000000,B01000000,B01000000,B01000000,B01000000,B01000000,B01000000,B00000000}, // 95 _
{B00000000,B00000000,B00000000,B00000000,B00000110,B00001110,B00001000,B00000000}, // 96 `
{B00000000,B01000000,B11101000,B10101000,B10101000,B11111000,B11110000,B00000000}, // 97 a
{B00000000,B11111110,B11111110,B10010000,B10010000,B11110000,B01100000,B00000000}, // 98 b
{B00000000,B01110000,B11111000,B10001000,B10001000,B11011000,B01010000,B00000000}, // 99 c
{B00000000,B01100000,B11110000,B10010000,B10010000,B11111110,B11111110,B00000000}, // 100 d
{B00000000,B01110000,B11111000,B10101000,B10101000,B10111000,B00110000,B00000000}, // 101 e
{B00000000,B00100000,B11111100,B11111110,B00100010,B00100110,B00000100,B00000000}, // 102 f
{B00000000,B00011000,B10111100,B10100100,B10100100,B11111100,B01111100,B00000000}, // 103 g
{B00000000,B11111110,B11111110,B00010000,B00010000,B11110000,B11100000,B00000000}, // 104 h
{B00000000,B00000000,B10000000,B11110100,B11110100,B10000000,B00000000,B00000000}, // 105 i
{B00000000,B01100000,B11100000,B10000000,B11111010,B01111010,B00000000,B00000000}, // 106 j
{B00000000,B11111110,B11111110,B00100000,B01110000,B11011000,B10001000,B00000000}, // 107 k
{B00000000,B00000000,B00000000,B11111110,B11111110,B00000000,B00000000,B00000000}, // 108 l
{B00000000,B11111000,B11111000,B00110000,B11100000,B00110000,B11111000,B11111000}, // 109 m
{B00000000,B11111000,B11111000,B00011000,B00011000,B11111000,B11110000,B00000000}, // 110 n
{B00000000,B01110000,B11111000,B10001000,B10001000,B11111000,B01110000,B00000000}, // 111 o
{B00000000,B11111100,B11111100,B00100100,B00100100,B00111100,B00011000,B00000000}, // 112 p
{B00000000,B00011000,B00111100,B00100100,B11111100,B11111100,B10000000,B11000000}, // 113 q
{B00000000,B11111000,B11111000,B00001000,B00001000,B00111000,B00110000,B00000000}, // 114 r
{B00000000,B10010000,B10101000,B10101000,B10101000,B10101000,B01001000,B00000000}, // 115 s
{B00000000,B00010000,B00010000,B11111100,B11111100,B00010000,B00010000,B00000000}, // 116 t
{B00000000,B01111000,B11111000,B10000000,B10000000,B11111000,B11111000,B00000000}, // 117 u
{B00000000,B00110000,B01110000,B11000000,B11000000,B01110000,B00110000,B00000000}, // 118 v
{B00000000,B01111000,B11111000,B10000000,B11110000,B10000000,B11111000,B01111000}, // 119 w
{B00000000,B10001000,B11011000,B01110000,B01110000,B11011000,B10001000,B00000000}, // 120 x
{B00000000,B00011000,B10111000,B10100000,B10100000,B11111000,B01111000,B00000000}, // 121 y
{B00000000,B00000000,B11001000,B11101000,B10111000,B10011000,B00000000,B00000000}, // 122 z
{B00000000,B00000000,B00010000,B01111100,B11101110,B10000010,B10000010,B00000000}, // 123 {
{B00000000,B00000000,B00000000,B11111110,B11111110,B00000000,B00000000,B00000000}, // 124 |
{B00000000,B10000010,B10000010,B11101110,B01111100,B00010000,B00000000,B00000000}, // 125 }
{B00000000,B00010000,B00011000,B00001000,B00011000,B00010000,B00001000,B00000000}}; // 126 ~
//============================================================================================
//============================================================================================
void setup() {
// devices = lc.getDeviceCount();
for(int i = 0; i < DEVICES; i++) {
lc.shutdown(i,false);
lc.clearDisplay(i);
lc.setIntensity(i,0);
}
// wont need these in final version, testing only
Serial.begin(115200);
Serial.println(' ');
Serial.println("LED Matrix 3 8x8 Displays");
Serial.println(' ');
BTSerial.begin(38400); // HC-05 default speed in AT command more
pinMode(BT_STATE, INPUT_PULLUP);
delay(DELAY_TIME);
}
void loop() {
if (digitalRead(BT_STATE)) {
if (!SentMenu) { // inital contact with bluetooth device, get rid of any random characters that may have been sent
while (BTSerial.available()) { BTSerial.read(); }
SendMenu();
SentMenu = true;
} else {
if (BTSerial.available()) {
MenuOption = BTSerial.read();
while (BTSerial.available()) { BTSerial.read(); } // clear other characters that may have been sent
switch (MenuOption) {
case 'R' :
RandomMsg = true;
break;
case 'r' :
RandomMsg = true;
break;
case 'C' :
messageNum = 10;
GetCustomMsg();
RandomMsg = false;
break;
case 'c' :
messageNum = 10;
GetCustomMsg();
RandomMsg = false;
break;
default :
if ((MenuOption > 47) && (MenuOption < 58)) {
messageNum = MenuOption - 48;
RandomMsg = false;
}
break;
}
}
}
} else {
SentMenu = false;
// MenuOption = 0x00;
}
for (int i = 0; i < 10; i++) { RandomLEDs20(20,20); }
if (RandomMsg) { GetRandomMSG(); }
// special for Christmas message
if (messageNum == 0) { MessageHeader_0(); }
// display message
DisplayMessage(messageNum);
delay(DELAY_TIME);
DisplaySmileyFace();
delay(1000);
ClearAll();
delay(DELAY_TIME);
}
//============================================================================================
//============================================================================================
//============================================================================================
void GetCustomMsg(void) {
int count = 0;
bool Finished = false;
BTSerial.println(' ');
BTSerial.println(' ');
BTSerial.println("Enter Custom Message, use # to end.");
BTSerial.println(' ');
while (!Finished) {
if (BTSerial.available()) {
msg[messageNum][count] = BTSerial.read();
if (msg[messageNum][count] == '#') {
msg[messageNum][count] = 0x00;
Finished = true;
} else {
count++;
if (count == MSG_MAX_CHARS) {
msg[messageNum][MSG_MAX_CHARS-1] = 0x00;
Finished = true;
}
}
}
}
SendMenu();
return;
}
//============================================================================================
void SendMenu(void) {
BTSerial.println(' ');
BTSerial.println("Select Message to Display");
BTSerial.println(" New Message will appear after current message.");
BTSerial.println(' ');
BTSerial.print("0 - ");
BTSerial.println(msg[0]);
BTSerial.print("1 - ");
BTSerial.println(msg[1]);
BTSerial.print("2 - ");
BTSerial.println(msg[2]);
BTSerial.print("3 - ");
BTSerial.println(msg[3]);
BTSerial.print("4 - ");
BTSerial.println(msg[4]);
BTSerial.print("5 - ");
BTSerial.println(msg[5]);
BTSerial.print("6 - ");
BTSerial.println(msg[6]);
BTSerial.print("7 - ");
BTSerial.println(msg[7]);
BTSerial.print("8 - ");
BTSerial.println(msg[8]);
BTSerial.print("9 - ");
BTSerial.println(msg[9]);
BTSerial.print("C - ");
BTSerial.println(msg[10]);
BTSerial.println("R - Random message.");
return;
}
//============================================================================================
// get new random message number and check if it has been displayed within the last 5 displays
void GetRandomMSG(void) {
msg_ok = false;
while (!msg_ok) {
messageNum = GetRandomNumber(NUM_MSGS);
msg_ok = true;
for (int i = 0; i < 5; i++) { if (messageNum == Last5messages[i]) { msg_ok = false; }
}
}
// shuffle last 5 messages and add new one
for (int i = 0; i < 4; i++) { Last5messages[i] = Last5messages[i+1]; }
Last5messages[4] = messageNum;
return;
}
//============================================================================================
// display smiley face Icon 0
void DisplaySmileyFace (void) {
for (int j =0; j < 8; j++) {
BitPattern[j] = pgm_read_byte(&Icons[0][j]);
}
displayChar(BitPattern, 0);
displayChar(BitPattern, 1);
displayChar(BitPattern, 2);
return;
}
//============================================================================================
//============================================================================================
/*
if (BTSerial.available())
Serial.write(BTSerial.read());
if (Serial.available())
BTSerial.write(Serial.read());
*/
//============================================================================================
//============================================================================================
void DisplayMessage(int Num) {
int msgDec = 0;
int i = 0;
for (int i = 0; i < 24; i++) { currentCols[i] = 0; } // clear display storage
// step through message scrolling characters until NULL found or greater than the maximum message size
while ((i < MSG_MAX_CHARS) && (msg[Num][i] != 0x00)) {
// convert ASCII to decimal for index into array. Range 'space' (32) to '~' (126)
if ((msg[Num][i] > 31) && (msg[Num][i] < 127)) { msgDec = msg[Num][i] - 32; } // check for character within bounds, blank if not
for (int j =0; j < 8; j++) {
BitPattern[j] = pgm_read_byte(&ASCII_Table[msgDec][j]); // get the character from Program Memory
}
ScrollChar(BitPattern);
i++;
}
// scroll characters off the display when message finished
for (int j =0; j < 8; j++) {
BitPattern[j] = B00000000;
}
ScrollChar(BitPattern);
ScrollChar(BitPattern);
ScrollChar(BitPattern);
return;
}
//============================================================================================
// move new character in one row at a time, from right to left shifting other rows
void ScrollChar(const byte* image) {
for (int col = 0; col < 8; col++) {
for (int i = 0; i < 23; i++) { currentCols[i] = currentCols[i + 1]; } // shuffle storage to left.
currentCols[23] = image[col]; // add new column.
for (int i = 0; i < 8; i++) { // shuffle display to left.
lc.setRow(2, i, currentCols[i]);
lc.setRow(1, i, currentCols[i+8]);
lc.setRow(0, i, currentCols[i+16]);
}
delay(50);
}
return;
}
//============================================================================================
// Christmas Message Header
void MessageHeader_0(void) {
for (int j =0; j < 8; j++) {
BitPattern[j] = pgm_read_byte(&Icons[1][j]);
}
displayChar(BitPattern, 0);
delay(400);
displayChar(BitPattern, 1);
delay(400);
displayChar(BitPattern, 2);
delay(400);
for (int i = 0; i < 5; i++) {
for (int j =0; j < 8; j++) { BitPattern[j] = pgm_read_byte(&Icons[2][j]); }
displayChar(BitPattern, 0);
displayChar(BitPattern, 1);
displayChar(BitPattern, 2);
delay(200);
for (int j =0; j < 8; j++) { BitPattern[j] = pgm_read_byte(&Icons[1][j]); }
displayChar(BitPattern, 0);
displayChar(BitPattern, 1);
displayChar(BitPattern, 2);
delay(200);
}
for (int i = 0; i < 5; i++) {
for (int j =0; j < 8; j++) { BitPattern[j] = pgm_read_byte(&Icons[1][j]); }
displayChar(BitPattern, 0);
displayChar(BitPattern, 1);
displayChar(BitPattern, 2);
delay(20);
ClearAll();
delay(20);
}
delay(DELAY_TIME);
return;
}
//============================================================================================
// Immediate display of the character
void displayChar(const byte* image, int address) {
for (int col = 0; col < 8; col++) {
// for (int row = 0; row < 8; row++) {
// lc.setLed(address, row, col, bitRead(image[7-col], row));
// }
lc.setRow(address, col, image[col]);
}
return;
}
//============================================================================================
void ClearAll(void) {
for (int address = 0; address < DEVICES; address++) { lc.clearDisplay(address); }
return;
}
//============================================================================================
// generates up to 'n' random leds ON at a time with 'd1' delay (max 20 LEDS)
void RandomLEDs20(int d1, int n) {
int row[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int col[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
for (int i = 0; i < n; i++) {
for(int address = 0; address < DEVICES; address++) {
row[i] = GetRandomNumber(8);
col[i] = GetRandomNumber(8);
lc.setLed(address,row[i],col[i],true);
}
}
delay(d1);
ClearAll();
return;
}
//============================================================================================
int GetRandomNumber(int limit) {
int adc0 = analogRead(0);
int adc1 = analogRead(1);
int adc2 = analogRead(2);
int adc3 = analogRead(3);
int adc4 = analogRead(4);
int adc5 = analogRead(5);
int seed = adc0 + adc1 + adc2 + adc3 + adc4 + adc5;
randomSeed(seed);
int num = random(limit);
return num;
}
//============================================================================================
//============================================================================================
//============================================================================================
//============================================================================================
//============================================================================================
indent preformatted text by 4 spaces