Displaying Diwali Patterns on an 8x8 LED Matrix Using Arduino and 74HC595 Shift Registers

by Rachana Jain in Circuits > Arduino

417 Views, 1 Favorites, 0 Comments

Displaying Diwali Patterns on an 8x8 LED Matrix Using Arduino and 74HC595 Shift Registers

Untitled design (7).png

This project demonstrates how to display Diwali-related patterns on an 8x8 LED matrix using an Arduino. The 8x8 matrix is controlled by two 74HC595 shift registers: one controlling the rows and the other controlling the columns. The project uses bit-banging to send data to the shift registers and displays various festive patterns such as diya (lamp), candle, firecacker and more, symbolizing the joy and spirit of Diwali.

Supplies

  1. Arduino UNO
  2. 8x8 LED Matrix: Displays the Diwali patterns by turning on specific LEDs.
  3. 2 x 74HC595 Shift Registers: One controls the rows, and the other controls the columns of the 8x8 matrix.
  4. Jumper Wires: Used for connections between components

Circuit Diagram

Displaying Diwali Patterns on an 8x8 LED Matrix Using Arduino and 74HC595 Shift Registers Schematic Diagram.png
Displaying Diwali Patterns on an 8x8 LED Matrix Using Arduino and 74HC595 Shift Registers Circuit Diagram.png
74HC595-IC-Pin-Configuration.jpg

The 8x8 LED matrix consists of 64 LEDs arranged in rows and columns. The rows are controlled by one 74HC595 shift register in a common anode configuration (all LEDs in a row share a common positive connection), and the columns are controlled by another 74HC595 in a common cathode configuration (all LEDs in a column share a common negative connection).

  1. Row Control (74HC595 #1): This shift register controls the rows by sourcing current to the anodes of the LEDs.
  2. Column Control (74HC595 #2): This shift register controls the columns by sinking current from the cathodes of the LEDs.

The shift registers are connected to the Arduino via three control lines:

  1. Data Pin: Transfers the data to be shifted into the register.
  2. Clock Pin: Synchronizes data shifts with clock pulses.
  3. Latch Pin: Latch the contents of shift register on output pins.

Working of the Components:

  1. 74HC595 Shift Register: This is an 8-bit serial-in parallel-out shift register, meaning you can send data to it one bit at a time, and it will output that data across its 8 output pins. It allows controlling multiple LEDs with fewer Arduino pins by using the shift register to expand the I/O.
  2. 8x8 LED Matrix: Each LED in the matrix is at the intersection of a row and a column. By controlling the rows and columns using the shift registers, you can select which LED to light up at any given time. Multiplexing is used to display patterns.

Code

Upload the following code to Arduino UNO:

/*
Code to Interface 8x8 Matrix in which
Rows are controlled by 74Hc595 Memory in Common Anode manner( Common + for all LEDS in a ROW) and
Columns are controlled by 74HC595 IC in Common Cathode manner( Common - for all LEDS in a COLUMN)
by www.playwithcircuit.com
Bit Banging code is used for communication with 74HC595 IC
*/

unsigned char alphabets[26][8] = {
{ 0x38, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00 }, //A 1
{ 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 }, //B 2
{ 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00 }, //C 3
{ 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00 }, //D 4
{ 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7C, 0x00 }, //E 5
{ 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00 }, //F 6
{ 0x38, 0x44, 0x40, 0x40, 0x5C, 0x44, 0x38, 0x00 }, //G 7
{ 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00 }, //H 8
{ 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00 }, //I 9
{ 0x7C, 0x08, 0x08, 0x08, 0x48, 0x48, 0x38, 0x00 }, //J 10
{ 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00 }, //K 11
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00 }, //L 12
{ 0x44, 0x6C, 0x54, 0x44, 0x44, 0x44, 0x44, 0x00 }, //M 13
{ 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00 }, //N 14
{ 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 }, //O 15
{ 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00 }, //P 16
{ 0x38, 0x44, 0x44, 0x44, 0x54, 0x4C, 0x3C, 0x00 }, //Q 17
{ 0x78, 0x44, 0x44, 0x44, 0x78, 0x44, 0x44, 0x00 }, //R 18
{ 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00 }, //S 19
{ 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00 }, //T 20
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00 }, //U 21
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00 }, //V 22
{ 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00 }, //W 23
{ 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00 }, //X 24
{ 0x44, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00 }, //Y 25
{ 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00 }, //Z 26
};

#define DELAY delayMicroseconds(1);

#define ROW_CLOCK 12
#define ROW_DATA 11
#define ROW_LATCH 10

#define ROW_CLOCK_HIGH digitalWrite(ROW_CLOCK, HIGH);
#define ROW_CLOCK_LOW digitalWrite(ROW_CLOCK, LOW);

#define ROW_DATA_HIGH digitalWrite(ROW_DATA, HIGH);
#define ROW_DATA_LOW digitalWrite(ROW_DATA, LOW);

#define ROW_LATCH_HIGH digitalWrite(ROW_LATCH, HIGH);
#define ROW_LATCH_LOW digitalWrite(ROW_LATCH, LOW);

#define ROW_CLOCK_PULSE \
{ ROW_CLOCK_LOW DELAY ROW_CLOCK_HIGH } // this is used as clock pulse for row IC

#define ROW_LATCH_PULSE \
{ ROW_LATCH_LOW DELAY ROW_LATCH_HIGH } // this is used as latch pulse for row IC

#define COLUMN_CLOCK 7
#define COLUMN_DATA 6
#define COLUMN_LATCH 5

#define COLUMN_CLOCK_HIGH digitalWrite(COLUMN_CLOCK, HIGH);
#define COLUMN_CLOCK_LOW digitalWrite(COLUMN_CLOCK, LOW);

#define COLUMN_DATA_HIGH digitalWrite(COLUMN_DATA, HIGH);
#define COLUMN_DATA_LOW digitalWrite(COLUMN_DATA, LOW);

#define COLUMN_LATCH_HIGH digitalWrite(COLUMN_LATCH, HIGH);
#define COLUMN_LATCH_LOW digitalWrite(COLUMN_LATCH, LOW);

#define COLUMN_CLOCK_PULSE \
{ COLUMN_CLOCK_LOW DELAY COLUMN_CLOCK_HIGH } // this is used as clock pulse for row IC

#define COLUMN_LATCH_PULSE \
{ COLUMN_LATCH_LOW DELAY COLUMN_LATCH_HIGH } // this is used as latch pulse for row IC

void row_putbyte(unsigned char databyte);

byte fillscreen[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
byte clearscreen[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte diya[8] = { 0x10, 0x28, 0x28, 0x92, 0xFE, 0x82, 0x44, 0x38 };
byte smiley[8] = { 0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C };
byte heart[8] = { 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18 };
byte arrow[8] = { 0x18, 0x0C, 0x06, 0xFF, 0xFF, 0x06, 0x0C, 0x18 };
byte sathiya[8] = { 0x9E, 0x90, 0x90, 0xFE, 0x12, 0x12, 0xF2, 0x00 };

byte om[8] = { 0x14, 0x68, 0x96, 0x19, 0xA1, 0x95, 0x52, 0x30 };
byte anar[8] = { 0x00, 0x44, 0x28, 0xD6, 0x10, 0x38, 0x7C, 0xFE };
byte candle[8] = { 0x10, 0x28, 0x28, 0x10, 0x38, 0x38, 0x38, 0x38 };
byte ladoo[8] = { 0x08, 0x14, 0x36, 0x49, 0x7F, 0x41, 0x3E, 0x00 };

byte charkhi_1[8] = { 0x10, 0x10, 0x18, 0x27, 0xE4, 0x18, 0x08, 0x08 };
byte charkhi_2[8] = { 0x02, 0x84, 0x58, 0x24, 0x24, 0x1A, 0x21, 0x40 };

byte diyaPattern[22] = {
0x30, 0x41, 0x42, 0x43, 0x33, 0x22, 0x12, 0x03,
0x14, 0x24, 0x44, 0x45, 0x36, 0x46, 0x56, 0x65,
0x74, 0x73, 0x72, 0x61, 0x50, 0x40,
};

byte smileyPattern[26] = {
0x02, 0x11, 0x20, 0x30, 0x40, 0x50, 0x61, 0x72,
0x73, 0x74, 0x75, 0x66, 0x57, 0x47, 0x37, 0x27,
0x16, 0x05, 0x04, 0x03, 0x22, 0x25, 0x42, 0x53,
0x54, 0x45
};

byte sathiyaPattern[26] = {
0x06, 0x05, 0x04, 0x03, 0x13, 0x23, 0x33, 0x43,
0x53, 0x63, 0x62, 0x61, 0x60, 0x00, 0x10, 0x20,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x46,
0x56, 0x66
};

void setup() {
//set pins to output so you can control the shift register and initially they should be HIGH
pinMode(ROW_CLOCK, OUTPUT);
pinMode(ROW_DATA, OUTPUT);
pinMode(ROW_LATCH, OUTPUT);
digitalWrite(ROW_CLOCK, HIGH);
digitalWrite(ROW_DATA, HIGH);
digitalWrite(ROW_LATCH, HIGH);
pinMode(COLUMN_CLOCK, OUTPUT);
pinMode(COLUMN_DATA, OUTPUT);
pinMode(COLUMN_LATCH, OUTPUT);
digitalWrite(COLUMN_CLOCK, HIGH);
digitalWrite(COLUMN_DATA, HIGH);
digitalWrite(COLUMN_LATCH, HIGH);
}

void loop() {
displayPattern(diyaPattern, 26, 20);
runStringLtoR("HAPPYDIWALI", 11, 10);
displayPattern(sathiyaPattern, 26, 10);
fillImageLong(candle, 50,1);
fillImageLong(anar, 50,0);
displayCharkhi(50);
}

void displayCharkhi(unsigned char displaytime) {
unsigned char counter=0;

do {
displayImage(charkhi_1, 10);
displayImage(charkhi_2, 10);
} while (counter++ < displaytime);
}

void row_putbyte(unsigned char databyte) {
char i;
for (i = 0; i < 8; i++) {
if ((databyte & 0x80) == 0x80) { // change data i.e send 8 bit of data over data line starting from MSB
ROW_DATA_HIGH
} else {
ROW_DATA_LOW
}
ROW_CLOCK_PULSE
databyte = databyte << 1; // left shift of data
}
}

void displayAlphabet(unsigned char alphabet, unsigned char displaytime) {
unsigned char alpha;
if (alphabet >= 65 && alphabet <= 90) {
alpha = alphabet - 65;
displayImage(alphabets[alpha], displaytime);
} else if (alphabet >= 97 && alphabet <= 122) {
alpha = alphabet - 97;
displayImage(alphabets[alpha], displaytime);
} else if (alphabet == 0x20)
displayImage(clearscreen, displaytime);
}

void runStringLtoR(unsigned char* displayString, unsigned char stringLength, unsigned char displaytime) {
char i, j, n;
unsigned char localImageBuffer[8] = { 0x00 };
unsigned char currentAlphabet[8] = { 0 };
unsigned char alphaIndex;

for (n = 0; n < stringLength; n++) {
// find the alphbet od string , find its index in alphabets[][] array and fill in the current Alphabet
if (displayString[n] >= 65 && displayString[n] <= 90) {
alphaIndex = displayString[n] - 65;
memcpy(currentAlphabet, alphabets[alphaIndex], 8);
} else if (displayString[n] >= 97 && displayString[n] <= 122) {
alphaIndex = displayString[n] - 97;
memcpy(currentAlphabet, alphabets[alphaIndex], 8);
} else {
memset(currentAlphabet, 0x00, 8);
}

for (j = 0; j < 8; j++) { // this loop is run for 8 times so that all colums is shited into localImageBuffer
// fill the current Alphabet into the local image buffer starting From its MSB
for (i = 0; i < 8; i++) {
localImageBuffer[i] = localImageBuffer[i] << 1; // first left current byte of local buffer shift by 1 bit
if (currentAlphabet[i] & (0x80)) {
localImageBuffer[i] |= 0x01; // Turn the LSB High
} else {
localImageBuffer[i] &= ~(0x01); // Turn the LSB LOW
}
currentAlphabet[i] = currentAlphabet[i] << 1; // left shift the current byte of current Alphabet
}
displayImage(localImageBuffer, displaytime);
}
}
}

void fillImageLong(unsigned char imagebuffer[8], unsigned char image_filling_time, char type) {
char i;
unsigned char localImageBuffer[8] = { 0x00 };
for (i = 0; i <= 7; i++) {
if (type) {
memcpy(localImageBuffer, imagebuffer, i + 1); // fill image top to botton
} else {
memcpy(localImageBuffer, imagebuffer, 8); // fill image completely into local buffer
memset(localImageBuffer, 0x00, 7 - i); // clear those ROWs which need needs to be off, from botton to top manner
}
displayImage(localImageBuffer, image_filling_time);
}
}

void displayPattern(unsigned char pattern[], unsigned char patternLength, unsigned char displaytime) {
unsigned char image[8] = { 0x00 };
char column, row, i;

// this loop puts the patterns bytes one by one as Most significant nibble is row and least significant nibble is column
for (i = 0; i < patternLength; i++) {
column = pattern[i] & 0x0F;
row = pattern[i] & 0xF0;
row = row >> 4;
image[row] |= 0x80 >> column;
displayImage(image, displaytime);
}
}

void displayImage(unsigned char imagebuffer[8], unsigned char displaytime) {
char row, column;
unsigned char counter = 0;

do {
display(imagebuffer);
} while (counter++ < displaytime);
}

void display(unsigned char staticDisplay[8]) {
char row, column;
for (row = 0; row < 8; row++) {
// We need to send byte to the columns in Left Most column first manner
// Hence we are sending the data MSB first and the bit shout be incerted as column is connected to Cathode(-).
for (column = 0; column < 8; column++) {
if ((staticDisplay[row] & (0x80 >> column))) {
COLUMN_DATA_LOW // to glow the LED it should be LOW, as column is connected to cathode
} else {
COLUMN_DATA_HIGH // to turn off the LED it should be HIGH, as column is connected to cathode
}
COLUMN_CLOCK_PULSE
}
COLUMN_LATCH_PULSE
// Now provide ROW data and turn On sigle ROW at a Time ROW is connected to Anode
row_putbyte((1 << row));
ROW_LATCH_PULSE
delay(1); // delay of 1 ms
// This is done becuse next LED which should glow it glows in previous ROW
// hence before changing the column data all LED off byte is sent
row_putbyte(0x00);
ROW_LATCH_PULSE
}
}