The MAX7219 is a IC that can drive 64 LED's, while you only need 4 wires to interface it to a microcontroller. So you can easily hook it to a 8x8 LED matrix module or an 7 segment display. In addition you can daisy chain multiple 7219 chips for more LED displays. The MAX7219 has a 4 wire SPI interface making it very easy to connect it to a microcontroller or a arduino.

 The MAX7219 has 24 pins of which 8 pins control the rows and 8 pins control the colums. The LED matrix display used here is a LuckyLight 8x8 1.2 inch display with an common anode. The color is amber.


schematic

Below is the schematic. The rows of the LED display are connectoed to the digit selection lines of the MAX7219. The colomns are connected to the segments of the MAX7219. There is resistor connectod to ISET to control the contrast of the display.


Build

The citcuit is made on an breadboard and connected to an ATMEGA328 board.


 C Code

The code is made with the WINAVR C-compilier. First the MAX is initialized by setting the different modes. The intensity is set to the maximum. 

 // program name: LED driver MAX7219 

// date: 2018.02.22
// author: www.avrprojects.net
// target device : ATMEGA328
// hardware: ATMEGE328 board, MAX7219, LED Matrix 8x8

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU = 20000000UL

#define clk_low 0b11111110
#define clk_high 0b00000001
#define load_low 0b00000000
#define load_high 0b00000010 
#define din_low 0b11111011
#define din_high 0b00000100

// adress
#define noop 0x00
#define decode_mode 0x09
#define intense_mode 0x0A
#define scanlim_mode 0x0B
#define shutdown_mode 0x0C
#define distest_mode 0xFF
#define dp 0b10000000

char second = 0;
int time_cntr = 0; //global variable for number of Timer 0

/// Timer 0 overflow interrupt service routine
ISR(TIMER0_OVF_vect)
{
//16.000.000hz/64=260000hz = 8µmS x 250 ticks = 1mS
//set timer/counter to 255-250 = 5
TCNT0= 10;
time_cntr++;
if (time_cntr == 250) /*check for one second, increment counter*/
{
time_cntr = 0 ;
second++;
}
}

void clk_pulse(void)
{
PORTC = PORTC & clk_low;
//_delay_ms(1);
PORTC = PORTC | clk_high;
//_delay_ms(1);
PORTC = PORTC & clk_low;
}

void send_bits(unsigned char data)
{
for (char i = 0; i < 8; i++)
{
// consider leftmost bit
// set line high if bit is 1, low if bit is 0 
if (data & 0x80)
PORTC = PORTC | din_high;
else
PORTC = PORTC & din_low; 
// pulse clock to indicate that bit value should be read
clk_pulse();
PORTC = PORTC & din_low;
// shift byte left so next bit will be leftmost
data <<= 1;
}
}

void send_data(unsigned char adress, unsigned char data)
{
send_bits(adress);
send_bits(data);
PORTC = load_low;
PORTC = load_high;
}

void screen(char data[8])
{
for (char i = 0; i < 8; i++)
{
send_data(i+1,data[i]);
}
}

int main (void)


// init
DDRC = 0xFF; //set PORTC as output
PORTC = 0; // reset PORTC

//set timer 0 prescaler to clk/256*/
TCCR0A = 0b00000000;
TCCR0B = 0b00000100;
// enable Timer 0 overflow interrupt*/
TIMSK0 = 0x01;
sei();

// init display
send_data(shutdown_mode,0x01);
send_data(scanlim_mode,0x0F);
send_data(intense_mode,0x01);
send_data(decode_mode,0x00); //set decode mode
//test();

char smile[8] = {0B11111111,0B10000001,0B10100101,0B10000001,0B10100101,0B10011001,0B10000001,0B11111111};
char heart[8] = {0b00000000,0b01100110,0b11111111,0b11111111,0b01111110,0b00111100,0b00011000,0b00000000};
char angry[8] = {0B11111111,0B10000001,0B10100101,0B10000001,0B10011001,0B10100101,0B10000001,0B11111111};

while(1)
{
{
screen(smile);
_delay_ms(500);
screen(angry);
_delay_ms(500);
screen(heart);
_delay_ms(500);
}
}
}