Scrolling text on aduino Uno

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
1 Like