Kinda Small Displays - Part 3

About: We are passionate programmers and embedded devices developers from Deggendorf, Germany. The AZ-Delivery Vertriebs GmbH, was established in 2016 with the purpose to offer our customers high-quality microelect...

This is part 3 of our series "Introducing Displays for Arduino and Raspberry Pi". Here we will write about 4x64 LED matrix display and 4 or 8 digit seven segment display. We already explain what is a display in our instructable where we wrote about OLED displays and what is an LED - Light Emitting Diode in our instructable. Now we will expand it.

As its name says 4x64 LED matrix display is a display with arrays of LEDs stacked one by one in matrix. This display (4x64 led matrix) is made out of 4 smaller 8x8 displays that we will call segments. 8x8 mean that there are 8 LEDs in one array (row) and there are 8 stacks of that arrays, which create matrix of 64 LEDs, or pixels. As we already know, to power up one LED we need two wires, one for power, and one for ground. And when we have 64 LED that is a lot of wires, which is very hard to control. That is why we connect LEDs like on diagram which create LED matrix (this is logical symbol for LEDs used in schematics diagrams). This is how our 8x8 LED matrix segment is connected. You can take it out of display board and see it image. It has 16 legs, and if we use it like this we will need at least 16 output pins on our Arduinos for only one 8x8 LED matrix. That is to much, so people invented LED matrix drivers. LED matrix driver in our case is MAX7219 chip. All you have to know about it is that we will use SPI communication protocol to speak with it, and you can stack one by one serialy and by this you can create really long display. Here we have 4 drivers connected serialy to create 4x64 LED matrix display. But we can stack it up more if we desire so, and we will do it in step 5. This stacking of chips is also called chaining of chips.

Seven segment display is actually seven LEDs arranged in digital number 8 (actually eight LEDs, with little dot on bottom near the digit, H segment, but its name does not change to eight segment). By turning few segments (LEDs) we get those retro digital numbers. Now we get same problem for controlling these displays. Every segment on 7 segment displays needs one line for power, and whole display needs one line for ground. That is 8 or 9 lines, we can make this work, but it is always better to use as less as possible lines. So to drive these displays we use the same chip as for LED matrix displays. This chip, MAX7219, is capable to drive 8 of seven segment displays, so that is why we have 8 bit seven segment displays. We also have 4 bit seven segment displays which use TM1637 driver chip. With MAX7219 driver chip we need only 4 lines to drive at least one seven segment display, and as many as 8 of seven segment displays. And with TM1637, we only need two lines to drive 4 seven segment displays.

For this instructable we will need:

We will use Uno, but you can use any of Arduino boards, just make sure to change connection diagrams.

We have free Quick Starter Guide for Uno R3 if tou need starter guide. We also have free Quick Starter Guide for 4x64 LED matrix display, and free Quick Starter Guide for breadboard and jumper wires.

Step 1: SPI Communication Protocol

SPI stand for Serial Peripheral Interface, and it is used for sending and receiving data between microcontrollers or other peripherals (sensors, memories, etc.). In some sources it is called 4-wire protocol because we obviously use only 4 wires to make hardware connections. For this protocol there are separate clock and data lines, and there are two lines for data, for every data direction one line. The fourth line is chip select line which is used to select with which slave device, master device is establishing communication. Usually communication is established between one master and one or many slave devices. Master device sends command, and waits for response from specific slave device. When specific device respond, communication if finished, and next can start. Lines names:

  • SCK - Serial Clock
  • MOSI - Master Out Slave In (data output from master)
  • MISO - Master In Slave Out (data output from slave)
  • SS - Slave Select (output from master, often active low)

We also have SPI protocol which can have multiple master devices, but those master devices can not communicate with each other, and we will not use this in our instructable posts.

Step 2: Libraries

For LED matrix display connect everything like on diagram.

To download library for 8x8 LED matrix display, open Arduino IDE, go to Tools > Manage Libraries and in search box type “MAX72XX”, install library by majicDesigns. Then we have to detect which display we are using. Go to File > Examples > MD_MAX72XX > MD_MAX72xx_HD_Mapper, and upload this sketch to your arduino. Then run Serial Monitor, Tools > Serial Monitor and change baud rate to 57600. After that follow instructions sent by Arduino to your Serial Monitor. There are three steps to this, and after which you should get this. So the result is FC16_HW, and we will use this in next steps.

For 8 bit seven segment display connect everything like on diagram. To download library for 8 bit seven segment display, open Arduino IDE, go to Tools > Manage Libraries and in search box type “LedControl” and install library by Eberhard Fahle. With this library comes three sketch examples, and we will use File > Examples > LedControl > LCDemo7Segmet, and we will modify it heavily.

For 4 bit seven segment display connect everything like on diagram. Again to download TM1637 library for this display, go to this link and download zip file. Than in Arduino IDE go to Sketch > Include Library > Add .ZIP Library. With this library comes only one program example, File > Examples > TM1637 > TM1637Test.

Step 3: Test Sketch for 8x8 LED Matrix

For this we will modify existing sketch, File > Examples > MD_MAX72XX > MD_MAX72xx_Test. This sketch is so complex to understand if you are beginner, so we will modify it, and explain everything.

Connect everything like on diagram from step 2.

Here is modified code, (just uncomment library in first #include because Instructable don't show it uncommented):

// Program to exercise the MD_MAX72XX library
// Uses most of the functions in the library
#include // <MD_MAX72xx.h >

// Turn on debug statements to the serial output
#define  DEBUG  1

#if  DEBUG
#define PRINT(s, x) { Serial.print(F(s)); Serial.print(x); }
#define PRINTS(x) Serial.print(F(x))
#define PRINTD(x) Serial.println(x, DEC)</p><p>#else
#define PRINT(s, x)
#define PRINTS(x)
#define PRINTD(x)
#endif

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES  4
#define CLK_PIN   13  // or SCK
#define DATA_PIN  11  // or MOSI
#define CS_PIN    10  // or SS

// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// We always wait a bit between updates of the display
#define  DELAYTIME  100  // in milliseconds

void scrollText(char *p) {
	uint8_t charWidth;
 	uint8_t cBuf[8];  // this should be ok for all built-in fonts
        PRINTS("\nScrolling text");
 	mx.clear();

        while (*p != '\0') {
 	   	charWidth = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
                for (uint8_t i=0; i<=charWidth; i++) { // allow space between characters
     			mx.transform(MD_MAX72XX::TSL);
      		        if (i < charWidth) {
        			mx.setColumn(0, cBuf[i]);
      		        }
      		        delay(DELAYTIME);
		}
    	}
}
void zeroPointSet() {
	// Demonstrates the use of setPoint and
	// show where the zero point is in the display
	PRINTS("\nZero point highlight");
  	mx.clear();
 	if (MAX_DEVICES > 1) {
    		mx.setChar((2*COL_SIZE)-1, '0');
  	}
  	for (uint8_t i=0; i<ROW_SIZE; i++) {
		mx.setPoint(i, i, true);
		mx.setPoint(0, i, true);
		mx.setPoint(i, 0, true);
		delay(DELAYTIME);
	}
	delay(DELAYTIME*3);
}

void rows() {
	// Demonstrates the use of setRow()
  	mx.clear();

  	for (uint8_t row=0; row<ROW_SIZE; row++) {
		mx.setRow(row, 0xff);
		delay(2*DELAYTIME);
		mx.setRow(row, 0x00);
	}
}

void columns() {
	// Demonstrates the use of setColumn()
	mx.clear();

  	for (uint8_t col=0; col<mx.getColumnCount(); col++) {
		mx.setColumn(col, 0xff);
		delay(DELAYTIME/MAX_DEVICES);
		mx.setColumn(col, 0x00);
	}
}

void stripe() {
	// Demonstrates animation of a diagonal stripe moving across the display
	// with points plotted outside the display region ignored.
  	const uint16_t maxCol = MAX_DEVICES*ROW_SIZE;
  	const uint8_t stripeWidth = 10;

  	mx.clear();
	for (uint16_t col=0; col<maxCol + ROW_SIZE + stripeWidth, col++) {
		for(uint8_t row=0; row < ROW_SIZE; row++) {
			mx.setPoint(row, col-row, true);
			mx.setPoint(row, col-row - stripeWidth, false);
		}
		delay(DELAYTIME);
	}
}

oid spiral() {
	// setPoint() used to draw a spiral across the whole display
	int  rmin = 0, rmax = ROW_SIZE-1;
  	int  cmin = 0, cmax = (COL_SIZE*MAX_DEVICES)-1;

	mx.clear();
  	while ((rmax > rmin) && (cmax > cmin)) {
    	// do row
    	for (int i=cmin; i<=cmax; i++) {
      		mx.setPoint(rmin, i, true);
      		delay(DELAYTIME/MAX_DEVICES);
    	}
    	rmin++;

    	// do column
    	for (uint8_t i=rmin; i<=rmax; i++) {
      		mx.setPoint(i, cmax, true);
      		delay(DELAYTIME/MAX_DEVICES);
    	}
    	cmax--;

    	// do row
    	for (int i=cmax; i>=cmin; i--) {
      		mx.setPoint(rmax, i, true);
      		delay(DELAYTIME/MAX_DEVICES);
    	}
    	rmax--;

    	// do column
    	for (uint8_t i=rmax; i>=rmin; i--) {
      		mx.setPoint(i, cmin, true);
      		delay(DELAYTIME/MAX_DEVICES);
    	}
    	cmin++;
  	}	
}

void bounce() {
	// Animation of a bouncing ball
  	const int minC = 0;
  	const int maxC = mx.getColumnCount()-1;
  	const int minR = 0;
  	const int maxR = ROW_SIZE-1;

 	int  nCounter = 0;
  	int  r = 0, c = 2;
  	int8_t dR = 1, dC = 1;  // delta row and column

   	mx.clear();

 	while (nCounter++ < 200) {
    		mx.setPoint(r, c, false);
    		r += dR;
    		c += dC;
    		mx.setPoint(r, c, true);
    		delay(DELAYTIME/2);

	   	if ((r == minR) || (r == maxR)) {
      			dR = -dR;
    		}
    		if ((c == minC) || (c == maxC)) {
      			dC = -dC;
    		}
  	}
}

void intensity() {
	// Demonstrates the control of display intensity (brightness) across
	// the full range.
  	uint8_t row;
  	mx.clear();

	// Grow and get brighter
  	for (int8_t i=0; i<=MAX_INTENSITY; i++) {
    		mx.control(MD_MAX72XX::INTENSITY, i);
    		mx.setRow(0, 0xff);
    		delay(DELAYTIME*10);
  	}
 	mx.control(MD_MAX72XX::INTENSITY, 8);
}

void blinking() {
	// Uses the test function of the MAX72xx to blink the display on and off.
  	int  nDelay = 1000;
  	mx.clear();
  	while (nDelay > 0) {
    		mx.control(MD_MAX72XX::TEST, MD_MAX72XX::ON);
    		delay(nDelay);
    		mx.control(MD_MAX72XX::TEST, MD_MAX72XX::OFF);
    		delay(nDelay);

	    	nDelay -= DELAYTIME;
  	}
}

void scanLimit(void) {
	// Uses scan limit function to restrict the number of rows displayed.
  	
  	mx.clear();

  	mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
  	for (uint8_t row=0; row<ROW_SIZE; row++) {
		mx.setRow(row, 0xff);
	}
	mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);

  	for (int8_t s=MAX_SCANLIMIT; s>=0; s--) {
    		mx.control(MD_MAX72XX::SCANLIMIT, s);
    		delay(DELAYTIME*5);
  	}
  	mx.control(MD_MAX72XX::SCANLIMIT, MAX_SCANLIMIT);
}

void transformation1() {
	// Demonstrates the use of transform() to move bitmaps on the display
	// In this case a user defined bitmap is created and animated.
  	uint8_t arrow[COL_SIZE] = {
  		0b00001000,
    		0b00011100,
    		0b00111110,
    		0b01111111,
    		0b00011100,
    		0b00011100,
    		0b00111110,
    		0b00000000
  	}

  	MD_MAX72XX::transformType_t  t[] = {
    		MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
    		MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
    		MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
    		MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
    		MD_MAX72XX::TFLR,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TRC,
    		MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD,
    		MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD, MD_MAX72XX::TSD,
    		MD_MAX72XX::TFUD,
    		MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU,
    		MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU, MD_MAX72XX::TSU,
    		MD_MAX72XX::TINV,
    		MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC,
    		MD_MAX72XX::TINV
  	}

 	mx.clear();

  	// use the arrow bitmap
  	mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
  	for (uint8_t j=0; j<mx.getDeviceCount(); j++) {
		mx.setBuffer(((j+1)*COL_SIZE)-1, COL_SIZE, arrow);
	}
	mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
	delay(DELAYTIME);

  	// run through the transformations
  	mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::ON);
  	for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); i++) {
    		mx.transform(t[i]);
    		delay(DELAYTIME*4);
  	}
  	mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::OFF);
}

void transformation2() {
	// Demonstrates the use of transform() to move bitmaps on the display
	// In this case font characters are loaded into the display for animation.
  	MD_MAX72XX::transformType_t  t[] = {
    		MD_MAX72XX::TINV,
    		MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC, MD_MAX72XX::TRC,
    		MD_MAX72XX::TINV,
    		MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL, MD_MAX72XX::TSL,
    		MD_MAX72XX::TSR, MD_MAX72XX::TSR, MD_MAX72XX::TSR,
    		MD_MAX72XX::TSD, MD_MAX72XX::TSU, MD_MAX72XX::TSD, MD_MAX72XX::TSU,
    		MD_MAX72XX::TFLR, MD_MAX72XX::TFLR, MD_MAX72XX::TFUD, MD_MAX72XX::TFUD
  	}

  	mx.clear();
  	mx.control(MD_MAX72XX::WRAPAROUND, MD_MAX72XX::OFF);

  	// draw something that will show changes
  	for (uint8_t j=0; j<mx.getDeviceConutn(); j++) {
		mx.setChar(((j+1)*COL_SIZE)-1, '0'+j);
	}
	delay(DELAYTIME*5);

 	// run thru transformations
  	for (uint8_t i=0; i<(sizeof(t)/sizeof(t[0])); i++) {
    		mx.transform(t[i]);
    		delay(DELAYTIME*3);
  	}
}

void wrapText() {
	// Display text and animate scrolling using auto wraparound of the buffer
  	
  	mx.clear();
  	mx.wraparound(MD_MAX72XX::ON);

  	// draw something that will show changes
  	for (uint16_t j=0; j<mx.getDeviceCount(); j++) {	
		mx.setChar(((j+1)*COL_SIZE)-1, (J&1 ? 'M' : 'W'));
	}
	delay(DELAYTIME);

  	// run thru transformations
  	for (uint16_t i=0; i<3*COL_SIZE*MAX_DEVICES; i++) {
    		mx.transform(MD_MAX72XX::TSL);
    		delay(DELAYTIME/2);
  	}

  	for (uint16_t i=0; i<3*COL_SIZE*MAX_DEVICES; i++) {
    		mx.transform(MD_MAX72XX::TSR);
    		delay(DELAYTIME/2);
  	}
  	for (uint8_t i=0; i<ROW_SIZE; i++) {	
		mx.transform(MD_MAX72XX::TSU);
		delay(DELAYTIME*2);
	}
	for(uint8_t i=0; i<ROW_SIZE; i++) {
		mx.transform(MD_MAX72XX::TSD);
		delay(DELAYTIME*2);
	}

	mx.wraparound(MD_MAX72XX::OFF);
}

void showCharset(void) {
	// Run through display of the the entire font characters set
	mx.clear();
  	mx.update(MD_MAX72XX::OFF);

  	for (uint16_t i=0; i<256; i++) {
    		mx.clear(0);
    		mx.setChar(COL_SIZE-1, i);

		if (MAX_DEVICES >= 3) {
      			char hex[3];
      			sprintf(hex, "%02X", i);
      			mx.clear(1);
      			mx.setChar((2*COL_SIZE)-1,hex[1]);
      			mx.clear(2);
      			mx.setChar((3*COL_SIZE)-1,hex[0]);
    		}

		mx.update();
		delay(DELAYTIME*2);
  	}
  	mx.update(MD_MAX72XX::ON);
}

void setup() {
  	mx.begin();
}

void loop() {
  	scrollText("Graphics");
  	zeroPointSet();
  	rows();
   	columns();
  	stripe();
  	bounce();
  	spiral();
  	scrollText("Control");
  	intensity();
  	scanLimit();
  	blinking();
  	scrollText("Transform");
  	transformation1();
  	transformation2();
  	scrollText("Charset");
  	wrapText();
  	showCharset();
}

Now, let’s explain.

First sketch include MD_MAX72XX.h library, than we see few definitions for macros. One special example is usage of Serial.print(F(x)). F(x) is macro that stores in this case “x” string in flash memory, not SRAM. By this we decrease limit of memory for our programs, which in most cases is enough, even to much, but increase SRAM memory, which is running memory and very important for running programs. If you do not use F(x) macro, most likely that you program won’t work as designed, because there are to many strings, which in C programming language are char arrays, and which eats up to much SRAM memory.

Than we define which display we use by setting hardware type to FC16_HW. This value we get in previous step. After this we define how much LED matrix display in chain we are using by setting MAX_DEVICES to 4. This we will change to 8 in next step.

There are three more macros which defines SPI communication protocol lines, after which we define mx object that is used throughout whole sketch.

After all of this, is where fun begins. We define functions for using LED matrix display.

First function as its name says is used for scrolling text on display. What we do here is that we are using built in function setColumn() which turns on/off one column array of LED on display. The rest is algorithm for scrolling text effect. We take string p from flash memory, and convert it in cBuf which is column array. and print it on LED matrix display. At the end of function we set delay time, and by changing it, we change the speed of scrolling text.

Second function is for displaying zero point of display. Here we use two built in functions, one is setChar() which takes two arguments, one is position of char on display, and second is actually char. Because we use 4 chained LED matrix displays, we get positions from 0 to 31, other positions are outside the display. And second builtin function is setPoint() which has three arguments, first two are X and Y position of one LED (pixel), and third is true for turning on that pixel, and false for turning off. In zeroPointSet() function we use setChar() to display a number 0 on second segment, and few setPoint() in for loop to display and arrow pointing to (0, 0) pixel on display.

Third function is rows() which uses built in function setRow(). setRow() function has two arguments, first which row will be used, where 0 mean first row from top. And second argument is number in hexadecimal, that represent 8 bit value for row array of pixels (8 pixels in one row). In this case we use 0xff which turns on all pixels.

Fort function is columns() which is same as rows() but in this case we turn on column arrays of pixels. It used built in function setColumn() which is the same as setRow() but just for columns.

Fifth function is stripe() which display scrolling diagonal stripe on whole display. In it we use nothing new, we see just the algorithm for scrolling stripe. At the end of this function we have delay() which can be used for changing the speed of scrolling stripe.

Sixth function is spiral() which displays snake like line that turns all pixels on display in spiral moving effect. Nothing new in here, just algorithm for turning pixel by pixel.

Seventh function is bounce() which displays moving pixel that bounces up of edges of LED matrix displays. The only thing new here is built in function getColumnCont() which returns number of columns on LED matrix display. The rest in this function is algorithm for moving pixel.

Eighth function is intensity(). We modified this function to turn on only first row, and change the speed of changing intensity, so that we can get sense of intensity. (other functions are same as in Example sketch). In this function we use control() function with two arguments, first is MD_MAX72XX::INTENSITY, which defines which property of mx object we will change, and second argument is number that represents intensity. Intensity means that we will change brightness of pixels, and number that represents intensity is in limits from 0 to 15, or 16 different intensities. Default value is 8.

Ninth function is blinking(), which blinks whole display (all pixels). It uses built in function control() but with two new arguments. First is MD_MAX72XX::TEST, which sets which property we are using, in this case turning on/off all display pixels, and second argument is MD_MAX72XX::ON / OFF which is used to turn on / off pixels.

Tenth function is scanLimit(), it uses special property of control() function, UPDATE. Here we use control() function with two arguments, MD_MAX72XX::UPDATE and MD_MAX72XX::OFF / ON. First we set OFF, turn off a display, than update display, here we can use anything, setRow(), setColumn(), setPoint(), even another control() and after all changes we set it ON. In scanLimit() function we set whole display on, than we use control() property MD_MAX72XX::SCANLIMIT to limit number of rows that is light up. At the beginning all rows are light up, than one by one is turned off. At the end, all rows are turned off.

Eleventh and twelve functions are transformation1() and transformation(). Both functions move bitmap images on display. First move arrow, and second letters. In first transforamtion1() function, we declare two arrays, one for arrow image which contain 8 bit binary numbers, and second is used for moving animation which contain enumerations for animation. Those 8 bit binary numbers represent rows of pixels, 8 rows, with 8 pixels, and with it we can show bitmap image on one segment. Enumerations are used for animation, and their format are MD_MAX72XX::”enumeration” and enumerations are:

  • TSL - Transform Shift Left one pixel element
  • TFLR - Transform Flip Left to Right
  • TSR - Transform Shift Right one pixel element
  • TRC - Transform Rotate Clockwise 90 degrees
  • TSD - Transform Shift Down one pixel element
  • TFUD - Transform Flip Up to Downl
  • TSU - Transform Shift Up one pixel element
  • TINV - Transform INVert (all pixels inverted, those who were light up, are off, and those who were not light up, are on).

After this we use UPDATE property of control() function to update display, and in it we use setBuffer() function to print arrow image. setBuffer() has three arguments, first two are for X and Y position of bitmap and third is for arrow array of binary numbers. Than we again use UPDATE property of control function and in it we use transform() function. This function takes one argument, and it is enumeration from above.

In transformation2() function we create array with enumerations, and use another property of control() function, which is MD_MAX72XX::WRAPAROUND, which can be set to OFF and ON to allow text to go outside display or not. After this we use setChar() function to display some text and then we transform it with transform() and enumerations.

Thirteenth function is warpText(). In this function we use built in function wraparound() which has one argument MD_MAX72XX::ON / OFF. When it is set to ON, which allows text to go outside of display, and then to again come back at beginning of display. After this we use animation to scroll it to left, to right, up and down.

Fourteenth function is showCharsset() which is used to show all Unicode characters that can be used on LED matrix display. Here we use built in function update() which act like mx.control with property UPDATE. First we set argument of update() to MD_MAX72XX::OFF than make changes, and at the end we set it to MD_MAX72XX::ON.

If you want to read more about these built in functions you should read this.

Step 4: Second Sketch for 8x8 LED Matrix

This is actually a way how to use other example sketches that you downloaded with library MD_MAX72XX. When you load any sketch from this library, you should change two things. first is to set up which display we are going to use, and second is to set up how many segments display has. we do it by setting this:

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4

Now load one sketch that is pretty cool, File > Examples > MD_MAX72XX > MD_MAX72xx_Pacman

:) and watch the chase.

Step 5: Chaining of LED Matrix Displays

In this step we will chain two 4x64 LED matrix displays. Connect everything like on diagram. And load any sketch from last two steps. Just change max devices from 4 to 8.

And that’s it. Peace of cake.

Step 6: Test Sketch for 8 Bit Seven Segment

If you connected everything like on diagram from step 2, then copy-paste this sketch into Arduino IDE.

#include "LedControl.h"  

/*
    __a__
  f|     |b
   |__g__|         =>   B(0000 0000) = B(habc defg)
 e|      |c
   |__d__|   .h   
   
*/

// Arduino Pin 7 to DIN, 6 to Clk, 5 to LOAD, no.of devices is 1
LedControl lc=LedControl(7,6,5,1);

void setup() {
   // Initialize the MAX7219 device
    lc.shutdown(0,false);   // Enable display
    lc.setIntensity(0,10);  // Set brightness level (0 is min, 15 is max)
    lc.clearDisplay(0);     // Clear display register
    delay(1000);
}
void loop() {
     setIT(); 
}

void setIT() {
    for(int i = 0; i < 21; i++) {  
      lc.setChar(0, i, 'a', false);              //  a
      lc.setDigit(0, i - 1, 2, false);           //  z
      lc.setRow(0, i - 2, 0x01);                 //  -
      lc.setChar(0, i - 3, 'd', false);          //  d
      lc.setChar(0, i - 4, 'e', false);          //  e
      lc.setRow(0, i - 5, B00001110);            //  l
      lc.setDigit(0, i - 6, 1, false);           //  i
      lc.setRow(0, i - 7, B00111110);            //  v
      lc.setChar(0, i - 8, 'e', false);          //  e
      lc.setRow(0, i - 9, 0x05);                 //  r
      lc.setRow(0, i - 10, B00111011);           //  y
      lc.setChar(0, i - 11, ' ', false);
      delay(300);
    }  
}

Here we first set up SPI communication on digital pin 7, 6 and 5 by setting LedControl(7, 6, 5, 1) constructor. Number 1 as forth argument is number of chip drivers used. There is one driver chip per 8 bit seven segment display.

Arduino pin > 8 bit seven segment pin

  • 5V > VCC
  • GND > GND
  • Digital pin 7 > DIN
  • Digital pin 5 > CS
  • Digital pin 6 > CLK

In setup() function we setup MAX7219 chip.

lc.shutdown(0, false) enables display 0

lc.setIntesiity(0, 10), sets intensity of display 0, and for intensity we have 16 different values, from 0 to 15.

lc.clearDisplay(0) clears display 0 register buffer.

In loop() function we call setIT() function which scrolls “AZ-Delivery” text on display.

In setIT() function we use several built in functions.

First is setDigit() which has four arguments, first is number of display (in our case that is 0), second is X position, or actually segment position, third is actual digit that we will display, and fourth is “false” which turns on specific segment.

Second is setChar() which also has four arguments, first two are the same as for setDigit() function, third is for character ‘a’ and here we can use only characters used in hexadecimal numbers ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, and ‘f’, and forth argument is the same as for setDigit() function.

Third built in function is setRow() which turns on any segment or segments we like. It has three arguments, where first two are the same as for setDigit() function, and third is binary representation of turned segments. If we name segments like on image, than binary number is constructed in this manner Bhabcdefg, example for letter L = B00001110.

And when we upload this sketch to our Arduino Uno, we will see magic in scrolling text.

Step 7: Test Sketch for 4 Bit Seven Segment

If you connected everything like on diagram, from step 2, copy-paste this sketch to your Arduino IDE.

#include // <Arduino.h>

#include // <TM1637Display.h>

// Module connection pins (Digital Pins)
#define CLK 2
#define DIO 3

// The amount of time (in milliseconds) between tests
#define TEST_DELAY   2000

const uint8_t SEG_DONE[] = {
  	SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,                 // d
  	SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,         // O
  	SEG_C | SEG_E | SEG_G,                                 // n
  	SEG_A | SEG_D | SEG_E | SEG_F | SEG_G                  // E
};

TM1637Display display(CLK, DIO);

void setup() {
}

void loop() {
    int k;
    uint8_t data[] = { 0xff, 0xff, 0xff, 0xff };  // 4 digits, 4 elements in array
    uint8_t blank[] = { 0x00, 0x00, 0x00, 0x00 };

    display.setBrightness(0x0f);    // All segments on
    display.setSegments(data);
    delay(TEST_DELAY);    // Selectively set different digits

    data[0] = display.encodeDigit(5);
    data[1] = display.encodeDigit(6);
    data[2] = display.encodeDigit(8);
    data[3] = display.encodeDigit(9);
    display.setSegments(data);
    delay(TEST_DELAY*4);

    display.clear();
    display.setSegments(data, 2, 2);
    delay(TEST_DELAY);

    display.clear();
    display.setSegments(data+2, 2, 1);
    delay(TEST_DELAY);

    display.clear();
    display.setSegments(data+1, 3, 1);
    delay(TEST_DELAY);

   // Show decimal numbers with/without leading zeros
    display.showNumberDec(0, false); // Expect: ___0
    delay(TEST_DELAY);
    display.showNumberDec(0, true);  // Expect: 0000
    delay(TEST_DELAY);
    display.showNumberDec(1, false); // Expect: ___1
    delay(TEST_DELAY);
    display.showNumberDec(1, true);  // Expect: 0001
    delay(TEST_DELAY);
    display.showNumberDec(301, false); // Expect: _301
    delay(TEST_DELAY);
    display.showNumberDec(301, true); // Expect: 0301
    delay(TEST_DELAY);
    display.clear();
    display.showNumberDec(14, false, 2, 1); // Expect: _14_
    delay(TEST_DELAY);
    display.clear();
    display.showNumberDec(4, true, 2, 2);  // Expect: 04__
    delay(TEST_DELAY);
    display.showNumberDec(-1, false);  // Expect: __-1
    delay(TEST_DELAY);
    display.showNumberDec(-12);        // Expect: _-12
    delay(TEST_DELAY);
    display.showNumberDec(-999);       // Expect: -999
    delay(TEST_DELAY);
    display.clear();
    display.showNumberDec(-5, false, 3, 0); // Expect: _-5_
    delay(TEST_DELAY);
    display.showNumberHexEx(0xf1af);        // Expect: f1Af
    delay(TEST_DELAY);
    display.showNumberHexEx(0x2c);          // Expect: __2C
    delay(TEST_DELAY);
    display.showNumberHexEx(0xd1, 0, true); // Expect: 00d1
    delay(TEST_DELAY);
    display.clear();
    display.showNumberHexEx(0xd1, 0, true, 2); // Expect: d1__
    delay(TEST_DELAY);
  
    // Done!
    display.setSegments(SEG_DONE);

    while(1);
}

Here we define SPI pins, CLK > Digital pin 2, and DIO > Digital pin 3.

Than we define SEG_DONE array, which is used to display word “done” on seven segment. It use enumerations for every letter, so for ‘d’ it is SEG_B | SEG_C | SEG_D | SEG_E | SEG_G and when you look on this image, you’ll see that when we light up these segments, we get letter ‘d’.

In setup() function we don’t need to set up anything.

In loop() function we use several built in functions. First is setSegments() which is used to set all segments, we pass one or three arguments to this function. First argument is uint8_t array with four values. These values are hexadecimal representation of decimal numbers. How this is done, we don’t need to know, only if we want to turn on/off all segments, to turn on we pass hexadecimal number 0xff, and to turn off - 0x00. If we want to pass specific digit, we use function encodeDigit(). This function has one argument and it is the digit that we want to encode to hexadecimal. We do this in data array, where we store for digits, 5, 6, 8 and 9. After this we use setSegments() function, first with one argument, then with three. When we use three arguments, fist is 4 value array, second is how many digits from that array will be displayed, starting from first (four digits, so this argument limits are 0 to 4), and third argument is position where first digit will be displayed (there are 4 segments, so positions are from 0 to 3).

In order to turn on those two dots in middle of 4 bit seven segment, in array, for second digit, we have to logically OR it with hexadecimal number 0x80, and to turn it of, we have to AND it with 0x7f. This is because first bit of hexadecimal number is used to turn this two dots segments, and this two dots will be turn on when we set this first bit of SECOND digit. We turned it on with this:

data[1] = display.encodeDigit(1) | 0x80;

So for example let’s explain this:

display.setSegments(data+2, 2, 1);

Here we have “data+2”, and what this does, is that only digits from second position in array “data” will be displayed, so in our case, only 6 and 8 will be displayed. Second argument “2” will display only two digits from “data” which is our 6 and 8 digits, and third argument “1” will set position on second segment (from left, first is 0, second 1, third 2 and fourth segment is 3).

After this we use showNumberDec() function which we can be used with 2 or 4 arguments. First argument is the 4 digit number, it can be also 3, or 2 or 1 digit number, and second argument is true/false. When it is false, 1 digit number will be displayed with right align and with no pre leading zeros, and when is true it will be diplayed with right align, but with 3 pre leading zeros. Third argument is number between 0 and 4, and it is used to point how many digits of number (in first argument) will be displayed. Fourth argument is used for starting position of number (in first argument), and its limits are from 0 to 3. If we has negative number, we can display it, like in this:

display.showNumberDec(-999);

And we can display negative numbers which are higher than -1000. So only 3, 2 and 1 digit negative numbers.

Next built in function is showNumberHexEx() which is the same as showNumberDec() but first argument is hexadecimal number, not decimal like in showNumberDec().

And last function is setBrightness() which has one argument and it is level of brightness, and its limits are from 0 to 7, eight different levels.

At the end of this sketch we display “done” on seven segment display, by using our SEG_DONE array which we defined at beginning of sketch:

display.setSegments(SEG_DONE);

Step 8: Future Projects

So with these displays we best can display numbers, and in special cases we can display letters. So these displays are best used for showing time, date, scores, numbers in general. We will create clocks and score displays in future, so hit follow button, if you want to stay up to date with our next Instructable posts.

This is all for this Instructable.

If you have any questions, feel free to ask.

You can reach us under info@az-delivery.com at any time and we will be glad to help you, or visit us under www.az-delivery.com

Share

    Recommendations

    • Pie Contest

      Pie Contest
    • Epilog X Contest

      Epilog X Contest
    • Trash to Treasure

      Trash to Treasure

    Discussions