The easiest way to control a multiplexed 7-segment display unit!

I built a library (called AutoPlex7) to control seven segment displays with up to four digits! It handles multiplexing in the background, on its own, using Timer2, requiring no refresh calls. You simply tell it what number to display (or a variable), and it shows up!
It works with common anode and common cathode displays, and allows you to change what pins the display is connected to.

Here’s an example of what you can do with AutoPlex7:

If anybody wants to try it out or let me know what you think, feel free! :slightly_smiling_face:

I looked at your github repository, and it appears that you are using direct drive for the LEDs.

However I did not see a circuit diagram, nor any mention of the requirement for suitable current limiting resistors. Failure to use them will ultimately destroy the MCU.

Given that the Arduino forum regularly sees posts from people who don't have any practical knowledge of circuits, it is important to be very clear about safely wiring projects. Are you clear about those requirements?

Hello! Yes, this is for displays only, not with any driver ICs or shift registers. However, it’s meant to work with the regular multi-digit displays that require multiplexing.

As for the circuit diagram… I guess I could add one. But you can wire it up any way you want as long as you define what pins the display is connected to in your sketch.

And for the current limiting resistors, I agree, I should mention this. I’ll edit my readme.

Also, yes! I do have a good amount of knowledge on how to safely wire circuits. I did basic electronics for a little over a year before starting Arduino.

Updated to add warning about using resistors in v1.0.3. :slightly_smiling_face:

With a 5V supply, it is advised to use a resistor of at least 270 ohms on the segment pins.

This will still damage the chip. If you do not understand why, I suggest you add a warning to the readme warning users that following your instructions will result in damage to their hardware.

The readme also fails to mention which models of Arduino the library is compatible with.

Huh? At 270Ω, the current is just ~11mA per segment.
The Arduino digital pins can provide 11mA just fine, with an absolute max of 40mA and recommended max of 20mA.
Why do you think this would damage the controller?

Also, the library should be compatible with most boards. Anything that has Timer2 since that is at the core of it’s automatic multiplexing function.

Let see the very beginning of the first example:

#include <AutoPlex7.h>

// Set up the display type and connections
int displayType = COMMON_ANODE; // Change to "COMMON_CATHODE" if using a common cathode display

For clarity, let's add macros from the library:

#include <AutoPlex7.h>

#define displayType ON
#define COMMON_CATHODE HIGH
#define COMMON_ANODE LOW
#define OFF !ON

// Set up the display type and connections
int displayType = COMMON_ANODE; // Change to "COMMON_CATHODE" if using a common cathode display

We see that the displayType is not actually a variable name, but a substitution.
Using a #define macro to replace a variable name is very bad code. Primarily because macros don't respect scope and are replaced throughout the entire text.
The C language doesn't prevent a user from creating a local variable named displayType. Due to scope separation, this wouldn't create any problems for the rest of the code... but in your case, due to your substitution, such a variable would also be replaced with ON, and everything would fall apart.

Ohhh… okay. I didn’t know that.
How would it become ‘ON’ without being set to that though? Because actually… displayType is supposed to be the same as on. COMMON_ANODE equals low and COMMON_CATHODE equals high. So by setting what displayType equals you are effectively telling the code whether going low or going high is what turns the segments on.

@techtronicsengineering
There are a lot of seven segment Arduino libraries in the net. Did you look at other libraries before writing yours?

Your library's code doesn't seem particularly efficient to me.
Besides the fact that you ignored my comments in post #7, I'd like to point out a few more points:

  1. A typical seven-segment indicator has eight pins controlling the segments and the dot. Each pin can have two states: on and off. Logically, the state of the entire indicator is described as a byte, where each bit represents the state of one segment. In this case, each symbol corresponds to only one byte variable
static const uint8_t digitCodeMap[] = {
  // GFEDCBA  Segments      7-segment map:
  0b00111111, // 0   "0"          AAA
  0b00000110, // 1   "1"         F   B
  0b01011011, // 2   "2"         F   B
  0b01001111, // 3   "3"          GGG
  0b01100110, // 4   "4"         E   C
  0b01101101, // 5   "5"         E   C
  0b01111101, // 6   "6"          DDD
  0b00000111, // 7   "7"
  0b01111111, // 8   "8"
  0b01101111, // 9   "9"
};

This method is used in almost every seven-segment indicator control library because it simplifies and shortens the code.

So instead of lot of digitalWrite() in your code:

void Display::showDigitSegments(int val){
    switch(val){
        case 0: digitalWrite(A,ON); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,ON); digitalWrite(E,ON); digitalWrite(F,ON); digitalWrite(G,OFF); break;
        case 1: digitalWrite(A,OFF); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,OFF); digitalWrite(E,OFF); digitalWrite(F,OFF); digitalWrite(G,OFF); break;
        case 2: digitalWrite(A,ON); digitalWrite(B,ON); digitalWrite(C,OFF); digitalWrite(D,ON); digitalWrite(E,ON); digitalWrite(F,OFF); digitalWrite(G,ON); break;
        case 3: digitalWrite(A,ON); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,ON); digitalWrite(E,OFF); digitalWrite(F,OFF); digitalWrite(G,ON); break;
        case 4: digitalWrite(A,OFF); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,OFF); digitalWrite(E,OFF); digitalWrite(F,ON); digitalWrite(G,ON); break;
        case 5: digitalWrite(A,ON); digitalWrite(B,OFF); digitalWrite(C,ON); digitalWrite(D,ON); digitalWrite(E,OFF); digitalWrite(F,ON); digitalWrite(G,ON); break;
        case 6: digitalWrite(A,ON); digitalWrite(B,OFF); digitalWrite(C,ON); digitalWrite(D,ON); digitalWrite(E,ON); digitalWrite(F,ON); digitalWrite(G,ON); break;
        case 7: digitalWrite(A,ON); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,OFF); digitalWrite(E,OFF); digitalWrite(F,OFF); digitalWrite(G,OFF); break;
        case 8: digitalWrite(A,ON); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,ON); digitalWrite(E,ON); digitalWrite(F,ON); digitalWrite(G,ON); break;
        case 9: digitalWrite(A,ON); digitalWrite(B,ON); digitalWrite(C,ON); digitalWrite(D,ON); digitalWrite(E,OFF); digitalWrite(F,ON); digitalWrite(G,ON); break;
    }
}

we can do it in more elegant way:

// Turns a segment on, as well as all corresponding digit pins
// (according to digitCodes[])
uint8_t pins[] = {A, B, C, D, E, F, G};
void showDigitSegments(uint8_t val){
 if (val < 10)  // check 0-9 range
  {
   for (uint8_t segment = 0 ; segment < 7 ; segment++) {
    if (digitCodeMap[val] & (1 << segment)) { // Check a single bit
      digitalWrite(pins[segment], ON);
    }
    else { digitalWrite(pins[segment], OFF); }
  }
}
}

I took the code above from the first library I found on Google - GitHub - DeanIsMe/SevSeg: Seven segment display controller library for Arduino

  1. Speaking of variables, it would be more efficient to declare pins as constants and store them within a library class than to use variables from a sketch and declare them external to your code. This is error-prone.
    And, as seen above, it's much more efficient to organize pins into an array.

It is not the case.
Your Timer2 code is only compatible with old classic AVR-based boards such as Arduino Nano (classic), Uno R3 and, perhaps, Mega.
This code will not work on the vast majority of existing Arduino boards, including any new boards like the Uno R4, Nano Every, etc. etc

There is nothing wrong with this, but you must specify the supported platform in the library.properties file

In which case, you could use Timer0 which is already in use for the millis timer, and leave Timer2 free for other uses. Millis uses the overflow interrupt, a compare interrupt can be used simultaneously.

Variables used both inside and outside of interrupts need to be declared volatile.

You seem to be refreshing the display more often than necessary, a bit over 50Hz for the entire display (200Hz for four digits) should be enough to eliminate a blinking appearance.

True for the very old ATmega based Arduinos, not true for many others.

For example, with the SAMD21 MCU, in the default configuration, digital output pin maximum current draw is 2 mA. With special configurations is it possible to set some pins to 7 mA max.

It appears that you know just enough about the topic to give irresponsible advice.

Not many people are happy to dedicate 11 pins to running a 7-segment display, given that two suffice with a driver chip.

Okay, if that controller can’t even deliver 10mA then it doesn’t seem very suitable for controlling seven segment displays anyway. At that rate, each segment would need a driving transistor.

I'm glad that you see the problem!

Right so… it’ll work on an Uno R3, Nano, and Mega? Correct?
(I’ll update my readme but want the info to be accurate)

I didn’t ignore your comments! Maybe you didn’t see my reply. I think you might have misunderstood though (or maybe I’m the one misunderstanding :man_shrugging:) but displayType is supposed to be equal to ‘ON.’ They’re interchangeable. It’s so the used only sees displayType rather than all the inner workings of the library, to prevent confusion.

I’ll try to make these adjustments when I have time.

I hope that writing your next library, you will be better prepared and study the experience of others before uploading your code to the GitHub ^)

  1. There are over a half dozen boards called "Arduino Nano", with several different MCUs.

  2. Your code will work only with processors featuring digital pins that can handle the LED current. ATmega and ATtiny processors are among those that can.

However, your design will eventually fail if a digital pin connected as a digit driver (not segment driver) sources or sinks much more than about 30 mA. which will be the case if the pin sources to or sinks current from more than 3 LED segments.

That is why informed people use transistors as digit drivers -- in the example below, common anode.

Yes. And it is not a good style...
See the SevSeg library (link in #9) to know how to write it properly.