MAX7219 Display Controller with the PIC18F4620
by Joe DiMeglio
So i ordered a MAX7912 from ebay - it arrived and then i went looking for some quick code so that i can start playing with it. How wrong was I. I found bits and peace's here and there but ultimately i ended up writing my own code and thought i'd post it so maybe that it can help some other poor sole.
The 8x8 matrix i received from ebay actually comes on a mounted board with a MAX7219. I fired up Proteus and wired up my PIC to a MAX7219 and then to my 8x8 LED matrix. This was the hardest part due to the lack of pin out descriptions for the 8x8 matrix within Proteus.
Probably would have been quicker if i'd just played with it on my bread board. :-)
Here's my MAX7912 8x8 driver. The code was written with CCS C Compiler - i'm sure it could be pretty easily to modify for other C Compilers.
This is my basic driver file. It contains the routines that have been tested with a PICF4620 using its built in hardware SPI. It never made any sense to me to write a software SPI routine when i have a fully working SPI port. It includes font, that i borrowed from someone on the internet, saved me some trouble putting it together. If find his code again i'll provide a link to his code.
max7212.c
Probably would have been quicker if i'd just played with it on my bread board. :-)
Here's my MAX7912 8x8 driver. The code was written with CCS C Compiler - i'm sure it could be pretty easily to modify for other C Compilers.
This is my basic driver file. It contains the routines that have been tested with a PICF4620 using its built in hardware SPI. It never made any sense to me to write a software SPI routine when i have a fully working SPI port. It includes font, that i borrowed from someone on the internet, saved me some trouble putting it together. If find his code again i'll provide a link to his code.
max7212.c
#use delay (clock=40M) /* ******************************************************************************* Module : MAX7219.C * Author : Joe DiMeglio * Description: MAX7219 LED Display Driver Routines * * The host communicates with the MAX7219 using three signals: DATA, CLK, and LOAD using SPI. * ******************************************************************************/ // CONSTANTS // #define Chip_Select PIN_D0 //this is the pin on the PIC that connects to LOAD #define Chip_Select_Direction TRIS_D #define scanLimitAmount 0x07 // - Mode Selection #define nop 0x00 #define decode 0x09 #define brightness 0x0A #define scanLimit 0x0B #define shutDown 0x0C #define dispTest 0x0F // FOR more space, we don't need byte 0 and byte 7. // We have stripped them out, IF/when we have a need and a bigger PIC, // then we can put them back IF we want. // Here we define row values FOR each of the six columns corresponding to the // Alphabet, from A through Z. byte Alphabet[156]= { 0x7f, 0x88, 0x88, 0x88, 0x88, 0x7f, // A 0xff, 0x91, 0x91, 0x91, 0x91, 0x6e, // B 0x7e, 0x81, 0x81, 0x81, 0x81, 0x42, // C 0xff, 0x81, 0x81, 0x81, 0x81, 0x7e, // D 0x81, 0xff, 0x91, 0x91, 0x91, 0x91, // E 0x81, 0xff, 0x91, 0x90, 0x90, 0x80, // F 0x7e, 0x81, 0x81, 0x89, 0x89, 0x4e, // G 0xff, 0x10, 0x10, 0x10, 0x10, 0xff, // H 0x00, 0x81, 0xff, 0xff, 0x81, 0x00, // I 0x06, 0x01, 0x81, 0xfe, 0x80, 0x00, // J 0x81, 0xff, 0x99, 0x24, 0xc3, 0x81, // K 0x81, 0xff, 0x81, 0x01, 0x01, 0x03, // L 0xff, 0x60, 0x18, 0x18, 0x60, 0xff, // M 0xff, 0x60, 0x10, 0x08, 0x06, 0xff, // N 0x7e, 0x81, 0x81, 0x81, 0x81, 0x7e, // O 0x81, 0xff, 0x89, 0x88, 0x88, 0x70, // P 0x7e, 0x81, 0x85, 0x89, 0x87, 0x7e, // Q 0xff, 0x98, 0x98, 0x94, 0x93, 0x61, // R 0x62, 0x91, 0x91, 0x91, 0x91, 0x4e, // S 0xc0, 0x81, 0xff, 0xff, 0x81, 0xc0, // T 0xfe, 0x01, 0x01, 0x01, 0x01, 0xfe, // U 0xfc, 0x02, 0x01, 0x01, 0x02, 0xfc, // V 0xff, 0x02, 0x04, 0x04, 0x02, 0xff, // W 0xc3, 0x24, 0x18, 0x18, 0x24, 0xc3, // X 0xc0, 0x20, 0x1f, 0x1f, 0x20, 0xc0, // Y 0xc3, 0x85, 0x89, 0x91, 0xa1, 0xc3, // Z }; byte Symbols[114] = { 0x00, 0x3c, 0x42, 0x81, 0x00, 0x00, // ( 0x00, 0x00, 0x81, 0x42, 0x3c, 0x00, // ) 0x00, 0x00, 0xff, 0x81, 0x00, 0x00, // [ 0x00, 0x00, 0x81, 0xff, 0x00, 0x00, // ] 0x00, 0x18, 0xe7, 0x81, 0x00, 0x00, // 0x00, 0x00, 0x81, 0xe7, 0x18, 0x00, // 0x00, 0x18, 0x24, 0x42, 0x81, 0x00, // < 0x00, 0x81, 0x42, 0x24, 0x18, 0x00, // > 0x00, 0x03, 0x0c, 0x30, 0xc0, 0x00, // / 0x00, 0xc0, 0x30, 0x0c, 0x03, 0x00, // \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0xfd, 0xfd, 0x00, 0x00, // ! 0x60, 0x80, 0x8d, 0x8d, 0x90, 0x60, // ? 0x42, 0x24, 0xff, 0xff, 0x24, 0x42, // * 0x24, 0xff, 0x24, 0x24, 0xff, 0x24, // # 0x62, 0x91, 0xff, 0xff, 0x91, 0x4e, // $ 0x66, 0x99, 0x99, 0x66, 0x09, 0x00, // & 0x42, 0xa4, 0x48, 0x12, 0x25, 0x42, // % 0x20, 0x3f, 0x20, 0x20, 0x3e, 0x21, // pi }; // latch the bits into the MAX VOID pulseCS(void) { output_bit (Chip_Select, 1); delay_us (2) ; output_bit (Chip_Select, 0); } //send data to MAX VOID send7219 (byte address, byte data) { //make a 16 bit variable address byte high, data byte low Int16 SerialData; SerialData = make16 (address, data); spi_xfer (SerialData); //transfer using spi software pulseCS (); } //Init MAX VOID InitMax7219 (void) { output_bit (Chip_Select, 0); // Set RD0 pin as hight set_tris_d(0x00) ; //configure properly send7219 (decode, 0x00); //no decoding (MSB) send7219 (brightness, 0x09); //Segment luminosity intensity send7219 (scanLimit, scanLimitAmount); //Scan all 7 digits send7219 (shutDown, 0x01); //No Shutdown reg. send7219 (dispTest, 0x00); // No test } // This is clear matrix function. VOID Clear7219 (void) { byte Addr; FOR (Addr = 1; Addr < scanLimitAmount+1; Addr++) { send7219 (Addr, 0x00) ; } } //Write CHAR to the screen VOID WriteChar7219 (byte myChar) { byte Column, Start_Byte; Start_Byte = (myChar - 65) * 6; // 65 represents the letter "A" in ASCII code. // We are using only columns from 2 through 7 FOR displaying the character. FOR (Column = 7; Column > 1; Column--) { send7219 (Column, Alphabet[Start_Byte++]); } } |
So all you would then do is this:
#include <18F4620.h> #fuses HS,NOLVP,NOWDT #use delay (clock=40M) #use fast_io(D) #USE SPI (MASTER, SPI1, BAUD=1000000, MODE=0, BITS=16, LOAD_ACTIVE=1, STREAM=SPI_1, MSB_FIRST,IDLE=1) #include <max7912.c> //my driver file :-) #define Chip_Select PIN_D0 //this is the pin on the PIC the LOAD must be connected to. #define Chip_Select_Direction tris_d(0) // Main function. VOID main() { InitMax7219 (); DO // infinite loop. { // You can write the characters this way, one at a time. WriteChar7219("J"); delay_ms(50); WriteChar7219("O"); delay_ms(50); WriteChar7219("E"); delay_ms(50); }WHILE (1); // do forever. } |
So it then occurred to me to have some fun and write some graphic routines. Still in early stages.
Demoone(); scrolls the characters across the screen. While demotwo(); has two bouncing balls bouncing off the edges.
#include <18F4620.h> #fuses HS,NOLVP,NOWDT #use delay (clock=40M) #use fast_io(D) #USE SPI (MASTER, SPI1, BAUD=1000000, MODE=0, BITS=16, LOAD_ACTIVE=1, STREAM=SPI_1, MSB_FIRST,IDLE=1) #include <max7912.c> #define Chip_Select PIN_D0 #define Chip_Select_Direction tris_d(0) byte VR[8]; //Video RAM used to draw the screen before sending to the 8x8 matrix int x=5 ,y=0; // starting position of ball one int xdir=1, ydir=1; //the director ball one will go int x1=0 ,y1=3; //starting poistion of ball two int x1dir=1, y1dir=-1; //its starting position //clear the "screen" - its the video ram thats getting cleared void grx_cls(void) { byte x; for (x=0;x<8; x++) { VR[x] = 0; } } //send it to the hardware void grx_display(void) { byte Addr, Row=0; FOR (Addr = 1; Addr < 9; Addr++) { send7219 (Addr, VR[row++]); } } //light up that LED at x,y position void grx_setxy(byte x,y) { byte temp; temp = 1; temp <<=x; VR[y]|=temp; // read row X at column Y } //turn off that LED at x,y position void grx_unsetxy(byte x,y) { byte temp; temp = 1; temp <<=x; temp = 255 - temp; VR[y]&=temp; // read row X at column Y } //Write CHAR to the screen VOID grx_WriteChar(byte myChar) { byte Column, Start_Byte; Start_Byte = (myChar - 65) * 6; // 65 represents the letter "A" in ASCII code. // We are using only columns from 2 through 7 FOR displaying the character. FOR (Column = 7; Column > 1; Column--) { VR[Column]=Alphabet[Start_Byte++]; } } //scroll left the contents in the video ram void grx_scroll(byte x,clip,dir) { byte scroll,edge; edge=VR[7]; //save last row for (scroll=7;scroll>0;scroll--) { VR[scroll]=VR[scroll-1]; } VR[0]=edge; //put in the first row } //anitmate the bouncing balls. void bouncing(void) { grx_setxy(x,y); //draw the ball one grx_setxy(x1,y1); //draw ball two grx_display(); //display it Delay_ms (5) ; grx_unsetxy(x,y); //turn them off grx_unsetxy(x1,y1); x= x + xdir; //new position y =y + ydir; if (x>=7||x<=0) //check if they hit the edges if so change direction. { xdir=-xdir; } if (y>=7||y<=0) { ydir=-ydir; } x1= x1 + x1dir; //same for ball two y1 =y1 + y1dir; if (x1>=7||x1<=0) { x1dir=-x1dir; } if (y1>=7||y1<=0) { y1dir=-y1dir; } } //demo scrolling left VOID demoone(VOID) { grx_scroll(1,0,0); delay_ms(5); grx_display(); //display it } VOID demotwo(VOID) { bouncing(); } // Here we have the main function. VOID main() { Delay_ms(100); InitMax7219 (); grx_cls(); // clear RAM grx_display(); //display it grx_WriteChar('X'); grx_display(); //display it DO // infinite loop. { // You can write the characters this way, one at a time. demoone(); //demotwo(); }WHILE (1); // do forever. } |
One more video of it scrolling - see it works. :-)
My circuit diagram too.
enjoy.
References:
http://www.bristolwatch.com/PIC18F2550/PIC18F2550_MAX7219.htm
http://www.maximintegrated.com/en/products/power/display-power-control/MAX7219.html
Can I use this microchip picf4620 for bigger displys like lcd tvs
ReplyDeleteThanks but I'm not sure I understand your question . The picf4620 is the processor which drives the max chip which in turn drives the 8x8 matrix.
ReplyDeleteFor bigger displays you'd need to change the max chip wih the equivalent chip/video chip.
This is an old circuit and there are so many other easier options available - that other than fun factor probably wouldn't use this chip. Eg raspberry Pi
:-)
Thanks bruh
Delete