Trouble Using a 74HC595 Shift Register to display numbers on 2x 7 segment displays

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Hi there!

I'm making a project in which I'm building the PONG game. I've created the code necessary to program the matrix and the game itself (ball, players, etc.) however I'm running into some trouble figuring out what's wrong with my players' scores (everything else is going as expected).

I'm using an ATMega324 with 1x 74HC595 Shift Register and 2x 74LS47N chips. I built this circuit (the shift reg + decoders + 7 segment) like shown in the image below. I also used this code I found online (strictly, everything's the same):

 

    #define CLK   0                                                                                                                    // PB0: Shift Register pin 11 (Clock).
    #define S_IN  1                                                                                                                    // PB1: Shift Register pin 14 (Data).
    #define LATCH 2
        DDRB = 0x0F;                                                                                                                // PB0 - PB3 as outputs (buzzer + shift register) and last 4 pins defined as inputs (switches).

void shift_data(uint8_t data)
{
    uint8_t i;
    uint8_t bit;

    PORTB &= ~(1 << LATCH); //deactivate latch output

    for (i = 0; i < 8; i++)
    {
        PORTB &= ~(1 << S_IN);
        PORTB &= ~(1 << CLK);

        if (data & (1 << i))
            bit = 0x01;
        else
            bit = 0x00;

        PORTB |= (bit << S_IN);
        PORTB |= (1 << CLK);
    }

    PORTB &= ~(1 << CLK);  //set clock to zero
    PORTB |= (1 << LATCH); //activate latch output
}

void update_score(uint8_t score_p1, uint8_t score_p2)
{
    shift_data((score_p2 & 0x0F) | ((score_p1 & 0x0F) << 4));
}

I call this function right before the game starts (after inic) and update it with the line: update_score(0, 0);
Then, whenever a goal is scored, I use the line: update_score(score1,score2); beeing score1 and score2 counters that increment when the ball enters the net.

I already re-checked my circuitry and it all seems fine (though a bit clustered).

What happens is that instead of displaying the numbers properly (0,1,2,.....9), it shows some numbers right (1, 3, 4) but others wrong (0 looks like a 2 in one of the displays; 0 looks like an 8 in the other display; 7 has a lighted on segment which shouldn't be lighted on, etc.).

I'll also leave you with the 7 Segment Display pinout. Any help would be appreciated as I have no idea why this is happening (thought about beeing the shift_data() function that causes the error). Just missing this and can't understand the problem.

 

 

Last Edited: Thu. Jan 2, 2020 - 06:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Instead of trying to show numbers, did you first test each segment to ensure it works as expected? ..send out to light up sega only, then seg b only....test each segment to ensure you have nothing wrong.  A little miswiring can cause strange results.

You also show floating pin inputs on your driver chips...fix that!

Avcc needs connected to Vcc & you need some caps on the AVR power pins.  What happened to your gnd at pin 31?  You other chips seem to be lacking power caps.

A minor note...gnd should always point down, unless it is not possible to do so & likewise, Vcc should point up.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Jan 2, 2020 - 07:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your schematic is missing some bypass capacitors that are critical. I’d suggest you address that sooner than later.

Have you tested the 7447/ display combination to ensure they work correctly?

The code looks suspect, but I’m on a mobile device at the moment so i won’t go further down this path.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is the erroneous pattern deterministic or random? What is the CPU frequency?

 

You could try adding _delay_us(1) in the shift_data function BEFORE the clock's rising edge in order to increase the setup time margin. Maybe also add a delay before falling edge just to reduce clock frequency.

 

I once had a similar problem but I was driving a large amount (8 x 8 or so) of relays and AC light bulbs. Sometimes the pattern was slightly incorrect and I could never find a solution. I eventually just had the code repeat the call to the function that updated the shift register. After 2-3 calls the pattern would be correct and stable.

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
void shift_data(uint8_t data)
{
    uint8_t i;

    PORTB &= ~(1 << LATCH); //deactivate latch output

    for (i = 0; i < 8; i++)
    {
        PORTB &= ~(1 << S_IN);
        PORTB &= ~(1 << CLK);

        if (data & 1)
            {
             PORTB |= (1 << S_IN);   
            }

        data >> = 1;
        PORTB |= (1 << CLK);
    }

    PORTB &= ~(1 << CLK);  //set clock to zero
    PORTB |= (1 << LATCH); //activate latch output
}

I've simplified the code a little.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


avrcandies wrote:
Instead of trying to show numbers, did you first test each segment to ensure it works as expected?

but the  74LS47N chips do the translation from BCD to segments - so the AVR doesn't have individual control of the segments.

 

@ takashi83 - have you checked that the inputs to the  74LS47N chips are correct for the digits you want to display ?

 

 

takashi83 wrote:
it shows some numbers right (1, 3, 4) but others wrong

 

So draw up a table for all 16 possibilities showing which segments should be lit, and which actually are lit.

Then look for patterns - transposed segments, etc ...

 

jaksel wrote:
Is the erroneous pattern deterministic or random?

 

and do you get the same errors on each digit, or are they different?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

        PORTB &= ~(1 << S_IN);
        PORTB &= ~(1 << CLK);

        if (data & 1)
            {
             PORTB |= (1 << S_IN);   
            }

wouldn't that be better as

        PORTB &= ~(1 << CLK);

        if (data & 1)
            {
             PORTB |= (1 << S_IN);   
            } 
        else
            {
             PORTB &= ~(1 << S_IN);
            }

else you'll get a glitch?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


 

You have 'A' from the shift register connected to 'D' of the 74LS47;

and 'B' to 'C';

and 'C' to 'B';

and 'D' to 'A'.

 

Is that what you intended ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why don't you use the hardware SPI to load data into the shift register? Only the latch needs to be controlled by software.

It would just need exchanging some wires in port B.

 

Seems to me, this would be much simpler. Unless the objective is to write a bitbang SPI?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

takashi83 wrote:
I'm using an ATMega324 

That's not what the schematic shows!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0



74LS47N chips do the translation from BCD to segments 

That's a very good point!!...been many many years since using that style....instead, should let the micro control all the segments, then you can display whatever pattern you want.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
been many many years since using that

It was a whole different century!

 

surprise

 

let the micro control all the segments

Indeed: 2 of those shift registers would give individual segment control - and save 1 chip on the board!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
2 of those shift registers would give individual segment control - and save 1 chip on the board!

 

True, and 2 of them can be chained together, effectively giving a 16 bit shift register. The downside is that a lookup table with a 7-segment character set is needed. It's no big deal for someone with a bit of experience, for noobs, well, they need to learn, anyway, so might as well try it...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

is that a lookup table with a 7-segment character set is needed

what?  no lengthy set of cpi compares/if's/switch statements?...for many noobs, it's brute force all the way cool  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
a lookup table with a 7-segment character set is needed.

Hey - is it 2003 already:  http://www.8052mcu.com/forum/read/55866 ?!

 

laugh

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


avrcandies wrote:

is that a lookup table with a 7-segment character set is needed

what?  no lengthy set of cpi compares/if's/switch statements?...for many noobs, it's brute force all the way cool  

 

Brute Force can't match the Lvl. 2 Secret Technique: Lookup Table in this situation! It does need some Flash to be cast, and maybe even valuable Static if you don't have the PROGMEM Advanced Skill.

 

It's time I go to bed, not making sense anymore cheeky

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 

setting a bit that you wanted to be 0 does nothing-

PORTB |= (bit << S_IN);

post #7 has the correct way.

 

if PORTB is 0b00000010, PORTB |= 0<<1 changes nothing, even though you actually wanted to clear the bit.

 

 

https://godbolt.org/z/L3KLdw

or

https://godbolt.org/z/rtjYJX

 

Last Edited: Fri. Jan 3, 2020 - 11:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the original code that was the intention - ie it does nothing. The data port pin is cleared at the top of the loop. I thought that was a bit silly, so i offered my correction as well as avoiding variable bit shifts.

 

In terms of the glitch Awneil mentions, that should not cause an issue unless there's some bad interconnection method. Personally I'd write the code the same way as Andy mentioned.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>The data port pin is cleared at the top of the loop

 

I saw it but still missed that, my bad.