17. Chapter LED Matrix
In the previous section, we have used 74HC595 to control 8 LEDs of the LED bar graph. Now let’s use 74HC595 to control LED matrix.
17.1. Component List
Control board x1
|
USB cable x1
|
Digital Tube x1
|
Freenove Projects Board
|
||
17.2. Component Knowledge
17.2.1. LED matrix
An LED Matrix is a rectangular display module that consists of a uniform grid of LEDs. The following is an 8X8 monochrome (one color) LED Matrix containing 64 LEDs (8 rows by 8 columns).
In order to facilitate the operation and reduce the number of ports required to drive this component, the Positive Poles of the LEDs in each row and Negative Poles of the LEDs in each column are respectively connected together inside the LED Matrix module, which is called a Common Anode. There is another arrangement type. Negative Poles of the LEDs in each row and the Positive Poles of the LEDs in each column are respectively connected together, which is called a Common Cathode.
The LED Matrix that we use in this project is a Common Anode LED Matrix.
Here is how a Common Anode LED Matrix works. First, choose 16 ports on RPI board to connect to the 16 ports of LED Matrix. Configure one port in columns for low level, which makes that column the selected port. Then configure the eight port in the row to display content in the selected column. Add a delay value and then select the next column that outputs the corresponding content. This kind of operation by column is called Scan. If you want to display the following image of a smiling face, you can display it in 8 columns, and each column is represented by one byte.
Column |
Binary |
Hexadecimal |
|---|---|---|
1 |
0001 1100 |
0x1c |
2 |
0010 0010 |
0x22 |
3 |
0101 0001 |
0x51 |
4 |
0100 0101 |
0x45 |
5 |
0100 0101 |
0x45 |
6 |
0101 0001 |
0x51 |
7 |
0010 0010 |
0x22 |
8 |
0001 1100 |
0x1c |
Scanning rows is another option to display on an LED Matrix (dot matrix grid). Whether scanning by row or column, 16 GPIO is required. In order to save GPIO ports of control board, two 74HC595 IC Chips are used in the circuit.
17.3. Circuit
Use pin 11, 12, 13 on control board to control the 74HC595. And connect 74HC595 to the 8 anode pins of LED Matrix, in the meanwhile, connect 8 digitals port on control board to the 8 cathode pins of LED Matrix.
Schematic diagram
|
Hardware connection
|
Hardware connection
|
|
17.4. Sketch
17.4.1. LED_Matrix
Now write the code to drive LED dot matrix to display static and dynamic images. In fact, dynamic images are formed by continuous static images.
1/*
2 LED_Matrix
3
4 modified 2021/7/1
5 by http://www.freenove.com
6*/
7
8int latchPin = 12; // Pin connected to ST_CP of 74HC595(Pin12)
9int clockPin = 13; // Pin connected to SH_CP of 74HC595(Pin11)
10int dataPin = 11; // Pin connected to DS of 74HC595(Pin14)
11
12// Define the pattern data for a smiling face
13const int smilingFace[] = {
14 0x1C, 0x22, 0x51, 0x45, 0x45, 0x51, 0x22, 0x1C
15};
16
17// Define the data of numbers and letters, and save them in flash area
18const int data[] PROGMEM = {
19 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // " "
20 0x00, 0x00, 0x21, 0x7F, 0x01, 0x00, 0x00, 0x00, // "1"
21 0x00, 0x00, 0x23, 0x45, 0x49, 0x31, 0x00, 0x00, // "2"
22 0x00, 0x00, 0x22, 0x49, 0x49, 0x36, 0x00, 0x00, // "3"
23 0x00, 0x00, 0x0E, 0x32, 0x7F, 0x02, 0x00, 0x00, // "4"
24 0x00, 0x00, 0x79, 0x49, 0x49, 0x46, 0x00, 0x00, // "5"
25 0x00, 0x00, 0x3E, 0x49, 0x49, 0x26, 0x00, 0x00, // "6"
26 0x00, 0x00, 0x60, 0x47, 0x48, 0x70, 0x00, 0x00, // "7"
27 0x00, 0x00, 0x36, 0x49, 0x49, 0x36, 0x00, 0x00, // "8"
28 0x00, 0x00, 0x32, 0x49, 0x49, 0x3E, 0x00, 0x00, // "9"
29 0x00, 0x00, 0x3E, 0x41, 0x41, 0x3E, 0x00, 0x00, // "0"
30 0x00, 0x00, 0x3F, 0x44, 0x44, 0x3F, 0x00, 0x00, // "A"
31 0x00, 0x00, 0x7F, 0x49, 0x49, 0x36, 0x00, 0x00, // "B"
32 0x00, 0x00, 0x3E, 0x41, 0x41, 0x22, 0x00, 0x00, // "C"
33 0x00, 0x00, 0x7F, 0x41, 0x41, 0x3E, 0x00, 0x00, // "D"
34 0x00, 0x00, 0x7F, 0x49, 0x49, 0x41, 0x00, 0x00, // "E"
35 0x00, 0x00, 0x7F, 0x48, 0x48, 0x40, 0x00, 0x00 // "F"
36};
37
38void setup() {
39 // set pins to output
40 pinMode(latchPin, OUTPUT);
41 pinMode(clockPin, OUTPUT);
42 pinMode(dataPin, OUTPUT);
43}
44
45void loop() {
46 // Define a one-byte variable (8 bits) which is used to represent the selected state of 8 column.
47 int cols;
48 // Display the static smiling pattern
49 for (int j = 0; j < 500; j++ ) { // repeat 500 times
50 cols = 0x01; // Assign 0x01(binary 00000001) to the variable, which represents the first column is selected.
51 for (int i = 0; i < 8; i++) { // display 8 column data by scaning
52 matrix(smilingFace[i],cols);
53 delay(1); // display them for a period of time
54 cols <<= 1; // shift"cols" 1 bit left to select the next column
55 }
56 }
57 // Display the dynamic patterns of numbers and letters
58 for (int i = 0; i < 128; i++) { // "space,0-9,A-F"16 letters ,each letter hold 8 columns, total 136 columns. Firstly, display space ,then we need shift 128 times(136-8)
59 for (int k = 0; k < 10; k++) { // repeat image of each frame 10 times.
60 cols = 0x01; // Assign binary 00000001. Means the first column is selected.
61 for (int j = i; j < 8 + i; j++) { // display image of each frame
62 matrix(pgm_read_word_near(data + j),cols);
63 delay(1); // display them for a period of time
64 cols <<= 1; // shift"cols" 1 bit left to select the next column
65 }
66 }
67 }
68}
69
70void matrix(byte row_value,byte col_value) {
71 digitalWrite(latchPin, LOW);
72 shiftOut(dataPin, clockPin, LSBFIRST, row_value);
73 shiftOut(dataPin, clockPin, MSBFIRST, ~col_value);
74 digitalWrite(latchPin, HIGH);
75}
Use another array to define 8-column data of a smiling face.
1const int smilingFace[] = {
2 0x1C, 0x22, 0x51, 0x45, 0x45, 0x51, 0x22, 0x1C
3};
Use another array to define some numbers and letters, and every eight elements of the array represent a dot matrix pattern data of a number or a letter.
1const int data[] PROGMEM = {
2 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // " "
3 0x00, 0x00, 0x21, 0x7F, 0x01, 0x00, 0x00, 0x00, // "1"
4 0x00, 0x00, 0x23, 0x45, 0x49, 0x31, 0x00, 0x00, // "2"
5 0x00, 0x00, 0x22, 0x49, 0x49, 0x36, 0x00, 0x00, // "3"
6 0x00, 0x00, 0x0E, 0x32, 0x7F, 0x02, 0x00, 0x00, // "4"
7 0x00, 0x00, 0x79, 0x49, 0x49, 0x46, 0x00, 0x00, // "5"
8 0x00, 0x00, 0x3E, 0x49, 0x49, 0x26, 0x00, 0x00, // "6"
9 0x00, 0x00, 0x60, 0x47, 0x48, 0x70, 0x00, 0x00, // "7"
10 0x00, 0x00, 0x36, 0x49, 0x49, 0x36, 0x00, 0x00, // "8"
11 0x00, 0x00, 0x32, 0x49, 0x49, 0x3E, 0x00, 0x00, // "9"
12 0x00, 0x00, 0x3E, 0x41, 0x41, 0x3E, 0x00, 0x00, // "0"
13 0x00, 0x00, 0x3F, 0x44, 0x44, 0x3F, 0x00, 0x00, // "A"
14 0x00, 0x00, 0x7F, 0x49, 0x49, 0x36, 0x00, 0x00, // "B"
15 0x00, 0x00, 0x3E, 0x41, 0x41, 0x22, 0x00, 0x00, // "C"
16 0x00, 0x00, 0x7F, 0x41, 0x41, 0x3E, 0x00, 0x00, // "D"
17 0x00, 0x00, 0x7F, 0x49, 0x49, 0x41, 0x00, 0x00, // "E"
18 0x00, 0x00, 0x7F, 0x48, 0x48, 0x40, 0x00, 0x00 // "F"
19};
- PROGMEM keyword
Microprocessors generally have two storage areas, namely ROM and RAM. ROM is used to store code. And these stored data will not change with the execution of code until the code are uploaded. RAM is used to store data, for example, the variables we defined are stored here. The stored data will change in real time with the execution of the code. Generally, capacity of RAM is small. So we can use PROGMEM keyword to save the data that don’t change in ROM.
Define a function to send the data of the LEDs that need to be lit for each row first, and then send the data of those for each column. Details are as follows.
1void matrix(byte row_value,byte col_value) {
2 digitalWrite(latchPin, LOW);
3 shiftOut(dataPin, clockPin, LSBFIRST, row_value);
4 shiftOut(dataPin, clockPin, MSBFIRST, ~col_value);
5 digitalWrite(latchPin, HIGH);
6}
- Bitwise logical operator
There are many bitwise logical operators such as and (&), or (|), xor (^), negate (~). The result of exclusive or (^) is true only when its arguments differ (one is true, the other is false).
&, | and ^ is used to operate the corresponding bit of two numbers. For example:
byte a = 1 & 2;
“a” will be assigned to 0. The calculation procedure is as follows:
1(00000001)
& 2(00000010)
--------------------------
0(00000000)
Negate (~) is used to negate a number, for example:
byte a = ~15;
“a” will be assigned to 240. The calculation procedure is as follows:
~ 15(00001111)
--------------------------
240(11110000)
In the loop () function, firstly, show the static smile pattern. Select one of the 8 columns circularly in turn to display each result. Repeat the process for 500 times, and then we can see a static smile pattern.
1for (int j = 0; j < 500; j++ ) { // repeat 500 times
2 cols = 0x01; // Assign 0x01(binary 00000001) to the variable, which represents the first column is selected.
3 for (int i = 0; i < 8; i++) { // display 8 column data by scaning
4 matrix(smilingFace[i],cols);
5 delay(1); // display them for a period of time
6 cols <<= 1; // shift"cols" 1 bit left to select the next column
7 }
8}
Then display the dynamic pattern of numbers and letters. We have defined space, 0-9, A-F, a total of 16 characters (136 columns) in an array, among which 8 adjacent rows of data form one frame. Shift one column once. There are 128 frames of image from the first frame (1-8) to the last frame (128-136 columns). Each frame image is displayed 10 times, then display the next frame. Repeat the process above, then we can see the pattern of scrolling numbers and letters.
1for (int i = 0; i < 128; i++) { // "space,0-9,A-F"16 letters ,each letter hold 8 columns, total 136 columns. Firstly, display space ,then we need shift 128 times(136-8)
2 for (int k = 0; k < 10; k++) { // repeat image of each frame 10 times.
3 cols = 0x01; // Assign binary 00000001. Means the first column is selected.
4 for (int j = i; j < 8 + i; j++) { // display image of each frame
5 matrix(pgm_read_word_near(data + j),cols);
6 delay(1); // display them for a period of time
7 cols <<= 1; // shift"cols" 1 bit left to select the next column
8 }
9 }
10}
Verify and upload the code, and LED Matrix begins to display the static smile pattern. A few seconds later, LED Matrix will display the scrolling number 0-9 and the letter A-F.






