In the previous tutorial, we learned how to interface a seven-segment display with Arduino. A seven-segment display is comprised of a unit of eight LEDs and seven of which are bar-shape and one is a dot. These display units are ideal for displaying numbers or letters.
For example, they’re often used as a display unit in cost-sensitive applications where an embedded system may only require numeric information, such as a digital clock or a token display board. This option is typically more cost-effective than full LCD displays.
In the previous tutorial, we discovered that interfacing a single, seven-segment display requires eight or nine connections. The seven-segment unit can only display a single digit. If more digits are required, then more segments are necessary.
If each seven-segment is interfaced independently with the controller (such as Arduino), several digital I/O channels are needed. Generally, the number of digital I/O pins on any controller are limited. However, many seven-segment displays can be interfaced with a controller using the multiplexing technique.
By using this technique, the number of pins required to interface multiple seven-segments with a controller can be greatly reduced. There are also several seven-segment display driver ICs that can perform the multiplexing technique and use standard serial interfaces to communicate with a controller.
MAX7219 is one such LED driver IC that allows multiplexing of up to eight of the seven-segment displays. It uses an SPI interface to communicate with the controller. This way only three pins of the controller are engaged to control eight of the seven-segment displays. Otherwise, direct multiplexing would require at least 16 digital I/O pins.
There are two types of seven-segment displays: common-cathode and common-anode.
When a single common-cathode, seven-segment is interfaced with a controller, the common-cathode terminal is usually hard-wired to ground. Similarly, when a single common-anode, seven-segment is interfaced with a controller, the common-anode terminal is typically hard-wired to VCC. This way the seven-segment is always active and ready to turn its LEDs on/off according to the logical signal at its data pins (a, b, c, d, e, f, g, and dp).
With the multiplexing technique, multiple seven-segments are interfaced with a controller and the respective data lines of all the segments are shorted. As such, when the controller transfers logic for turning the segments to on/off, this is passed to all of the seven-segments at the same time. However, only one display unit is activated at a time.
Also, each of the seven-segments multiplexed with a controller should be of the same type (i.e. either all should be common-anode or common-cathode).
The common-anode or common-cathode terminals are not hard-wired to the VCC or the ground. Rather, they’re interfaced to the microcontroller pins. The common-anode or common-cathode terminals of the seven-segments serve as select lines. One of the segments can be selected by passing the relevant logic to the common-cathode/common-anode terminals.
If common-anode, seven-segments are multiplexed:
- One of the seven-segments can be selected by passing a HIGH logic to the common-anode terminal that’s to remain activated at a time.
- All of the other seven-segments can be kept inactive by maintaining a LOW logic to their common-anode terminals.
- The desired digit can be displayed on the selected seven-segment by turning on the appropriate LED segments simply by passing a LOW logic to the respective data lines.
Similarly, if the common-cathode, seven-segments are multiplexed:
- One of the seven-segments can be selected by passing a LOW logic to the common-cathode terminal that’s to remain activated at a time.
- All of the other seven-segments can be kept inactive by maintaining a HIGH logic to their common-cathode terminals.
- The selected digit can be displayed on the selected seven-segment by turning on the appropriate LED segments by passing a HIGH logic to the respective data lines.
The multiplexed seven-segments can be seen as a matrix of LEDs that are grouped by seven-segment display units — each unit is activated, one after the other. The LEDs of the unit are controlled by passing the appropriate logic.
Only one seven-segment is activated at a time and the desired digit is displayed on it. Then, the other seven-segment is activated and the selected digit is displayed on it. This continues for all of the multiplexed seven-segments.
If 25 frames (or more) are displayed in one second, the human eye views the frames as a continuous display. So, the multiplexed seven-segments will appear as if they are displaying the digits simultaneously.
LED driver ICs
Even when seven-segments are directly multiplexed to the digital I/O pins of a controller, they engage a lot of pins. Interfacing each seven-segment requires engaging an additional pin on the controller. This is apart from the eight pins already engaged for the data lines. If the eight, seven-segments are to be interfaced with the controller, 16 digital I/O pins will be required (eight for the data lines and eight for the selection lines).
However, not all microcontrollers have this many GPIOs. And, even if they do, engaging this many pins for interfacing a display system is typically not advisable. This is because other components may also require interfacing with the controller.
The solution to this problem: LED driver ICs. These ICs perform multiplexing on their own channels/pins, which means the seven-segments or LED matrices can be controlled via standard serial interfaces (such as an SPI or I2C). LED driver ICs only require obtaining data from the controller, using either the I2C interface or a three-wire SPI.
The I2C allows half-duplex data communication over two wires. The means an LED display driver IC using the I2C interface engages only two pins of a microcontroller to control several of the seven-segment displays or the LED matrix.
The three-wire SPI allows unidirectional data communication over three wires. An LED display driver IC using a three-wire SPI engages only three pins of a microcontroller to control several of the seven-segment displays or the LED matrix.
The MAX7219 8-digit LED driver
MAX7219/MAX7221 is an eight-digit, common-cathode LED display driver. It allows for interfacing a microprocessor or microcontroller with seven-segment display units with up to eight digits. Bar-graph displays and 64-LED matrices can also be interfaced with a controller/computer using this IC.
The IC includes:
- An on-chip BCD code-B decoder
- A segment and digit driver
- A multiplex scan circuitry
- An 8×8 static RAM to store up to eight digits
The IC has a 10-MHz serial interface that can communicate with a controller/computer over an SPI, a QSPI, or a MICROWIRE.
It operates over a 5V 330mA supply and consumes only 150 uA current in shutdown mode. For 3V operation, the MAX6951 can be used. The MAX7219/MAX7221 supports a shutdown mode, analog and digital brightness control, and test mode that forces all of the LEDs to turn on. Each LED segment can also be individually controlled by this driver.
The MAX7219 comes in a 24-pin DIP and SO packages, with the following pin diagram:
The MAX7219 has this functional diagram:
MAX7219 IC has the following pin configuration:
Multiplexing with Arduino using MAX7219
It’s quite simple to multiplex the eight, seven-segment display units with a controller/computer via the MAX7219/MAX7221.
- The data pins of the seven-segments should first be connected to the SEG A to SEG G and MAX7219’s DP pins.
- The common-cathode terminals of the segments must be connected to MAX7219’s DIG0 to DIG7 pins.
- The IC’s pins 4 and 9 should be hard-wired to the ground.
- The IC’s pin 19 should be connected to the 5V DC.
- MAX7219’s pin 18 must also be connected to the 5V DC via a suitable resistor.
- The IC’s DIN, LOAD, and CLK pins should be connected to the digital I/O pins of a controller/computer.
An SPI interface with Arduino
The SPI bus is a synchronous master-slave, serial-data bus. There can be only one master on an SPI bus and several slave devices can share it.
An SPI bus has four wires:
1. Master Out Slave In (MOSI) — for data transfer from master to slave
2. Master In Slave Out (MISO) — for data transfer from slave to master
3. Serial Clock (SCK/SCLK) — for clock signal from master to slave
4. Slave Select (SS on Master)/Chip Select (CS on Slave) — for selection of slave by the master
Some electronic components only require transmitting or receiving data. Such parts may only have a MISO or MOSI channel. Some devices use a three-wire SPI, in which the MISO and MOSI are combined with one wire, and called the MIMO.
An SPI bus can communicate data to hardware via a simple shift register. The data bits are communicated uninterrupted and continuously with each bit transferred over every clock pulse.
Most Arduino boards have at least one SPI interface. The SPI interface on Arduino UNO is shown here:
How the MAX7219 works over the SPI bus
The MAX7219 IC requires a three-wire SPI bus for data communication with a controller/computer, where the bus only has the MOMI, CLK, and SS/CS pins.
The IC has a 16-bit internal shift register where the data is shifted in from a controller/computer when there’s a rising edge at the IC’s LOAD pin. The data transferred to the IC over an SPI has two bytes.
- The first byte is the address of an internal register, which selects one of the internal registers.
- The second byte writes data to the selected internal register.
By passing the 16-bit data to the IC, various seven-segment digits — and features such as brightness control, test mode, and shutdown — mode can be controlled.
The MAX7219 registers
The MAX7219 has these internal registers…
No-op register – when data is transferred to this register, no operation is performed on the seven-segment display units of the given MAX7219 IC. This register is used when several MAX7219 ICs are daisy-chained.
For example, if four MAX7219 ICs are daisy-chained, then to transfer data to a fourth IC, the first three MAX7219 ICs must have data written to their no-op registers. This register has an address of bXXXX0000 (0xX0).
DigitrRegisters – used to control the eight digits that are displayed via the seven-segment display units. There are eight digit registers that have addresses from bXXXX0001 (0xX1) to bXXXX0111 (0xX7).
Decode-mode register – selects the BCD Code-B or no-decode operation for each digit. Each bit in the register corresponds to one digit. A logic HIGH selects the code B decoding and a logic LOW bypasses the decoder. This register has an address of bXXXX1001 (0xX9).
If the BCD Code-B is selected for a digit, the decoder only looks at the lower nibble of the data in the digit registers (D3–D0) — disregarding bits D4–D6.
The bit D7 of the digit registers is independent. If it’s set to HIGH, it turns on the decimal point. Otherwise, if set to LOW, it turns off the decimal point.
The BCD code-B control the seven-segment digits according to the following table:
If no-decode is selected, the data bits D7–D0 of the digit registers correspond to the segment lines of the MAX7219/MAX7221 as shown here:
Intensity register – controls the brightness of the segments. It has an address of bXXXX1010 (0xXA). If a resistor with a minimum value (9.53 kΩ) is connected between the V+ and ISET pins, the peak current sourced to the segments is 100 times the current entering ISET pin. This current can be digitally controlled by writing data to the intensity register.
The display brightness is digitally controlled via an internal pulse-width modulator, which scales the segment current in 16 steps.
This pulse-width modulator is controlled by the lower nibble of the intensity register, according to this table:
Scan-limit register – controls the number of digits displayed by the MAX7219/MAX7221. It has an address of bXXXX1011 (0xXB).
The digits to be displayed are controlled according to this table:
Shutdown register – if the LSB of this register is set to 0, the MAX7219/MAX7221 goes into shutdown mode and all of the digits are turned off. This register has an address of bXXXX1100 (0xXC).
Display-test register – if the LSB of this register is set to 1, the MAX7219/MAX7221 goes into the display test mode and all of the segments the digits are turned on. This register has an address of bXXXX1111 (0xXF).
Controlling the seven-segments via the MAX7219
To control the multiplexed seven-segment display units via the MAX7219/MAX7221, the controller/computer must write data to the IC’s internal registers using the SPI, QSPI, or Microwire bus.
The data is passed to the 16-bit internal shift register of the IC, where the first byte selects an internal register and the second byte writes the data to the selected register. If the seven-segment display units or the IC need to be tested, data can be written to display the test register (address byte 0x0F). It will confirm whether all of the seven-segment digits are operational.
The brightness of the display can be controlled by writing data to the intensity register (address byte 0x0A). The number of digits to be used can be implemented by writing data to scan-limit register (address byte 0x0B). Then, the decode mode should be selected by writing data to the decode-mode register (address byte 0x09).
The individual digits can then be controlled by writing data to the digit registers (addresses 0x01 to 0x08). If the display has to be turned off, the MAX7219 can be forced into shutdown mode by writing data to the shutdown register (address byte 0x0C).
If more than one MAX7219/MAX7221 ICs are daisy-chained, the no-op register (address byte 0x00) can be used while transferring data across the daisy-chained MAX7219s/MAX7221s.
Recipe: seven-segment display counter using Arduino and MAX7219
In this recipe, we’ll design a number counter using seven-segment display units, a MAX7219 LED driver IC, and Arduino UNO. The counter will count from 0000 up to 9999.
1. Arduino UNO x1
2. SSD x4
3. MAX7219 x1
4. Jumper or connecting wires
A MAX7219 IC-based, seven-segment driver module is used. The IC’s DIN, CLK and LOAD pins are connected to Arduino UNO’s pins 12, 11, and 10, respectively. The MAX7219 IC is supplied 5V of DC and ground from Arduino.
How the project works
The multiplexed seven-segment display units are interfaced with the MAX7219 IC. The IC is interfaced with Arduino UNO via the SPI bus. Using the SPI interface in Arduino, 16 bits of data are transferred to the shift register of the MAX7219 IC.
By writing data to the internal registers of the MAX7219 IC, seven-segment digits are controlled to display a counter from numbers 0000 to 9999
The Arduino sketch begins by importing the SPI library. The global variables are defined to assign pin numbers that are connected to MAX7219 IC’s DIN, CLK, and LOAD pins. A variable of an array type is defined to store the 16-bit commands for the MAX7219.
A character table is stored in the flash memory of Arduino UNO using the PROGMEM construct. This table contains the bytes that must be written to the LED segments for displaying digits 0 to 9 and letters A to F.
A function spiTransfer() is defined so the shiftOut() function transfers the 16-bit data to the MAX7219 IC. Each 16-bit data contains two bytes. The first byte is the address of the MAX7219 register and the second byte is the data to be written to a selected register. Both bytes are passed as arguments to this user-defined function.
A function clearDisplay() is defined, where the spiTransfer() function is used to write 0x00 to all of the digit registers to clear all of the digits. A function shutdown() is defined, which uses the spiTransfer() function to write data to the shutdown-mode register of the MAX7219.
A function init_7seg() is defined to initialize the display. In this function, the MOSI, SCLK, and CS pins are set to the digital output. The CS pin is set to HIGH to select the MAX7219 on the SPI bus.
A value of 0x00 is transferred to the display-test register (register address 15 or 0x0F) using the spiTransfer() function to set the MAX7219 to normal mode. A value of 0x07 is transferred to scan the limit register (register address 11 or 0x0B), allowing the use of all eight digits. A value of 0x00 is transferred to the decode-mode register (register address 9 or 0x09) to select “no decode” for all of the digits.
A function setChar() is defined that writes a value to the digit register of the MAX7219. Both the value and digit are set as parameters of the function. In this function, the data validation for the digit number and the value passed is complete. Then, the verified value is passed to a given digit register using the spiTransfer() function.
In the setup() function, the init_7seg() and shutdown(false) functions are called. The spiTransfer(10, 8) function is called to set the intensity of the display. The display is cleared by calling the clearDisplay() function.
In the loop() function, a “for loop” is run for the values 0 to 9999. For each number, four digits are derived using arithmetic operations and the digits are displayed on the multiplexed seven-segments using the setChar() function. Each number is incremental and displayed at an interval of 250 milliseconds. The interval is provided via the delay() function.
In the next tutorial, we’ll cover how to interface the character LCD with Arduino.