LED signs are everywhere and they can be bought dirt chip nowadays, but the feeling is good if you can build your own. This project is based on Atmega328P with Arduino UNO bootloader and some shift registers and a driver. The schematic shown is the complete circuit of the project. You notice that there are even no current limiting resistors, the LED matrix is directly driven by the shift register. This circuit is just for testing and is not guaranteed for a long period of operation. The message buffer can accommodate up to 100 characters.

The demo video is a little garbled because I am only using a mobile phone , but the actual device the message is clear.

8x32Matrix

Schematic Diagram

A simple message uploader written in C# can be download from here. The uploader requires .NET Framework 4.0 Installed.

Message Uploader

Message Uploader

Arduino Sketch


#include "cmap.h"

int d;
unsigned char char_pointer;
char Display_Ram[38];
unsigned char mask;
char LED_DATA[100]= "8x32 LED Scrolling Message Display by tiktak 2013 ~";
char LED_BUFFER[100];
char count;
unsigned char shift_counter;
int rxctr = 0;

#define INTEN 6500

const char DAT = 8;
const char CLK = 10;
const char LAT = 9;

const char DAT1 = 11;
const char CLK1 = 13;
const char LAT1 = 12;
int i = 0;
void setup() {
 pinMode(CLK, OUTPUT);
 pinMode(DAT, OUTPUT);
 pinMode(CLK1, OUTPUT);
 pinMode(DAT1, OUTPUT);
 pinMode(LAT, OUTPUT);
 pinMode(LAT1, OUTPUT);

 Serial.begin(9600);

}

void loop(){
 if(Serial.available()){
 int rx = Serial.read();
 LED_BUFFER[rxctr] = rx;
 rxctr++;
 if(rx == '~'){
 for(int h=0; h<100; h++){
 LED_DATA[h] = 0;
 }
 rxctr = 0;
 for(int x = 0; x<100; x++){
 LED_DATA[x] = LED_BUFFER[x];
 }
 Clear_Display_Ram();
 }
 }

 Display();
 shift();
}

void scanRow(unsigned char row)
{
 int i;
 for(i = 0; i<8; i++)
 {
 if(row & 0x80){
 digitalWrite(DAT1,HIGH);
 }
 else{
 digitalWrite(DAT1,LOW);
 }

 digitalWrite(CLK1,HIGH);
 digitalWrite(CLK1,LOW);

 row <<= 1;
 }
 digitalWrite(LAT1,HIGH);
 digitalWrite(LAT1,LOW);

}

void shift(void)
{
 int x;
 for(x=0; x<38; x++){
 Display_Ram[x] = Display_Ram[x+1];
 }

shift_counter++;
 if(shift_counter == 6){
 shift_counter = 0;
 load();
 }

}

void Display(void)
{
 mask = 0x01;
 scan();
 scanRow(0x80);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x02;
 scan();
 scanRow(0x40);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x04;
 scan();
 scanRow(0x20);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x08;
 scan();
 scanRow(0x10);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x10;
 scan();
 scanRow(0x08);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x20;
 scan();
 scanRow(0x04);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x40;
 scan();
 scanRow(0x02);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);

mask = 0x80;
 scan();
 scanRow(0x01);
 for(d=0;d<INTEN;d++){}
 scanRow(0x00);
}

void load(void){
 char counter1;
 if(LED_DATA[char_pointer+1] == '~')
 char_pointer = 0;
 for(counter1 = 0; counter1 < 5; counter1++){
 Display_Ram[32 + counter1] = character_data[(LED_DATA[char_pointer] - 0x20)][counter1];
 }
 Display_Ram[37] = 00;
 char_pointer++;
}

void Clear_Display_Ram(void){
 unsigned char rcount;
 for(rcount = 0; rcount < 37; rcount++)
 Display_Ram[rcount] = 0x00;
}

void scan(void){
 for (count=0;count<32;count++){
 if ((Display_Ram[count] & mask) == mask)
 digitalWrite(DAT,HIGH);
 else
 digitalWrite(DAT,LOW);
 digitalWrite(CLK,HIGH);
 digitalWrite(CLK,LOW);
 }
 digitalWrite(LAT,HIGH);
 digitalWrite(LAT,LOW);
}

cmap.h


const unsigned char character_data[][6] =
{
 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //20-
 { 0x00, 0x00, 0x00, 0xF2, 0x00, 0x00 }, //21-!
 { 0x00, 0x00, 0xE0, 0x00, 0xE0, 0x00 }, //22-"
 { 0x28, 0xFE, 0x28, 0xFE, 0x28, 0x00 }, //23-#
 { 0x24, 0x54, 0x7E, 0x54, 0x48, 0x00 }, //24-$
 { 0xC4, 0xC4, 0x10, 0x26, 0x46, 0x00 }, //25-%
 { 0x6C, 0x92, 0xAA, 0x44, 0x1A, 0x00 }, //26-&
 { 0x00, 0x00, 0xA0, 0xC0, 0x00, 0x00 }, //27-'
 { 0x00, 0x00, 0x38, 0x44, 0x82, 0x00 }, //28-(
 { 0x00, 0x82, 0x44, 0x38, 0x00, 0x00 }, //29-)
 { 0x28, 0x10, 0x6C, 0x10, 0x28, 0x00 }, //2A-*
 { 0x10, 0x10, 0x6C, 0x10, 0x10, 0x00 }, //2B-+
 { 0x00, 0x00, 0x0A, 0x0C, 0x00, 0x00 }, //2C-,
 { 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 }, //2D--
 { 0x00, 0x00, 0x06, 0x06, 0x00, 0x00 }, //2E-.
 { 0x04, 0x08, 0x10, 0x20, 0x40, 0x00 }, //2F-/
 { 0x7C, 0x82, 0x82, 0x82, 0x7C, 0x00 }, //30
 { 0x00, 0x42, 0xFE, 0x02, 0x00, 0x00 }, //31
 { 0x42, 0x86, 0x8A, 0x92, 0x62, 0x00 }, //32
 { 0x84, 0x82, 0xA2, 0xD2, 0x8C, 0x00 }, //33
 { 0x18, 0x28, 0x48, 0xFE, 0x08, 0x00 }, //34
 { 0xE4, 0xA2, 0xA2, 0xA2, 0x9C, 0x00 }, //35
 { 0x3C, 0x52, 0x92, 0x92, 0x0C, 0x00 }, //36
 { 0x80, 0x8E, 0x90, 0xA0, 0xC0, 0x00 }, //37
 { 0x6C, 0x92, 0x92, 0x92, 0x6C, 0x00 }, //38
 { 0x60, 0x92, 0x92, 0x94, 0x78, 0x00 }, //39
 { 0x00, 0x00, 0x6C, 0x6C, 0x00, 0x00 }, //3A-:
 { 0x00, 0x00, 0x6A, 0x6C, 0x00, 0x00 }, //3B-//
 { 0x00, 0x10, 0x28, 0x44, 0x82, 0x00 }, //3C-<
 { 0x28, 0x28, 0x28, 0x28, 0x28, 0x00 }, //3D-=
 { 0x00, 0x82, 0x44, 0x28, 0x10, 0x00 }, //3E->
 { 0x40, 0x80, 0x8A, 0x90, 0x60, 0x00 }, //3F-?
 { 0x7C, 0x82, 0xBA, 0xAA, 0xBA, 0x70 }, //40-@
 { 0x7E, 0x88, 0x88, 0x88, 0x7E, 0x00 }, //41-A
 { 0xFE, 0x92, 0x92, 0x92, 0x6C, 0x00 }, //42-B
 { 0x7C, 0x82, 0x82, 0x82, 0x44, 0x00 }, //43-C
 { 0xFE, 0x82, 0x82, 0x44, 0x38, 0x00 }, //44-D
 { 0xFE, 0x92, 0x92, 0x92, 0x82, 0x00 }, //45-E
 { 0xFE, 0x90, 0x90, 0x90, 0x80, 0x00 }, //46-F
 { 0x7C, 0x82, 0x92, 0x92, 0x5E, 0x00 }, //47-G
 { 0xFE, 0x10, 0x10, 0x10, 0xFE, 0x00 }, //48-H
 { 0x00, 0x82, 0xFE, 0x82, 0x00, 0x00 }, //49-I
 { 0x04, 0x02, 0x82, 0xFC, 0x80, 0x00 }, //4A-J
 { 0xFE, 0x10, 0x28, 0x44, 0x82, 0x00 }, //4B-K
 { 0xFE, 0x02, 0x02, 0x02, 0x02, 0x00 }, //4C-L
 { 0xFE, 0x40, 0x30, 0x40, 0xFE, 0x00 }, //4D-M
 { 0xFE, 0x20, 0x10, 0x08, 0xFE, 0x00 }, //4E-N
 { 0x7C, 0x82, 0x82, 0x82, 0x7C, 0x00 }, //4F-O
 { 0xFE, 0x90, 0x90, 0x90, 0x60, 0x00 }, //50-P
 { 0x7C, 0x82, 0x8A, 0x84, 0x7A, 0x00 }, //51-Q
 { 0xFE, 0x90, 0x98, 0x94, 0x62, 0x00 }, //52-R
 { 0x62, 0x92, 0x92, 0x92, 0x8C, 0x00 }, //53-S
 { 0x80, 0x80, 0xFE, 0x80, 0x80, 0x00 }, //54-T
 { 0xFC, 0x02, 0x02, 0x02, 0xFC, 0x00 }, //55-U
 { 0xF8, 0x04, 0x02, 0x04, 0xF8, 0x00 }, //56-V
 { 0xFC, 0x02, 0x1C, 0x02, 0xFC, 0x00 }, //57-W
 { 0xC6, 0x28, 0x10, 0x28, 0xC6, 0x00 }, //58-X
 { 0xE0, 0x10, 0x0E, 0x10, 0xE0, 0x00 }, //59-Y
 { 0x86, 0x8A, 0x92, 0xA2, 0xC2, 0x00 }, //5A-Z
 { 0x00, 0x00, 0xFE, 0x82, 0x82, 0x00 }, //5B-[
 { 0x40, 0x20, 0x10, 0x08, 0x04, 0x00 }, //5C-\

{ 0x00, 0x82, 0x82, 0xFE, 0x00, 0x00 }, //5D-]
 { 0x20, 0x40, 0xFE, 0x40, 0x20, 0x00 }, //5E-^
 { 0x01, 0x01, 0x01, 0x01, 0x01, 0x00 }, //5F-_
 { 0x80, 0x40, 0x20, 0x00, 0x00, 0x00 }, //60-`
 { 0x04, 0x2A, 0x2A, 0x2A, 0x1E, 0x00 }, //61-a
 { 0xFE, 0x12, 0x22, 0x22, 0x1C, 0x00 }, //62-b
 { 0x1C, 0x22, 0x22, 0x22, 0x04, 0x00 }, //63-c
 { 0x1C, 0x22, 0x22, 0x12, 0xFE, 0x00 }, //64-d
 { 0x1C, 0x2A, 0x2A, 0x2A, 0x18, 0x00 }, //65-e
 { 0x08, 0x3F, 0x48, 0x40, 0x20, 0x00 }, //66-f
 { 0x18, 0x25, 0x25, 0x25, 0x3E, 0x00 }, //67-g
 { 0xFE, 0x10, 0x20, 0x20, 0x1E, 0x00 }, //68-h
 { 0x00, 0x22, 0xBE, 0x02, 0x00, 0x00 }, //69-i
 { 0x02, 0x01, 0x21, 0xBE, 0x00, 0x00 }, //6A-j
 { 0x00, 0xFE, 0x08, 0x14, 0x22, 0x00 }, //6B-k
 { 0x00, 0x82, 0xFE, 0x02, 0x00, 0x00 }, //6C-l
 { 0x3E, 0x20, 0x18, 0x20, 0x1E, 0x00 }, //6D-m
 { 0x3E, 0x10, 0x20, 0x20, 0x1E, 0x00 }, //6E-n
 { 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00 }, //6F-o
 { 0x3F, 0x24, 0x24, 0x24, 0x18, 0x00 }, //70-p
 { 0x18, 0x24, 0x24, 0x14, 0x3F, 0x00 }, //71-q
 { 0x3E, 0x10, 0x20, 0x20, 0x10, 0x00 }, //72-r
 { 0x12, 0x2A, 0x2A, 0x2A, 0x04, 0x00 }, //73-s
 { 0x20, 0xFC, 0x22, 0x02, 0x04, 0x00 }, //74-t
 { 0x3C, 0x02, 0x02, 0x04, 0x3E, 0x00 }, //75-u
 { 0x38, 0x04, 0x02, 0x04, 0x38, 0x00 }, //76-v
 { 0x3C, 0x02, 0x0C, 0x02, 0x3C, 0x00 }, //77-w
 { 0x22, 0x14, 0x08, 0x14, 0x22, 0x00 }, //78-x
 { 0x38, 0x05, 0x05, 0x05, 0x3E, 0x00 }, //79-y
 { 0x22, 0x26, 0x2A, 0x32, 0x22, 0x00 }, //7A-z
 { 0x00, 0x10, 0x6C, 0x82, 0x00, 0x00 }, //7B-{
 { 0x00 }, //7C-|-BLANK BAR
 { 0x00, 0x82, 0x6C, 0x10, 0x00, 0x00 }, //7D-}
 { 0x18, 0x24, 0x7E, 0x24, 0x08, 0x00 },
 { 0 } //7F-DO NOT USE

};

Advertisements
Comments
  1. Edward says:

    So I have a couple Sure P4 32X8 LED matrix boards using HT1632C LED driver. Should I be able to adapt your code, adding the ht1632c.h library and omitting cmap.h?
    Could I use Hyperterminal in place of your Message Uploader?

  2. karldayap says:

    can you help me integrate the message uploader to a matlab gui?

  3. sarahmariano says:

    hello.. how can i make my own message uploader?

  4. jaybee says:

    Good day, I am using Gizduino (mini) w/ATmega328 board, I created a web browser as an interface to input message. My problem is, the message displayed in my LED matrix display were limited to 262 characters only. Is there any way to solve this? is it because of the board’s RAM or the string that i passed? The arduino received all the characters but only displayed 262 characters. I have to display at most 300 characters. Please help, thank you very much.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s