# 4-digit 7 Segment LED displaying numbers in the wrong order

I am a novice Arduino programmer and am currently having trouble with a SH5461AS 4-digit/7-segment LED when using it with an Arduino Uno. I have struggled to find an accurate datasheet/tutorial of any kind for this particular model (It is the LED without the colons in between digits 2 and 3) but I believe I have it figured out.

I currently have it going through a HC595 shift register but when I removed the register and connected the LED directly to the board the problem remained. My code below is with the shift register; I am displaying it this way because it is simpler to view and I thought it would make it easier to debug.

I can display a single digit at a time correctly. However, when I try to display 2+ digits at one time, they are in the incorrect order. For example, I can count 1-9 on the first digit, then 1-9 on the 2nd digit, and so on and everything displays correctly (other digits are off). But as soon as I try to display multiple digits they are in the wrong order. So if I try to display 12__ with the last 2 digits off, 21__ is displayed with the last two digits off. If I try to display 23, 32 is displayed. If I try to display 1234, 4123 is displayed.

I am at a loss because the code seems like it should be simple.

``````const int DATA = 0;
const int LATCH = 1;
const int CLOCK = 2;

const int DIGIT_ONE = 3;
const int DIGIT_TWO = 4;
const int DIGIT_THREE = 5;
const int DIGIT_FOUR = 6;

//digits[0-9] corresponds to the patterns for numbers 0 -> 9.
//Add 1 to the digits[X] to turn on the dot.
byte digits[] = {B11111100, B00011000, B01101110, B00111110, B10011010, B10110110, B11110010, B00011100, B11111110, B10111110};

void setup() {
pinMode(DATA, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(LATCH, OUTPUT);

pinMode(DIGIT_ONE, OUTPUT);
pinMode(DIGIT_TWO, OUTPUT);
pinMode(DIGIT_THREE, OUTPUT);
pinMode(DIGIT_FOUR, OUTPUT);

digitalWrite(DIGIT_ONE, HIGH);
digitalWrite(DIGIT_TWO, HIGH);
digitalWrite(DIGIT_THREE, HIGH);
digitalWrite(DIGIT_FOUR, HIGH);
}

void loop() {
writeDigit(DIGIT_TWO, 2);
writeDigit(DIGIT_THREE, 3);
}

/*
* Write a digit to the 4-digit 7-segment LED
* - digitPin corresponding to the pin on the LED to light up the correct digit.
* - number 0-9 to display on the LED
*/
void writeDigit(int digitPin, int number) {
digitalWrite(digitPin, LOW);

digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, digits[number]);
digitalWrite(LATCH, HIGH);

digitalWrite(digitPin, HIGH);
}
``````

So in this instance, I am expecting 23 but 32 is displaying instead.

I am also having trouble with some bleeding (I don't know what the correct term is) where some segments are very faintly glowing even though I am not doing it intentionally. This is a much smaller issue, however, than digits randomly in the wrong order.

If it would help, I can try to post the circuit diagram as well.

Here is a datasheet I found that seems a better macth for your display model (that's the datasheet for a display that I use):

This is the datasheet I directly got from my local supplier.

According to what you say, the problem does not seem to be a wiring problem.

It looks more like a timing issue:

``````void writeDigit(int digitPin, int number) {
digitalWrite(digitPin, LOW);

digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, digits[number]);
digitalWrite(LATCH, HIGH);

digitalWrite(digitPin, HIGH);
}
``````

The first issue when you call `writeDigit()` is that it forces the cathod low BEFORE having set the shift register, so the digit will first show the current register value, i.e. the one from the previous call to `writeDigit()`.

Then it pushes the new value for the segments on the shift register, that will be fast but not as fast as two consecutive calls to `loop()`.

If we try to roll and expand the `loop()` call in your example that will be:

``````// First call: writeDigit(DIGIT_TWO, 2)
digitalWrite(DIGIT_TWO, LOW);
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, digits[2]);
digitalWrite(LATCH, HIGH);
digitalWrite(DIGIT_TWO, HIGH);

// Second call: writeDigit(DIGIT_THREE, 3)
digitalWrite(DIGIT_THREE, LOW);
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, digits[3]);
digitalWrite(LATCH, HIGH);
digitalWrite(DIGIT_THREE, HIGH);
``````

The calls to `loop()` and `writeDigit()` are negligible in terms of timing here.

In the sequence above, most of the time is spent in:

``````  shiftOut(DATA, CLOCK, LSBFIRST, digits[2]);
shiftOut(DATA, CLOCK, LSBFIRST, digits[3]);
``````

So that means your function will:

1. show the previous value on the new digit for `t1 us`
2. show the new value of the new digit for `t2 us`

with `t1 >> t2`, hence your eyes will see the opposite of your intent!

To fix that issue you definitely need to introduce some delay to reverse what your eyes will see:

``````void writeDigit(int digitPin, int number) {
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, digits[number]);
digitalWrite(LATCH, HIGH);
digitalWrite(digitPin, LOW);
delayMicroseconds(100);
digitalWrite(digitPin, HIGH);
}
``````

In the code above:

• no digit shows while the shift register is set
• the requested digit shows immediately after the shift registry has been written and lacthed, and for a duration of 100us, which will be much longer than the rest of the time.

That code should also get rid of the "bleeding" you observed.

• Excellent, detailed answer; thank you! I will try that when I get home to see if it fixes it. Sep 17, 2014 at 17:59

I found the data sheet here:

It's a horrible bit of writing. Not at all clear.

It looks like it's multiplexed. You use pins 14, 16, 13, 3, 5, 11, 15, and 7 as the cathodes for the segments on a digit (ground the pins for the segments you want to light.) Pin 7 appears to be the decimal place for a given digit.

One of the pins 1, 2, 6, or 8 should be fed a +5V to light a particular digit.

The other pins control the colons and other dots on the display. Let's ignore those.

To light the display here's what I THINK you would do (I'm tired, and didn't study the data sheet that closely, so I may may be wrong here)

For pins 14, 16, 13, 3, 5, 11, 15, and 7: These are the cathodes for the segments in the current digit you are driving. Set the pins you want to light as digital outputs, LOW. Set the others as inputs, which will make them essentially open circuits. The selected pins will be grounded, and the ones set as inputs will not be connected to anything.

Pull pin 1 HIGH to light the selected segments in digit 1. Put it back low, set the segment pins, then pull pin 2 HIGH to light that digit. Repeat, pulling pins 6 and 8 high to light the selected segments in digits 3 and 4.

You'd have to cycle rapidly through the digits, lighting 1 at a time, in order to make them appear all lit at once.

Get that working first without using shift registers. (It will take 11 I/O lines to drive all 4 digits and their decimal places - 1 less if you don't care about the decimal place.)

I think that if your drive all the pins using a shift register then some of the unlit segments will be fed reverse voltage. (When set as an output, sending a LOW connects the output pin to ground, and setting it high drives it to 5V. With all the control pins driven from outputs of a shift register, the off segments will have 5 volts on them, and the off digit select pins will have ground on them.)

• That datasheet does not match the OP descriprion, it has a `:` in the middle. Sep 17, 2014 at 4:38
• Yup. I assumed it was a variation on the same item. Sep 17, 2014 at 11:15
• It is much more than a simple variation: the one used by OP is common cathode, while yours is common anode! Sep 18, 2014 at 21:02
• @jfpoilpret, it sounds like you found the correct data sheet. Why not post either the correct data sheet or an assessment similar to mine based on the specs for the correct display. Sep 19, 2014 at 0:07
• Well I guess the OP already understood how to use his display, so it was not necessary IMO to detail further the specs. As I said in my answer the main problem is in the code not the wiring. Sep 19, 2014 at 4:34

I don't have enough reputation to add a comment, but the datasheet link in @jfpoilpret is dead. This link has the datasheet from the same website.

Thanks.