4digit 7segment display with 74HC595, displays digits in wrong order

I've just started using Arduino and trying some basic examples and ran into a problem I can't solve early on... I have an Arduino UNO R3 and connected it to a common anode 4 digit 7 segment display (datasheet) and a 74HC595 shift register as is shown in the attached schematic. Then I ran this simple program to test it out:

#define LATCH_PIN 8
#define DATA_PIN  11
#define CLOCK_PIN 12

int curDigit = 0;

int digitPin[] = {2,3,5,7};
int value[] = {3, 159, 37, 13, 153, 73, 65, 31, 1, 9};

void setup() {
  // put your setup code here, to run once:
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(7, OUTPUT);

  Serial.begin(57600);
}

void loop()
{
  displayDigit(curDigit, value[curDigit]);
  curDigit++;
  curDigit %= 4;
}

void displayDigit(int digit, int value)
{
//  if(digit != 1) return;
  digitalWrite(LATCH_PIN, LOW);
  digitalWrite(digitPin[digit], HIGH);
  shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
  digitalWrite(digitPin[digit], LOW);
  digitalWrite(LATCH_PIN, HIGH);
  delayMicroseconds(100);  
}

I would expect it to print [color=red]3210[/color] but to my surprise it prints [color=red]2103[/color]! And to make it even more strange, if I uncomment the if in displayDigit and have it working with only one digit, then it prints it in the correct place. So, if that line is
if(digit != 0) return then 0 is displayed at the right most place on the display... If I change the pins in digitPin array to int digitPin[] = {7,2,3,5}; then the four digits are displayed correctly but the single digit is moved to the left most place instead of the right most one...

Can somebody help make sense of this thing?

Thanks in advance...

clock.png
Looked at it most carefully - I cannot see the problem. Only observation is that it should be in the order

 digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(digitPin[digit], LOW);

But that is minor.

Where is the definition and initialisation of curDigit?

From the data sheet:

Your schematic (+1 karma for posting one at all, and for using code tags) has the digit pins labelled D1 to D4, but there is no indication if D1 is on the left or right. In the data sheet the digit pins are 12, 9, 8, 6 from left to right.

the single digit is moved to the left most place instead of the right most one...

I don't understand why this surprises you. Arduino pin 7 is connected to the leftmost digit and pin Arduino pin 2 is connected to the rightmost digit.

So, if that line is
Code: [Select]
if(digit != 0) return
then 0 is displayed at the right most place on the display

That surprises me. I think you must have changed the wiring or code at some point and forgotten you did it. Can you reproduce that effect again?

6v6gt:
Where is the definition and initialisation of curDigit?

Thanks for pointing that out, it is simply a global int, initialized to 0, just omitted some comments and some other unused variables when copy/pasting. Will add it now to the original post.

Paul__B:
Looked at it most carefully - I cannot see the problem. Only observation is that it should be in the order

 digitalWrite(LATCH_PIN, HIGH);

digitalWrite(digitPin[digit], LOW);



But that is minor.

Thanks for taking the time! You are right about the order there will change it, but doesn't make any difference regarding my issue... Starting to wonder if it is a faulty display or something...

Another thing that surprises me is the data sheet. The colon dots are connected in parallel with the DP for digit 2. So I think there must be two variants of the display, one with the colon (maybe no DPs) and one without colon. Yet there are not 2 part numbers for those two variants (only 2 part numbers for CA & CC variants). How is the manufacturer to know which variant a customer wants to order without a part number for each type?

Problem is, your diagram refers to "D1" to "D4" on the display but gives no assurance you have used the correct actual pins.

And - omitting parts of the code makes it simply impossible to determine problems. :astonished:

Thanks for the taking the time with this!

PaulRB:
From the data sheet:

Your schematic (+1 karma for posting one at all, and for using code tags) has the digit pins labelled D1 to D4, but there is no indication if D1 is on the left or right. In the data sheet the digit pins are 12, 9, 8, 6 from left to right.

The part of the datasheet you have quoted shows that DIG4 is the right-most digit of the display and is powered by pin 6 of the display. I have that wired to D2 of UNO and in the code declared as digitPin[0]. So I would expect, when trying to display 3210 to have 0 at the right most digit. However I get that on the second digit from the right (2103).

PaulRB:
I don't understand why this surprises you. Arduino pin 7 is connected to the leftmost digit and pin Arduino pin 2 is connected to the rightmost digit.

It surprises me because it is correct behavior when displaying one digit but incorrect when displaying the four digits.

PaulRB:
That surprises me. I think you must have changed the wiring or code at some point and forgotten you did it. Can you reproduce that effect again?

It is reproducible every time. If I comment out the if, I get "2103". If I un-comment it, I get "_ _ _ 0". I would expect it to be "_ _ 0 _" in order to be consistent...

Paul__B:
Problem is, your diagram refers to "D1" to "D4" on the display but gives no assurance you have used the correct actual pins.

Not sure what you mean... DIG4 of the display is connected to D2 of the Arduino. I can post a picture of the actual breadboard to show you if needed.

Paul__B:
And - omitting parts of the code makes it simply impossible to determine problems. :astonished:

Agreed, it was certainly not my intention... But I can assure you, the code I now have in the post, is the exact code in the Arduino and it is working as described.

You said this is a common anode display. So the 74hc595 pins are sinking current from the cathodes/segments and the Arduino pins are sourcing current to the anodes/digits.

void displayDigit(int digit, int value)
{
//  if(digit != 1) return;
  digitalWrite(LATCH_PIN, LOW);
  digitalWrite(digitPin[digit], HIGH);
  shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
  digitalWrite(digitPin[digit], LOW);
  digitalWrite(LATCH_PIN, HIGH);
  delayMicroseconds(100); 
}

In this code, the Arduino pin is only high while the data is being shifted out. Just before you latch the data, you set the pin low again. So the digit is only on for a very brief time (the time it takes to execute shiftOut()) and at that point, the data you want to display on that digit has not been latched yet, so what appears is the data that was previously loaded into the shift register, the data for the previous digit. If you limit the code to only 1 digit, this does not matter, but as soon as you allow all 4 digits, each is showing the pattern intended for the previous digit.

Try this:

void displayDigit(int digit, int value)
{
//  if(digit != 1) return;
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
  digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(digitPin[digit], HIGH);
  delayMicroseconds(1000); 
  digitalWrite(digitPin[digit], LOW);
}

I looked at that as being the problem, considered that it was a common anode display and had convinced myself that it was correct!

Should actually be:

  digitalWrite(LATCH_PIN, LOW);
  digitalWrite(digitPin[digit], LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
  digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(digitPin[digit], HIGH);
  delayMicroseconds(1000);

or:

  shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
  digitalWrite(LATCH_PIN, LOW);
  digitalWrite(digitPin[digit], LOW);
  digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(digitPin[digit], HIGH);
  delayMicroseconds(1000);

Given that the latch output only changes on the rising edge of LATCH_PIN. :grinning:

also, try adding this to end of setup() just to check that the magic numbers in the array are correct.

for ( byte i = 0 ; i < 10 ; i++ )  { 
   Serial.println (i ) ;
   displayDigit( 0, value[ i ] ) ;
   delay( 2000 ) ;
}

PaulRB:
Try this:

void displayDigit(int digit, int value)

{
//  if(digit != 1) return;
 digitalWrite(LATCH_PIN, LOW);
 shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
 digitalWrite(LATCH_PIN, HIGH);
 digitalWrite(digitPin[digit], HIGH);
 delayMicroseconds(1000);
 digitalWrite(digitPin[digit], LOW);
}

Yeap, you nailed it! Working now! Thanks!