Max7219 and a couple of wires. Ticker
Everyone has long been accustomed to the fact that everyone electronic device there is a screen through which it gives a person any useful information. The MP3 player shows the name of the track being played, the quadcopter remote displays flight telemetry, even washing machine displays the time until the end of the wash, and the smartphone generally hosts a whole desktop of a personal computer! Most likely, your next device will also need some small display 🙂 Let's try to make a simple electronic clock! And as a scoreboard we use a common and cheap character liquid crystal display 1602. Just like in the picture: In addition to 16x2, a 20x4 character display (four lines of 20 characters each) is considered quite popular, as well as a graphic display with a resolution of 128x64 pixels. Here they are in pictures:
1. Connecting the character LCD display 1602
The 1602 display has 16 pins. Usually they are numbered from left to right, if you look at it as in the picture. Sometimes the conclusions are signed, such as: DB0, DB1, EN, etc. And sometimes they just indicate the output number. In any case, the list of pins is always the same: 1 - "GND", ground (power minus); 2 - "Vcc", +5V supply; 3 - "VEE", contrast; 4 - "RS", register selection; 5 - "R / W", data transfer direction (write / read); 6 - "EN", synchronization; 7-14 - "DB0", "DB1", .., "DB7" - data bus; 15 - backlight anode ( +5V); 16 - backlight cathode (ground). Lines VEE, RS and four data lines DB4, DB5, DB6, DB7 are connected to the digital outputs of the controller. We will connect the “R / W” line to the “ground” of the controller (since we only need the function of writing to the display memory). We will not connect the backlight for now, I believe you can easily figure it out yourself 🙂 Schematic diagram of connecting the display to Arduino UnoLayout appearance
Just in case, also in the form of a plate:
LCD display 1602 | 1 | 2 | 4 | 6 | 11 | 12 | 13 | 14 | 15 | 16 |
Arduino Uno | GND | +5V | 4 | 5 | 6 | 7 | 8 | 9 | +5V | GND |
2. Program "Hello, world!"
To work with LCD displays of various sizes and types, the Arduino IDE editor has a special library liquid crystal. To include the library, we write the following expression as the first line of our program: #include3. Program the watch
Now that the display is working accurately, let's try to turn our simple device into a real electronic clock. Attention! To display the time, we need the "Time" library. If it is not installed yet, then you can download the archive from the link. Let's include it: #include- year() - will return the year to us;
- month() - month;
- day() - day;
- hour() - hour;
- minute() - returns the minute;
- second() - second.
Hello Guys. Today we will cut down the running line on the LED modules MAX7219 and Arduino. The task is very simple and does not require us to have great knowledge in the field of electronics and programming. To begin with, I propose to study a little theory on the device of the LED matrix, the principle of its connection and watch the video of the result, which we will strive for throughout the article.
The LED Matrix is a graphical indicator that can be used to display simple images, letters and numbers. I do not set the task to deal in detail with the device of matrix indicators, however, it is worth noting that, in fact, the matrix consists of 8x8 LEDs. In fact, everything comes down to dynamic indication. Based on this, it is clear that grouping several matrices together is not an easy task. For each new row or column of matrices, you need to add a new shift register along with wires and resistors, and in a good way also the ULN2003 chip.
Fortunately, engineers have long developed specialized microcircuits for controlling various kinds of indicators. In this article, we will look at the matrix module with the MAX7219 chip. As it will become clear later, working with such a module is a pleasure.
LED Matrix Module with MAX7219 Chip
The module is a board with a microcircuit, the strapping necessary for it and, in fact, a matrix indicator. Usually the indicator is not soldered into the board, but inserted into the connector. This is done so that a group of modules can first be fixed to some surface with screws, and then the matrices can be inserted into them.
The module has five pins on each side. On the one hand, data enters the module, on the other hand, data leaves the module and is transferred to the next one. This allows you to chain matrices y.
Input connector / Output connector:
- VCC, GND - power;
- DIN - data input;
- CS - module selection (chip select);
- CLK - clock pulse.
The module operates on a voltage of 5 volts.
Pixel output using the Max72xxPanel library
To control the MAX7219 chip, we will use the library Max72xxPanel. You can download it from the links at the end of the article.
Let's install the library and write a small code that will display only one point with coordinates x=3 and y=4. The dot will flash with a period of 600 milliseconds.
#include
#include #include int pinCS = 10; int numberOfHorizontalDisplays = 1; // number of matrices horizontally int numberOfVerticalDisplays = 1; // vertical number of matrices Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays); void setup() ( matrix.setIntensity(4); // brightness from 0 to 15 ) void loop() ( matrix.drawPixel(3, 4, HIGH); // light up the pixel at (3,4) matrix.write (); // draw all pixels to the matrix delay(300); matrix. drawPixel(3, 4, LOW); // blank out the pixel matrix. write(); delay(300); ) As mentioned earlier, matrix modules with the MAX7219 chip can be easily combined. It is for this purpose that at the beginning of the program we set the number of matrices horizontally and vertically. In this case, one matrix is used, so both of these parameters will be equal to 1.
It is important to note that after turning pixels on and off using the drawPixel, you need to call the function write. Without the write function, the pixels will not light up on the matrix!
Now let's write the code that will display the smiley on the matrix. We will encrypt the smile using an array of eight bytes. Each byte of the array will be responsible for the row of the matrix, and each bit in the byte for a point in the row.
#include
#include #include int pinCS = 10; int numberOfHorizontalDisplays = 1; // number of matrices horizontally int numberOfVerticalDisplays = 1; // vertical number of matrices Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays); const byte data = ( 0b00111100, 0b01000010, 0b10100101, 0b10000001, 0b10100101, 0b10011001, 0b01000010, 0b00111100 ); void setup() ( matrix.setIntensity(7); // brightness from 0 to 15 matrix.fillScreen(LOW); // clearing the matrix for (int y = 0; y< 8; y++) { for (int x = 0; x < 8; x++) { // зажигаем x-й пиксель в y-й строке matrix.drawPixel(x, y, data[y] & (1< Note. The Max72xxPanel library has a function setRotation, which specifies the orientation of the image on the matrix. For example, if we want to rotate the smiley by 90 degrees, we will need to immediately after calling the function setIntensity call setRotation with appropriate arguments:
matrix.setRotation(0, 1);
the first parameter is the index of the matrix, in our case it is equal to zero; the second parameter is the number of turns by 90 degrees.
Text output with Adafruit-GFX-Library
In a similar way, you can display any other symbol, for example, a letter, on the matrix. But in order to be able to display any letter of the English alphabet, we will need to define as many as 26 eight-byte arrays in the program! This is very dreary, and of course someone has already done this before us.
In the popular Adafruit-GFX-Library, in addition to functions for working with graphics and text, there is also a base of Latin letters in upper and lower case, as well as all punctuation marks and other service characters. The link to the library is at the end of the article.
You can display a symbol on a matrix using the function drawChar.
drawChar(x, y, character, color, background, size);
The first two parameters of the function are responsible for the coordinates of the upper left corner of the symbol. The third parameter is the symbol itself. The color of the symbol in our case will be equal to 1 or HIGH, since the matrix is two-color. The background is 0 or LOW. Let's make the last parameter "size" equal to 1.
Let's write a program that will display in turn all the letters of the phrase: "HELLO WORLD!"
#include
#include #include int pinCS = 10; int numberOfHorizontalDisplays = 1; int numberOfVerticalDisplays = 1; Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays); String tape = "HELLO WORLD"; int wait = 800; void setup() ( matrix.setIntensity(1); // brightness from 0 to 15 ) void loop() ( for (int i = 0 ; i< tape.length(); i++) { matrix.fillScreen(LOW); matrix.drawChar(0, 0, tape[i], HIGH, LOW, 1); matrix.write(); delay(wait); } } Note. The Adafruit_GFX library has many functions for working with graphics. For example, drawCircle(3, 3, 2, HIGH) will draw a circle with center (3,3) and radius 2. The last parameter is the color, but in the case of a monochrome matrix it is 1 or HIGH. The drawLine(0, 0, 3, 6, HIGH) function will draw a line between the points (0,0) and (3,6).
Running line on max7219
And so I hope we figured out the device and the principle of output to a single matrix. Now let's go directly to the running line.
What will be required?
To implement the idea, you need very few details:
- two LED modules, consisting of four matrices of 8 by 8 pixels;
- connecting wires;
- Arduino Nano board;
Scheme
On the printed circuit board of the LED module used, there are 4 matrices 8 by 8 pixels in size. Each LED board is controlled by a MAX7219 chip.
The MAX7219 is a controller for up to 64 LED displays, common cathode arrays, and discrete LEDs. For a more comfortable perception of information displayed on the LED display, it is recommended to install several modules. To do this, they are combined into series-connected groups, that is, the output of the first module (out) is connected to the input of the second module (in). My assembly consists of two modules (16 matrices), the length of which is quite enough for convenient reading of entire sentences. In this case, the assembly is connected to the Arduino in the same way as to a single module.
Running line programming.
The running line from Arduino and LED modules under control of MAX7219 is almost ready. It is time to move on to the final program part.
#include
#include #include int pinCS = 10; // Connect CS to pin 10, DIN to MOSI and CLK to SCK int numberOfHorizontalDisplays = 1; // Number of modules horizontally int numberOfVerticalDisplays = 8; // Number of modules vertically Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays); String tape = ""; int wait = 10; // Scroll speed in milliseconds int spacer = 1; // Gap between characters (number of dots) int width = 5 + spacer; // Character width /* Convert Russian font from UTF-8 to Windows-1251 */ String utf8rus(String source) ( int i,k; String target; unsigned char n; char m = ( "0", "\0" ); k = source.length(); i = 0; while (i< k) { n = source[i]; i++; if (n >= 0xC0) ( switch (n) ( case 0xD0: ( n = source[i]; i++; if (n == 0x81) ( n = 0xA8; break; ) if (n >= 0x90 && n<= 0xBF) n = n + 0x2F; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB7; break; } if (n >= 0x80 && n<= 0x8F) n = n + 0x6F; break; } } } m = n; target = target + String(m); } return target; } /* Код для работы с com-портом */ String Serial_Read() { unsigned char c; // переменная для чтения сериал порта String Serial_string = ""; // Формируемая из символов строка while (Serial.available() >0) ( // If there are characters in the serial port c = Serial.read(); // Read the character //Serial.print(c,HEX); Serial.print(" "); Serial.print(c); if (c == "\n") ( // If this is the end of the string return Serial_string; // Return the string ) if (c == 0xB8) c = c - 0x01; // Correction of character codes for the table???? since Russian characters in the table are shifted relative to the standard utf encoding by 1 character if (c >= 0xBF && c<= 0xFF) c = c - 0x01; Serial_string = Serial_string + String(char(c)); //Добавить символ в строку } return Serial_string; } void setup() { Serial.begin(9600); tape = utf8rus("сайт Amateur Radio WorkShop"); // Этот текст выводиться при включении или если в com-порт не пришла информация matrix.setIntensity(3); // Яркость от 0 до 15 matrix.setRotation(matrix.getRotation()+3); //1 - 90 2 - 180 3 - 270 } void loop() { if (Serial.available()){ tape=Serial_Read(); } for (int i = 0 ; i < width * tape.length() + matrix.width() - 1 - spacer; i++) { matrix.fillScreen(LOW); int letter = i / width; // Номер символа выводимого на матрицу int x = (matrix.width() - 1) - i % width; int y = (matrix.height() - 8) / 2; // Центрируем текст по вертикали while (x + width - spacer >= 0 && letter >= 0) ( if (letter< tape.length()) { matrix.drawChar(x, y, tape, HIGH, LOW,1); } letter--; x -= width; } matrix.write(); // Вывод сообщения на экран delay(wait); } } I don't see the point in writing code. He is well commented. However, there are some features worth mentioning.
Note. Important. The Adafruit_GFX standard library initially supports only English fonts, so the guys from Russia did their best and rewrote the library by adding Russian fonts and all sorts of goodies. All libraries and sketch are available on my GitHUB page.
A piece of code for working with the com-port is needed in order to quickly change the text of the message displayed on the LED module. However, we need it not only for this. In the future, through this function, we will connect ours and the running line on the Arduino.
To work with character graphic displays, we suggest using the LiquidCrystal library, which is included in the standard set of Arduino IDE and is designed to work on an 8-bit (4-bit) parallel interface. If your display is connected to the Arduino via the I2 bus, then you need to install the LiquidCrystal_I2C library (most of the functions of which repeat the functions of the first library).
Supported displays:
Display | Connection and initialization |
---|---|
LCD1602 - character display (16x02 characters), |
#include [ , 8 , 9 , 10 , 11 ]); void setup()( lcd.begin(16 , 2);} // Explanation:
|
with I2C interface (blue) |
#include #include LiquidCrystal_I2C lcd(0x27 or 0x3F, 16 , 2); void setup()( lcd.init(); } // Explanation: |
LCD1602 I2C - character display (16x02 characters), with I2C interface (green) |
#include #include LiquidCrystal_I2C lcd(0x27 or 0x3F, 16 , 2); void setup()( lcd.init(); } // Explanation: |
LCD2004 - character display (20x04 characters), with parallel interface (blue) |
#include LiquidCrystal lcd(2 , 3 , 4 , 5 , 6 , 7[ , 8 , 9 , 10 , 11 ]); void setup()( lcd.begin(20 , 4);} // Explanation: // If 8 data bus wires are used, then specify all of them |
LCD2004 I2C - character display (20x04 characters), with I2C interface (blue) |
#include #include LiquidCrystal_I2C lcd(0x27 or 0x3F, 20 , 4); void setup()( lcd.init(); } // Explanation: |
#1 Example
We display the inscription on the LCD1602 display connected via the I2C bus. To work with the LCD2004 display, you need to change line 3 to LiquidCrystal_I2C lcd(0x27,20,4);
#include
#2 Example
We display the inscription on the LCD1602 display connected via a 4-bit parallel bus. To work with the LCD2004 display, you need to change line 5 to lcd.begin(20, 4);
#include
#3 Example
We display the inscription "Russian language" on the LCD1602 display connected via the I2C bus:
#include
#4 Example
We display the time elapsed after the start on the LCD1602 display connected via the I2C bus:
#include
Functions common to LiquidCrystal and LiquidCrystal_I2C libraries:
- begin( cols, rows, ); – Display initialization with the number of columns, rows and character size.
- clear();– Clearing the display with the cursor set to 0,0 (Takes a lot of time!).
- home();– Set cursor to 0,0 (Takes a lot of time!).
- display();– Quick turn on of the display (without changing data in RAM).
- noDisplay();– Quick turn off of the display (without changing the data in the RAM).
- blink();– Activation of the blinking cursor (with a frequency of approx. 1 Hz).
- noBlink();– Switch off the blinking cursor.
- cursor();– Enable cursor underlining.
- noCursor();– Turn off cursor underlining.
- scrollDisplayLeft();– Scroll display to the left. Shift display coordinates one column to the left (without changing RAM).
- scrollDisplayRight();– Scroll display to the right. Shift display coordinates one column to the right (without changing RAM).
- leftToRight();– Specifies to further shift the position of the cursor, after the output of the next character, one column to the right.
- rightToLeft();– Indicates to further shift the position of the cursor, after the output of the next character, one column to the left.
- noAutoscroll();– Indicates that the text is further aligned to the left of the cursor position (as usual).
- autoscroll();– Indicates that the text will be further aligned to the right of the cursor position.
- createChar( num,array ); – Write a custom character to the display's CGRAM under the specified number.
- setCursor( col,row ); – Set the cursor to the position indicated by the column and line number.
- print( text ); – Display text, symbols or numbers on the display screen. The syntax is similar to the function of the same name in the Serial class.
Functions implemented only in the LiquidCrystal_I2C library:
- init();– Display initialization. Must be the first command of the LiquidCrystal_I2C library after object creation. In fact, this function is also in the LiquidCrystal library, but in that library it is called automatically (by default) when an object is created.
- backlight();– Turn on the backlight of the display.
- noBacklight();– Turn off the backlight of the display.
- setBacklight( flag ); – Backlight control (true - enable / false - disable), used instead of the noBacklight and backlight functions.
Connection:
// For the I2C bus: |
Parameter:
|
// For a 4-wire parallel bus: #include liquid crystal lcd( RS , E , D4 , D5 , D6 , D7 ); void setup()( lcd.begin( col , row ); } |
Parameter:
|
// For an 8-wire parallel bus: #include liquid crystal lcd( RS , E , D0 , D1 , D2 , D3 , D4 , D5 , D6 , D7 ); void setup()( lcd.begin( col , row ); } |
|
begin( col ,
row ,
);
Display initialization with screen sizes and characters. |
Parameter:
|
Display control functions:
display(); Turns on the display after it has been turned off by the noDisplay function. |
Note: The function is executed quickly and without changes to the display RAM. |
noDisplay(); Turns off the display. The data on the display will not be displayed until the display function is called, but it will not be erased from the RAM memory, and after the display function is called, it will be displayed again. |
Note: The function is executed quickly and without changes to the display RAM. |
scrollDisplayLeft(); Shifts the display coordinates one column to the left. |
|
scrollDisplayRight(); Shifts the display coordinates one column to the right. The constant call of this function will create the effect of a running line. The coordinates are shifted both for the information on the display and for the one that will be displayed after. |
Note: The function is executed without changing the display RAM. If you call the function 40 times in a row, the coordinate will return to the original point |
clear(); Clearing the display with the cursor set to 0,0. The information on the display will be permanently erased. |
Note: Takes a long time. |
backlight(); Turn on the backlight of the display. |
|
noBacklight(); Turn off the display backlight. |
Note: The function is implemented only in the LiquidCrystal_I2C library. |
setBacklight( flag );
Backlight control (instead of noBacklight and backlight functions). |
Parameter:
|
Cursor control functions:
setCursor( col ,
row );
Sets the cursor to the specified position. |
Parameter:
|
home(); Set cursor to position 0,0. Works like setCursor(0,0); |
Note: Takes a long time. |
blink(); Turn on the blinking cursor. |
Note: The cursor occupies the entire character field and flashes at a frequency of about 1 Hz, in the position where it was previously set. |
noBlink(); Turn off the blinking cursor. |
Note: The cursor becomes invisible, but its position is preserved. |
cursor(); Enable cursor underlining. |
Note: The cursor changes to an underscore character and is positioned where it was previously set. |
noCursor(); Turn off cursor underlining. |
Note: The cursor becomes invisible, but its position is preserved. |
Direction and alignment functions:
leftToRight(); Specifies that after each new character, the cursor position should move one column to the right. |
Note: If the text "abc" is displayed, the display will show "abc" and the text will be to the right of the initial cursor position. (Normally) |
rightToLeft(); Specifies that after each new character, the cursor position should move one column to the left. |
Note: If the text "abc" is displayed, the display will show "cba" and the text will be to the left of the initial cursor position. (Writing from right to left) |
noAutoscroll(); Specifies that in the future, the text should be left-aligned from the initial cursor position. |
Note: if you set the cursor to position 10.0 and display the text, then the first character of the displayed text will be in this position. (Normally) |
autoscroll(); Specifies that in the future, the text should be right-aligned from the initial cursor position. |
Note: if you set the cursor to position 10.0 and display the text, then the cursor will be located at this position. (The display coordinates will be shifted to the left, as if you called the scrollDisplayLeft function as many times as there are letters in the displayed text) |
Text and character input functions:
createChar(num,array); Write a custom character to the display's CGRAM at the specified number. If you want to print the text (using the print function) which should contain the character you set, specify the slash and the number under which this character was written: print("C\1MBO\2"). |
Parameter:
|
print(text); Display text, symbols or numbers on the display screen. |
Parameter:
|
Running line in LCD on HD44780.
The search for a "ready-made solution" for the running line in C did not give any result. So I had to do it myself.
This "piece" of code allows you to display a ticker (from right to left), anywhere and using any number of character spaces, in LCD indicators with an HD44780 controller or similar.
The first thing to note is that the C language does not allow you to work with strings "directly". That is, it is not possible to copy a character from one string to another using the assignment operator ( = ) ... for this you need to use a special function strncpy(). Generally speaking, several functions are used to work with strings in C. In Self-Tormentors, a separate chapter is devoted to the use of these functions. In Help "e on CV_AVR, the description of functions for working with strings is in the section "String Functions". The prototypes of these functions are in the file string.h.
"...initial string..." - string characters from which you want to display in the "running" line;
"...displayed characters..." - actually "creeping line".
The following algorithm was chosen to organize the running line:
1. Displayed characters are shifted from right to left. The extreme left is "lost".
2. After the shift, the next character from the source string is copied into the rightmost character.
3. When the end of the source string is reached, the first character of the source string becomes next.
For character shift - for the cell being shifted, the character code is read from the HD44780 on-screen RAM (DDRAM) and written to the left-hand RAM cell.
According to the DataSheet on the HD44780, the left character of the top row has a DDRAM address of 0x00 and the left character of the bottom row is 0x40. It must be remembered that in order to refer specifically to the screen RAM (and not to the character generator RAM), it is necessary that the RS bit be equal to 1 (RS is the high bit in the address byte, see DataSheet).
As a result, we get that in order to "refer" to the second character from the left of the top line, you need to "work" with the address 0x01 | 0x80 = 0x81.
The functions of writing and reading the "internal content" of the HD44780 are in the library (prototypes in lcd.h).... therefore.. the actual program:
/* for CV_AVR In this example, the running line is displayed in bits 8 (0xC7) through 16 of the bottom line of a 16-bit indicator. . ...... #include unsigned char n_sim=1,m_end=43; //43 - line length in the example beg_string()( // ticker shift if(beg_str)( // write the next character to the rightmost position lcd_gotoxy(15,1); |
Glossary: n_sim - pointer to the position of the current character in the source string; m_end - total number of characters in the source string; beg_str- shift enable bit. With it, you can adjust the speed of "running"; ish_str - source string. |
Most likely, each of the existing C compilers has library functions for working with the HD44780. Therefore, it will not be difficult to "remake" the program for "your" compiler.
I "cook" the source string using the well-known utility "HD44780.exe". When using it, the comments indicate the length of the line: "/* Maximum length of a line: 43 byte */"