[Solved] 4 Digit 7 Segment Display Question

Hello! I'm pretty new to Arduino, but I have gone through helpful tutorials, and I think I have a grasp on beginner concepts, but I have a project idea that I'm struggling with.
The end goal is to connect an ultrasonic sensor to a 4 digit 7 segment display to display distance. Now, I've done some research on seven segment displays, but I still have some questions.

Here's my hardware:
5641AS Common Cathode 4 Digit 7 Segment Display
HC-SR04 Ultrasonic Sensor.

Here's some code that I got when I went to a tutorial video that I plan to use;

// 5461AS 
int time = 5;

int pinA = 9;
int pinB = 8;
int pinC = 7;
int pinD = 6;
int pinE = 5;
int pinF = 4;
int pinG = 3;
int pinDP = 2;

int DIG1 = 13;
int DIG2 = 12;
int DIG3 = 11;
int DIG4 = 10;

void choose_digit(char num) {
switch(num) { default: // 0
default value digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH); 
digitalWrite(pinD, HIGH); 
digitalWrite(pinE, HIGH); 
digitalWrite(pinF, HIGH); 
digitalWrite(pinG, LOW);
digitalWrite(pinDP,LOW);
break; 
case 1:
digitalWrite(pinA, LOW); 
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH); 
digitalWrite(pinD, LOW);
digitalWrite(pinE, LOW);
digitalWrite(pinF, LOW);
digitalWrite(pinG, LOW);
digitalWrite(pinDP,LOW);
break; 
case 2:
digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, LOW); 
digitalWrite(pinD, HIGH); 
digitalWrite(pinE, HIGH); 
digitalWrite(pinF, LOW);
digitalWrite(pinG, HIGH);
digitalWrite(pinDP, LOW);
break; 
case 3:
digitalWrite(pinA, HIGH); 
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, HIGH);
digitalWrite(pinE, LOW); 
digitalWrite(pinF, LOW); 
digitalWrite(pinG, HIGH); 
digitalWrite(pinDP, LOW); 
break;
case 4:
digitalWrite(pinA, LOW);
digitalWrite(pinB, HIGH); 
digitalWrite(pinC, HIGH); 
digitalWrite(pinD, LOW); 
digitalWrite(pinE, LOW); 
digitalWrite(pinF, HIGH);
digitalWrite(pinG, HIGH);
digitalWrite(pinDP, LOW);
break; 
case 5:
digitalWrite(pinA, HIGH);
digitalWrite(pinB, LOW);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, HIGH);
digitalWrite(pinE, LOW);
digitalWrite(pinF, HIGH);
digitalWrite(pinG, HIGH);
digitalWrite(pinDP, LOW);
break; 
case 6:
digitalWrite(pinA, HIGH);
digitalWrite(pinB, LOW); 
digitalWrite(pinC, HIGH);
digitalWrite(pinD, HIGH);
digitalWrite(pinE, HIGH);
digitalWrite(pinF, HIGH);
digitalWrite(pinG, HIGH);
digitalWrite(pinDP, LOW);
break; 
case 7: 
digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, LOW);
digitalWrite(pinE, LOW); 
digitalWrite(pinF, LOW);
digitalWrite(pinG, LOW);
digitalWrite(pinDP, LOW);
break; 
case 8: 
digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, HIGH);
digitalWrite(pinE, HIGH);
digitalWrite(pinF, HIGH);
digitalWrite(pinG, HIGH);
digitalWrite(pinDP, LOW);
break;
case 9: 
digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, HIGH);
digitalWrite(pinE, LOW); 
digitalWrite(pinF, HIGH);
digitalWrite(pinG, HIGH);
digitalWrite(pinDP, LOW);
break;
}

}

void pick_digit(int digit) {
digitalWrite(DIG1, HIGH);
digitalWrite(DIG2, HIGH);
digitalWrite(DIG3, HIGH);
digitalWrite(DIG4, HIGH);
switch(digit) { 
  case 1: 
  digitalWrite(DIG1, LOW); 
  break;
  case 2: 
  digitalWrite(DIG2, LOW);
  break;
  case 3: 
  digitalWrite(DIG3, LOW);
  break;
  default:
  digitalWrite(DIG4, LOW);
  break;
}

}

void decimal_place() {
digitalWrite(pinDP, HIGH);
}

void seven_segment(int number) {
unsigned char thousands = int (number/1000);
unsigned char hundreds = int ((number/100)%10);
unsigned char tens = int ((number/10)%10);
unsigned char ones = int (number%10); //1234
choose_digit(thousands);
pick_digit(1);
delay(time); choose_digit(hundreds);
pick_digit(2);
delay(time); choose_digit(tens);
pick_digit(3);
decimal_place(); // add decimal point
delay(time); choose_digit(ones);
pick_digit(4);
delay(time);

}

void setup() { pinMode(DIG1, OUTPUT);
pinMode(DIG2, OUTPUT);
pinMode(DIG3, OUTPUT);
pinMode(DIG4, OUTPUT);
pinMode(pinA, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(pinC, OUTPUT);
pinMode(pinD, OUTPUT);
pinMode(pinE, OUTPUT);
pinMode(pinF, OUTPUT);
pinMode(pinG, OUTPUT);
pinMode(pinDP,OUTPUT);
Serial.begin(9600);

}

void loop() { int sensor_value = analogRead(A0);
Serial.println(sensor_value); seven_segment(sensor_value); delay(1);

}

And here are my questions:

1: How do you hook up the display?
I generally understand the pinout diagram idea, but online there is not one consistent way of hooking up the display. I've seen that transisors are part of the diagram as well as resistors, but I've also seen a lack of transistors work. I'd prefer not to use a shift register or transistors -- preferably just resistors, but I don't want to break anything on the display or my board. What should I do?

2: How does the display ground?
I'm just used to grounding things on the GND pin on my board, but on a diagram, they didn't use the GND pin; they just hooked it up to other pins. Now, with a bit more reading, I can accept hooking up an LED to two pins and setting one LOW for grounding it, but that's just one LED. How does this work on a 7 segment display? Is it with multiplexing setting only one digit on at a time, and then the electricity can ground through another display pin? So then, if you wrote all four digital pins as LOW (AKA ON), would that not work because there would be no ground and therefore no flow? Can someone explain this whole grounding idea?

Thanks for the help!!!

I'm just wondering if it's worth the effort.
Why not use a dedicated LED driver IC, e.g. MAX7219/MAX7221 (SPI) or HT16K33 (I2C)

Your code indicates you will be multiplexing by digit - turning on one digit at a time. So for a particular digit, you will take the pins high for the segments which are to be lit up for the number to be displayed, then take the common cathode pin for that digit low. That completes the circuit and turns on those segments on that digit. Then you turn those off and do the same thing for the next digit. If you go through the four digits fast enough, they will all appear to be lit up at the same time.

The problem is that LEDs operate on current. The more current you run through them, the brighter they are. So the question is whether your I/O pins can source and sink enough current to light up the displays to your satisfaction. A point to keep in mind is that LEDs vary greatly in how efficiently they produce light - how much light you get for your milliamp buck.

So in the worst case, which is displaying the number “8”, each segment pin will source current for one segment, and each digit pin will sink current for seven segments (or eight if you’re using the decimal point). If a segment needs, say, 10 mA to be bright enough, then an individual segment pin can easily supply that, but there might be question about the aggregate 70 mA needed to drive all of the segments. The datasheet for your processor will give you data about the maximum current it can handle through its Vcc and GND pins.

But it’s unlikely that a single I/O pin can sink 70 mA, and that’s why transistors are often used on the common cathode lines.

However, if only 5 mA is needed to adequately light up a segment, then the transistors may not be needed. In any case, you will need a resistor on each individual segment driver line. I know you’ll see lots of examples of people not bothering with the resistors, but they should be there as a general rule to limit current. You cannot just put one resistor on each common cathode line because then all of the segments being lit will share an essentially fixed amount of current, which would make a “1” brighter than an “8”, which you don’t want.

I’ll attach a schematic showing the wiring for two digits. Each of the additional digits would be done the same way.

I should say that there is another way to multiplex these displays, and that is by segment. You would turn on each segment, one at a time, and the common cathode pins would determine on which digits that segment is to be lit up. This requires about double the refresh rate as the traditional method, but can usually be done without transistors, and with resistors only on the four common cathode lines. More about this if you’re interested.

[

Expand<](https://forum.arduino.cc/index.php?action=dlattach;topic=678277.0;attach=358141)

ShermanP:
I should say that there is another way to multiplex these displays, and that is by segment. You would turn on each segment, one at a time, and the common cathode pins would determine on which digits that segment is to be lit up. This requires about double the refresh rate as the traditional method, but can usually be done without transistors, and with resistors only on the four common cathode lines.

And of course, would therefore result in a dimmer display.

Paul__B:
And of course, would therefore result in a dimmer display.

Well, yes, for a 4-digit display. You would have to adjust the common cathode lines' resistor value to compensate for that. So each segment would be on for 1/8 of the time instead of 1/4 of the time, but would be twice as bright when it's on. So the perceived brightness would be about the same, as would the overall power expended. But definitely a lower parts count (4 resistors versus 12 resistors and 4 transistors). Of course for a 4-digit display, it would depend on the GPIO pin being able to drive four segments at once, so high-efficiency displays might be needed. And I don't know whether any 7-segment library supports multiplexing by segment. Anyway, here's my repo on it with sample sketches:

It appears the SevSeg library supports multiplexing by segment. You would choose the resistors-on-digits option.

So basically, all I'd need to do is run my code, and just put a resistor in to any input LED segment? That would protect everything no transistors needed. And, if I did that, the only problem would be the inadequate current (or voltage?) getting to the LEDs? I can deal with a bit of dimming with shared current, but would anything fry with only resistors? Will the display like suck out more current than the Arduino can output? Or with a resistor is that negated? Thanks again!

No, you would have one resistor on each common cathode pin - four resistors in total. See the attached drawing for two digits.

It doesn't look like your code would work for this method. You would have to study the sevseg.h library and the examples included there, and rewrite everything. Probably the first step is to see if you can get the SevSeg_Counter example to work.

This will depend entirely on how efficient your LEDs are. A single processor pin will be driving a maximum of four segments at the same time. If the display is bright enough with, say 470-ohm resistors, then something like an Uno should drive it ok. You might get away with 330-ohm.

Alternate.jpg

330 Ohm OK for two, but where are the other two? :astonished:

Each digit's common cathode has a resistor to a GPIO pin, and that pin only sinks current for one segment at a time. The issue is whether a segment GPIO pin can source current for at most four segments at a time (the same segment on all four digits). Depending on the voltage drop across the segment LEDs, 330 ohm resistors will put you in the neighborhood of 10mA per segment, or 40mA in total. (The 5641AS datasheet says it drops 1.8V typical at 20mA.) That may be pushing things a bit. So 470R might be a safer choice if it's bright enough - that would give you about 27mA maximum source current on a segment pin, which an Uno should be able to handle.

I'm not quite understanding why you would put the resistor on the digit pins.
Doesn't the current flow from the arduino to one of the segments, and then grounds through one of the digit pins? Then multiplexing switches the digits.

So then wouldn't I want to have the resistor BEFORE the current reaches the LED segments?

tyster02:
I'm not quite understanding why you would put the resistor on the digit pins.
Doesn't the current flow from the arduino to one of the segments, and then grounds through one of the digit pins? Then multiplexing switches the digits.

So then wouldn't I want to have the resistor BEFORE the current reaches the LED segments?

No. This would be multiplexing by segment, not by digit. You turn on only the segment A pin, which is connected to segment A on all four digits, and at the same time you turn on the digit pins of all the digits which should have segment A lit up. Then you turn off segment A, and do the same for segment B, and so forth. One segment pin may need to source current for none or as many as four segments at the same time, but each digit pin only has to sink current for one segment at a time. So you want the resistors on the digit pins so every segment will get the same current. If you put resistors on the segment lines, brightness will vary depending on how many digits have a particular segment lit up, and that's not what you want. There's a video link in the Readme of the Github repo I linked to above that explains it pretty well.

1. Connect your cc-type multiplexed display devices as per Fig-1.
ccd4rxlib.png
Figure-1:

2. Test the functioning of the display unit of Fig-1 with the help of following SevSeg.h Library based sketch. After uploading of the sketch, the display will show 31.76.

#include "SevSeg.h"
SevSeg sevseg;
byte numDigits = 4;
byte digitPins[] = {A0, A1, A2, A3};//DP0, DP1, DP2, DP3 from left to right
byte segmentPins[] = {8, 9, 10, 11, 12, 13, 6, 7};//a, b, c, ..., g, p from left
bool resistorsOnSegments = false;
byte hardwareConfig = COMMON_CATHODE;

void setup()
{
  Serial.begin(9600);
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
  sevseg.setBrightness(30);
  //analogReference(INTERNAL);
}

void loop()
{
  unsigned long prMillis = millis();
  while (millis() - prMillis < 2000)//
  {
    sevseg.refreshDisplay();
  }
  float temp = 31.76;//100 * ( 1.1 / 1023) * analogRead(A4);//31.76
  sevseg.setNumber(temp, 2);//decimal point before 2-digit from right
}

ccd4rxlib.png

SevSeg-master.zip (20.7 KB)

GolamMostafa, your drawing has the resistors on the segment lines, so wouldn't you need to change:

bool resistorsOnSegments = false;

to

bool resistorsOnSegments = true;

?

ShermanP:
GolamMostafa, your drawing has the resistors on the segment lines, so wouldn't you need to change:

bool resistorsOnSegments = false;

to

bool resistorsOnSegments = true;

?

true or false -- it does not bring any difference.

GolamMostafa:
1. Connect your cc-type multiplexed display devices as per Fig-1.
ccd4rxlib.png

You clearly haven't been following the discussion here.

What you illustrate is the usual way of driving a display - it doesn't matter whether common cathode or common anode as the code determines whether pins are driven HIGH or LOW.

If multiplexing by digit, then you need to limit the total current of all segments so that the digit driver can handle it - your eight 2k2 resistors achieve that.

What has been discussed, purely as an interesting alternative and not on any practical imperative - is to multiplex by segment. To do this, you put the resistors in the digit lines instead so that now the total current in the segment driver is limited. Since there are only four digits, you can drive them twice as hard as eight segments and use half the resistor value.

If you had eight digits, there is no advantage either way, but multiplexing by digit is generally easier to code. In either case, your 2k2 resistors are conservative and while the brightness is limited, it will be much more uniform that if you are driving the maximum current where the segments will be noticeably dimmer when many or all are lit due to loss of voltage in the digit driver. :grinning:

Paul__B:
What has been discussed, purely as an interesting alternative and not on any practical imperative - is to multiplex by segment. To do this, you put the resistors in the digit lines instead so that now the total current in the segment driver is limited. Since there are only four digits, you can drive them twice as hard as eight segments and use half the resistor value.

Yes, I guess the case for segment multiplexing is not really compelling since you probably have to drive the segments with twice as much current since they're on only half as much time. But if the persistence of human vision might let you use a little less current than that, then the "practical imperative" could be a significant savings in parts count if you are able to avoid the use of transistors. And even if you don't need transistors either way, four resistors is still less than eight. And if it's a two digit display, two resistors is still less than eight.

And since sevseg.h supports both methods, there really isn't any difference in coding requirements.

My approach would be to see if multiplexing by segment produces a bright enough display and the increased refresh rate doesn't cause any problems. If both are true, then that's the best solution with the lowest parts count. And human nature being what it is, you might find that the necessary brightness level isn't so great if reducing it means avoiding all those parts.

Paul__B:
If multiplexing by digit, then you need to limit the total current of all segments so that the digit driver can handle it - your eight 2k2 resistors achieve that.

I was intending on multiplexing by digit and not by segment. If this is the case, don't I need to put the resistors before each segment?

Sorry if I'm being difficult here.

Here's what I'm thinking
For this example, let's just start with the A segment

1:Current flows out from a digital pin on the UNO and flows into the A pin on the display.

2: Then, ONE of the digit pins goes LOW, allowing current to ground through it.

This completes a fully lit up display for ONE digit, and you can do this for as many segments as you want.

3: Then for a 4 digit display, you just rapidly change the digit pin that you send low and the input pins that you send high to multiplex.

So then that means you would have eight resistors before each segment pin, just like the schematic above, right? That makes sense to me. I was intending on multiplexing by digit. Is that what I should do?

Yes. ShermanP was just musing that for a four digit display, multiplexing by segment actually allows you to use four fewer resistors! :grinning:

I would suggest using eight 1k resistors on the segments. It will likely be quite bright enough. This always remains nothing more than an amusing exercise; if brightness is actually a problem, you really should be going and purchasing a couple of the MAX7219 modules as they are simple to use and stunningly bright. :sunglasses:

Thank you very much!!