README.md

Overview

Drv7SegQ595 is a single-class Arduino library for driving a multiplexed 7-segment display using a single 74HC595 shift register IC and a set of GPIO-driven transistors.

Parent project

This library is a derivative (a fork) of the Drv7Seg2x595 library. The main difference is that the parent project uses two daisy-chained 74HC595 shift register ICs, while this library uses a single shift register IC and a set of 1 to 4 GPIO-driven transistors instead.

Concept

7-segment displays are simple, cheap and reliable data output devices. However, interfacing them with a microcontroller (MC) requires appropriate software and, most commonly, additional hardware.

Typically, 7-segment displays come in models with 1 to 4 character positions (digits). Number of input pins for any given model equals 8 + number of positions, thus 9 is the minimum and 12 is the maximum (duplicated pins count as one). Driving such a display requires a number of individual signals equal to the number of the input pins:

  • 8 signals to turn ON and OFF individual segments (including a dot segment, also known as a decimal point or DP).
  • 1 to 4 signals to turn ON and OFF whole positions.

Due to significant number of required signals, output-extending devices, such as output shift registers, are commonly used. 74HC595, sometimes simply called 595, is a widely used 8-bit serial-in, parallel-out (SIPO) shift register integrated circuit (IC) commonly employed to drive 7-segment displays. A single 595 provides an 8-bit shift register, which is sufficient to hold a segment pattern corresponding to a glyph. The register’s 8 bits are referred to as segment byte or seg_byte.

Another 1 to 4 signals come from a set of GPIO-driven transistors. Combined with the shift register, it is sufficient for controlling any typical 7-segment display.

The API provided by this library allows for control over 1 to 4 character positions. The number of ns to be used must be specified during the driver configuration.

Multiplexing

This library relies on multiplexing: a way of driving a multi-digit 7-segment display by turning on only one character position at a time in quick succession, in a cycle. Because the multiplexing cycle runs faster than the eye can follow, all positions appear to be lit continuously, even though only one is actually turned on at any given moment.

This approach greatly simplifies the circuit because it doesn’t rely on a separate set of segment-control outputs for every position and instead utilizes the single set of segment-control outputs shared by all positions (the defined segment pattern shows up only on the intended position anyway, because only that position will be turned on at the appropriate moment).

Ghosting and countermeasures

Advantages of multiplexing come with an unwanted side effect called ghosting: segments can seem to have a faint, “ghost-like” glow on positions that are supposed to be off. To avoid this effect, the library utilizes the anti-ghosting techniques that involve retention of a currently output glyph on a respective position for a short period of time. Duration of the said period can be fine-tuned by the library user via the library’s API.

The library’s anti-ghosting logic is based on a non-blocking, micros()-based timer. No blocking, delay()-based timers are used.

Position switching

Every character position is turned on (powered) by setting the output level of a GPIO specified during the driver configuration either to high or low, because it makes it possible to source/sink current from/to that pin and thus to drive a switching device, such as a transistor.

Depending on the display type (whether it’s a common-cathode or a common-anode device) and the switching device type (whether it’s an active-high device, like an NPN BJT or an N-channel MOSFET, or an active-low device, like a PNP BJT or a P-channel MOSFET), positions will be turned on either by high or low digital output level. The API provided by this library supports both variants. The switching type (active-high or active-low) must be specified during the driver configuration.

Data transfer (shifting)

The driver implemented by this library uses either bit-banging or SPI for shifting the data into the shift register. If you choose bit-banging, the driver will use whatever GPIO pins you assign to it. If you choose SPI, the driver will use the default SPI instance (although support for non-default and multiple SPI instances may be added later).

Reference schematic

Here’s a typical circuit diagram for the described arrangement (assumes a common-cathode display):

circuit_diagram_(schematic).png

For convenience, the example sketch default constant values corresponds to the circuit diagram provided here.

Wiring for a common-anode display is almost identical, the only difference being that the transistors’ emitters should connect to the display’s common pins and their collectors should connect to the circuit’s positive rail (VCC).

The wiring in your circuit may differ from the provided schematic to some degree, and the library will still be applicable as long as your circuit complies with the premise of the seg_byte and the position-control pins’ distinct roles.

Notes on the reference schematic

  • Power your 595 with the same voltage your MC runs on.
  • Transistors Q1..Q4 are intended to be general-purpose NPN BJTs such as MMBT3904 (assumed by the reference PCB design, see below), 2N3904, 2N4401, 2N2222, or BC548. You can even use a KT315, comrade.
  • If the display segment LEDs are too bright, or if you notice visible brightness changes when the DP blinks, increase the R0..R7 resistor values to around 470-680 Ω. This is especially advisable if your 595 is powered from a 5 V supply.

API usage

Include the library:

#include <Drv7SegQ595.h>    // Arduino style.
//#include "Drv7SegQ595.h"  // Generic embedded programming style.

Driver configuration

Choose one of the following variants.

Bit-banging:

// Prototype.
int32_t begin_bb(PosSwitchType pos_switch_type,  // Whether high or low output level turns on a character position.
                 uint32_t data_pin,              // The pin that outputs the next bit value to be shifted.
                 uint32_t latch_pin,             // The pin that propagates the shifted data to the output register.
                 uint32_t clock_pin,             // The pin that commands the next bit value to be shifted.
                 int32_t pos_1_pin,              // Number of the MC pin that will control the 1st position.
                 int32_t pos_2_pin,              // Number of the MC pin that will control the 2nd position.
                 int32_t pos_3_pin,              // Number of the MC pin that will control the 3rd position.
                 int32_t pos_4_pin               // Number of the MC pin that will control the 4th position.
                );

// Example call.
Drv7Seg.begin_bb(Drv7SegActiveHigh,  // Other option is Drv7SegActiveLow.

                 /* Digital output pins you want to use for shifting the data into the IC.
                  * Pin numbers must correspond to the pin numbering specified
                  * by the Arduino core you're using.
                  */
                 6, 7, 8,

                 /* Digital output pins you want to use for character position switching.
                  * Pin numbers must correspond to the pin numbering specified
                  * by the Arduino core you're using.
                  *
                  * The first one of these arguments (1st position-control pin) is required.
                  * Subsequent arguments are optional.
                  * The driver will be configured to control the number of positions
                  * equal to the number of arguments that weren't omitted.
                  */
                 10,  // This parameter is required.
                 11,  // This parameter is optional.
                 12,  // This parameter is optional.
                 9    // This parameter is optional.
                );

SPI with default pins:

/* Mostly identical to the bit-banging variant, but among the shifting pins only the latch pin needs to be specified
 * (the default MOSI pin must be used as a data pin and the default SCK pin must be used as a clock pin).
 */

// Example call.
Drv7Seg.begin_spi(...
                  LATCH_PIN,
                  ...
                 );

SPI with custom pins:

/* Mostly identical to the bit-banging variant, but the data pin role goes to
 * the specified MOSI pin and the clock pin role goes to the specified SCK pin.
 */

// Example call.
Drv7Seg.begin_spi_custom_pins(...
                              MOSI_PIN,
                              LATCH_PIN,
                              SCK_PIN,
                              ...
                             );

Status check

Get the driver configuration status (check if it was configured successfully):

int32_t drv_config_status = Drv7Seg.get_status();
// Loop the error output if the driver configuration was unsuccessful.
if (drv_config_status < 0) {  // If an error is detected.
    while(true) {
        Serial.print("Error: driver configuration failed, error code ");
        Serial.println(drv_config_status);
        delay(INTERVAL);
    }
}

You can also check the value returned by begin_*() instead of calling get_status().

Output

Assign the glyphs you want to output to each character position:

// Prototype.
int32_t set_glyph_to_pos(uint8_t seg_byte,  // A byte that corresponds to the glyph to be output.
                         Pos pos            // A number of the position the glyph must be output on.
                        );

// Example call (single).
Drv7Seg.set_glyph_to_pos(
                         0b00010001,  // Depending on wiring, may represent character '1'.

                         /* Valid arguments are Drv7SegPosN, where
                          * N => 1
                          * and
                          * N <= the number of positions the driver was configured to use.
                          */
                          Drv7SegPos1
                        );

/* Example calls (typical implementation).
 *
 * Make recurrent calls in quick succession for all positions your driver was configured to use.
 */
Drv7Seg.set_glyph_to_pos(seg_byte_minutes_tens, Drv7SegPos1);
Drv7Seg.set_glyph_to_pos(seg_byte_minutes_ones, Drv7SegPos2);
Drv7Seg.set_glyph_to_pos(seg_byte_seconds_tens, Drv7SegPos3);
Drv7Seg.set_glyph_to_pos(seg_byte_seconds_ones, Drv7SegPos4);

Commence the actual output:

// Call it inside the loop() function.
Drv7Seg.output_all();

If you want a more fine-grained control over output, you can use a lower level method. Using it will override the glyph assignment done with set_glyph_to_pos() calls.

// Prototype.
int32_t output(uint8_t seg_byte,  // A byte that corresponds to the glyph to be output.
               Pos pos            // A number of the position the glyph must be output on.
              );

// Example call (single).
Drv7Seg.output(
               0b00010001,  // Depending on wiring, may represent character '1'.

               /* Valid arguments are Drv7SegPosN, where
                * N => 1
                * and
                * N <= the number of positions the driver was configured to use.
                */
               Drv7SegPos1,
              );

/* Example calls (typical implementation).
 *
 * Make recurrent calls in quick succession for all positions your driver was configured to use.
 */
Drv7Seg.output(seg_byte_minutes_tens, Drv7SegPos1);
Drv7Seg.output(seg_byte_minutes_ones, Drv7SegPos2);
Drv7Seg.output(seg_byte_seconds_tens, Drv7SegPos3);
Drv7Seg.output(seg_byte_seconds_ones, Drv7SegPos4);

Anti-ghosting

Ghosting prevention involves retention of a currently displayed glyph on a corresponding position for a short period of time. The duration of such period has a reasonable default of 600 microseconds, but you can override it.

/* If you encounter ghosting, random flickering, or glyphs appear too dim or show inconsistent brightness,
 * try passing a higher value (about 1000 to 4000).
 * If you encounter constant flickering, try passing a lower value (about 10 to 400).
 */
Drv7Seg.set_anti_ghosting_retention_duration(1000);

Refer to Drv7SegQ595.h for more API details.

Special cases

  • Multiple drivers. You can create additional instances of Drv7SegQ595Class and use them for driving multiple displays, but you shouldn’t employ SPI by more than one instance at a time.

  • Single-digit displays. With a single-position display there’s usually no purpose in a switchable signal that turns the only character position ON and OFF (all control job can be done by seg_byte alone), nor there’s a need for multiplexing. Still, you can use this library to control a single-digit display in a pinch. You can either:

    • assign a single position-control pin during the driver configuration and use that pin to control your only position (in this case the multiplexing logic will still be applied, but the single position will always be the one to be turned on next);
    • ignore the position-control pins completely and power your display directly by connecting it to GND or VCC, according to the display type. You will still have to pass a single position-control pin argument during the driver configuration to comply with the library logic, but its particular value becomes mostly irrelevant (pick any GPIO pin available for driving).
  • Ignoring certain digits. If you, for instance, have a 4-position display and for some reason you want to use only positions 2 and 3, it’s completely OK, you can do that using this library. Pass two position-control pins during the driver configuration: one for the 2nd physical position (it’ll correspond to Drv7SegPos1 within the library logic) and another one for the 3rd physical position (it’ll correspond to Drv7SegPos2 within the library logic).

Dependencies

  • SPI.h library implementation for the Arduino core and the board (device) you’re using. It is available for most major Arduino cores, although it isn’t guaranteed that every single Arduino core in the world will have it as well. In an unlikely case when it is not implemented for your Arduino core or device, you can still use this library’s bit-banging mode, but in order to avoid compilation errors you’ll have to manually comment out the #define DRV7SEGQ595_SPI_PROVIDED_ASSUMED preprocessor directive in Drv7SegQ595.h.

  • SegMap595 library (available from Arduino Library Manager, also see links below) is used in the example sketch in order to simplify byte mapping, but aside from that it’s not a prerequisite for using Drv7SegQ595.h.

Compatibility

The library works with any Arduino-compatible MC capable of bit-banging or SPI data transfer.

Availability of the configuration variant that takes custom-assigned SPI pins relies on the capabilities of a given MC and the corresponding SPI.h implementation. As of the last update to this library, this variant is only available for ESP32 and STM32 MC families.

Rich circuit diagram

This library includes a KiCAD project that provides a reference schematic. PCB layout is not included though. The project was created in KiCAD 9.0.

To-do list

  • Add support for using non-default and multiple SPI instances.

Licensing

  • The software part of this library, as well as its documentation, is licensed under the MIT License (see LICENSE here).
  • All hardware-related files in this library, including illustrations, are licensed under the CERN-OHL-P v2 (see extras/kicad/LICENSE_HARDWARE here).

Links

This library

SegMap595

Drv7Seg2x595

The parent project of this library. Uses a second shift register IC instead of a set of GPIO-driven transistors.

Contact details

Maintainer — Dmitriy Efimov aka Erling Sigurdson

Your feedback and pull requests are welcome.

Описание
A single-class Arduino library for driving a multiplexed 7-segment display using a single 74HC595 shift register IC and a set of GPIO-driven transistors.
Релизы
2026-01-14
последний
Конвейеры
0 успешных
0 с ошибкой
Разработчики