Dot matrix LEDs are standard electronic components for electronics kits. Using these components, you can control a large number of LEDs with just a small number of pins. We will introduce dynamic lighting control, which is a standard control method for dot matrix LEDs.
If you take a close look at the electric bulletin boards on street corners and stations, you will notice many LEDs arranged in a grid are individually lit to display characters and images.
If you’ve ever worked with a microcontroller board like an Arduino, you might be wondering how it’s possible to control hundreds or thousands of LEDs using a microcontroller with only a few pins?
We will explain dynamic lighting control, which enables you to control a large number of LEDs with just a small number of pins using dot matrix LEDs, standard electronic components in electronics kits.
Dynamic lighting control is a lighting method that switches LEDs on and off at high speeds to make it appear as if multiple LEDs are lit at the same time. For example, if you switch the lighting of multiple LEDs hundreds of times per second, it will appear to the human eye as if the LEDs are lit at the same time. Using this kind of lighting control, multiple LEDs can be controlled with just a small number of pins on a microcomputer board.
Dot matrix LEDs, in which multiple LEDs are wired in a matrix array, are often used for this kind of dynamic lighting control. By combining this with dynamic lighting control, various LED lighting patterns can be created utilizing less wiring.
We will explain how to use a dot matrix LED equipped with a total of 64 LEDs in 8 columns x 8 rows, which are often used in electronics kits. There are only 16 wires for this dot matrix LED, including the number of columns and rows.
Internal wiring diagram of the matrix LED (OSL641501-AG) used here. It has 64 LEDs, but only 16 wires.
Dot matrix LEDs do not have a current limiting resistor. While looking at the data sheet, connect eight resistors to either the anode side or the cathode side.
The resistance value is determined by the voltage (5V) of the Arduino digital input / output pin, the forward voltage drop (VF) unique to the LED, and the brightness (current) of the LED. However, please note that Arduinos have a limit on the current value that can be drawn from the pin. It doesn’t matter whether the resistor is connected to the anode side or the cathode side.
A circuit diagram connecting an Arduino Uno and dot matrix LED. It looks like a complicated circuit because there are so many wires, but the circuit does not necessarily have to use this wiring pattern. If you know the anode side and the cathode side of the LED, then the difference in wiring can be absorbed by the sketching.
When using an Arduino Uno, wire away from the digital 0,1 (TX, RX), used for writing sketches, and digital 13 to which the built-in LED is connected. Although there will be shortages of digital terminals, use analog A0 to A5, respectively, as digital D14 to D19, wiring 16 pins.
After wiring the dot matrix LED, let’s write a sketch. First, turn on all the LEDs of the dot matrix LED. The method used is to turn on all the LEDs in one row, then switch columns quickly to make it look like all the LEDs are turned on.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// Matrix LED pin permutation int anode[8] = { 15, 4, 5, 11, 7, 12, 17, 18 }; int cathode[8] = { 10, 16, 9, 14, 2, 8, 3, 6 }; void setup() { //Pin initialization for ( int i = 0; i < 8; ++i ) { pinMode( anode[i], OUTPUT ); digitalWrite( anode[i], LOW ); } for ( int i = 0; i < 8; ++i ) { pinMode( cathode[i], OUTPUT ); digitalWrite( cathode[i], HIGH ); } } void loop() { for ( int i = 0; i < 8; ++i ) { digitalWrite( cathode[i], LOW ); for ( int j = 0; j < 8; ++j ) { digitalWrite( anode[j], HIGH ); } //delay(100); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], LOW ); } digitalWrite( cathode[i], HIGH ); } } |
If you use an array and a “for statement” for the dot matrix LED, it will be a simple sketch.
We will briefly explain the flow of the program.
In the first anode array and cathode array, enter the wiring information of the matrix LED pin and the Arduino pin, respectively. In the anode array, enter the pins of the matrix LED column in order. In the cathode array, enter the pins in the row of the matrix LEDs in order. Make sure the Arduino pins to be connected are stored in the array in the order of the matrix number of the matrix LED.
In the following setup function, in order to define the state of the pins used in the Arduino, each pin is initialized one by one using the anode / cathode array and the “for statement.”
The lighting state of the matrix LED is controlled by the loop function. The lighting of the matrix LED will fit neatly if you use a double “for statement.”
In the outer “for statement,” the cathode side of the lit line is set to LOW so that the current flows through the entire line. Afterwards, specify the columns you want to light in order by the inner “for statement.” We will turn on the LEDs in every row this time, so set all of the anode sides to HIGH. When this is done, the entire line will light up. By repeating this operation quickly for all rows, it seems like all LEDs are lit at the same time.
If you enable the delay function, which is commented out on the 29th line of code, you can see how the display is switched on line by line. In this way, dynamic lighting is a method that quickly switches the LED ON / OFF to make it appear as if multiple LEDs are lit at the same time.
At this point, you are close to understanding how dot-matrix LEDs are controlled. However, it’s easy to simply turn on the LEDs, so let’s switch the lighting state of the LEDs. In this example, let’s display the letter “D” from DEVICE PLUS.
Since only the data type 0 and 1 (boolean type) are required for LED ON / OFF control, the lighting data for the letter “D” is defined using an array, as shown below. Let’s define the array in the manner of a dot picture, assuming that an LED that’s lit up is “1” and an LED that is turned off is “0”. Since we are using an 8 x 8 dot matrix, the array is also 8 x 8.
1 2 3 4 5 6 7 8 9 10 |
boolean matrix[8][8] = { { 0, 1, 1, 1, 1, 0, 0, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 1, 1, 0, 0, 0 } }; |
Let’s change the sketch so that the contents of the array are reflected in the display. Change the digitalWrite function in the double “for statement” to refer to the defined array.
1 2 3 |
digitalWrite( anode[j], HIGH ); ↓ digitalWrite( anode[j], matrix[i][j] ); |
A sketch that reflects these changes is shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// Matrix LED pin permutation int anode[8] = { 15, 4, 5, 11, 7, 12, 17, 18 }; int cathode[8] = { 10, 16, 9, 14, 2, 8, 3, 6 }; void setup() { //Pin initialization for ( int i = 0; i < 8; ++i ) { pinMode( anode[i], OUTPUT ); digitalWrite( anode[i], LOW ); } for ( int i = 0; i < 8; ++i ) { pinMode( cathode[i], OUTPUT ); digitalWrite( cathode[i], HIGH ); } } boolean matrix[8][8] = { { 0, 1, 1, 1, 1, 0, 0, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 0, 1, 1, 0 }, { 0, 1, 1, 0, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 1, 1, 0, 0, 0 } }; void loop() { // Character data output processing for ( int i = 0; i < 8; i++ ) { digitalWrite( cathode[i], LOW ); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], matrix[i][j] ); } //delay(50); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], LOW ); } digitalWrite( cathode[i], HIGH ); } } |
When you execute the sketch, the LED should be lit according to the contents of the array. As with the sketch above, if you enable the commented out delay function, you can see how the LEDs are switched on while tracing the shape of the D line by line.
The processing sketch is simple, reading “0” and “1” in the array respectively, and controls the lighting state of the LED in the corresponding location. By reading the array in this way, you can freely control the lighting state.
At this point, you should understand the dynamic lighting control of dot matrix LEDs.
Now that you can freely turn on the dot matrix LEDs, you may wish to move it like an electric bulletin board. Of course, if you use the dot matrix LED and Arduino, you can switch the display state while it’s lit and scroll it like an electric bulletin board, but from here on, you will need the sketching techniques.
For example, how would you scroll characters by 1 second while performing dynamic lighting control? If you use the delay function that is often used for L-blinking, the microcontroller will stop. The dynamic lighting control also stops, and the characters will not be displayed.
In order to control LEDs continuously, it is necessary to have an idea about how to process it without stopping the movement of the microcontroller at all. Furthermore, in order to display many characters, as with an electric bulletin board, a significant amount of array data is required, and it’s necessary to consider how to extract the part to be displayed from it.
Therefore, so as not to stop the microcontroller, we will add a process to scroll the characters while measuring the elapsed time using the millis function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
if (tm + SCROLL_TIME <= millis()) { for (int i = 0; i < 8 ; i++) { for (int j = 0; j < 8 ; j++) { matrix[i][j] = matrix_data[i][j + slide]; } } //Slide the storage location and return to the beginning when you reach the end if (slide < 49) { ++slide; } else { slide = 0; } //Remeasure the elapsed time tm = millis(); } |
The array of the character data also becomes larger if you want to scroll it. We will create array data that can scroll the characters “DEVICE PLUS”.
1 2 3 4 5 6 7 8 9 10 |
boolean matrix_data[8][57] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 } }; |
The sketch with the added function for scrolling is as follows. The flow of the whole sketch is to extract the array of the part to be displayed from the array that stores the character data, and scroll it at the specified time. Since Arduino devices run continuously, they always perform dynamic lighting control.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
// Matrix LED pin permutation int anode[8] = { 15, 4, 5, 11, 7, 12, 17, 18 }; int cathode[8] = { 10, 16, 9, 14, 2, 8, 3, 6 }; //Character data boolean matrix_data[8][57] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0 } }; boolean matrix[8][8] = {}; //Array variable for output int slide = 0; unsigned long tm = 0; //Scroll time #define SCROLL_TIME 90 // milliseconds void setup() { //Pin initialization for ( int i = 0; i < 8; ++i ) { pinMode( anode[i], OUTPUT ); digitalWrite( anode[i], LOW ); } for ( int i = 0; i < 8; ++i ) { pinMode( cathode[i], OUTPUT ); digitalWrite( cathode[i], HIGH ); } //Initialize the output array for (int i = 0; i < 8 ; ++i) { for (int j = 0; j < 8 ; ++j) { matrix[i][j] = 0; } } //Store initial elapsed time tm = millis(); } void loop() { //Store the character data in the output array for each elapsed time if (tm + SCROLL_TIME <= millis()) { for (int i = 0; i < 8 ; i++) { for (int j = 0; j < 8 ; j++) { matrix[i][j] = matrix_data[i][j + slide]; } } //Slide the storage location and return to the beginning when you reach the end if (slide < 49) { ++slide; } else { slide = 0; } //Remeasure the elapsed time tm = millis(); } // Character data output processing for ( int i = 0; i < 8; i++ ) { digitalWrite( cathode[i], LOW ); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], matrix[i][j] ); } //delay(50); for ( int j = 0; j < 8; j++ ) { digitalWrite( anode[j], LOW ); } digitalWrite( cathode[i], HIGH ); } } |
You can adjust the scroll speed of this sketch by changing the number for SCROLL_TIME on the 23rd line. The video is a little hard to see because it reflects light, but you can see the shape of the characters even if you increase the speed up to 70ms.
By directly controlling the dot matrix LED using an Arduino, you are limited to moving the 8 x 8 dot matrix LED. To control a larger dot-matrix LED, communication control using a dedicated IC and external memory are required.
Dot-matrix LEDs, which look simple at first glance, are quite complicated electronic components. To use them successfully, electronic components and microcontroller control technology are required.
Dot matrix LEDs may be an ideal electronic component for learning, as the technology that handles dot matrices can also be applied to the use of other electronic components.
It’s an easy-to-obtain electronic component both for electronics kits and learning purposes, so if you buy an Arduino, it’s a good idea to buy one together with it.