Nov 162015
 
RasPiO 7 segment display kit

Last week I bought some 4-digit, 7-segment displays to experiment with. Strangely enough it was something I’d never tried before, so I was interested to see how they work. I googled around looking to see if someone else had done this before. It seems there are several different sorts of 7-segment displays, so you have to find a good match for the one you’ve bought.

You can get them in various guises including: i2c backpack; 12 pins; 16 pins; resistors built-in; common anode; common cathode etc.

The ones I bought are 12 pin, bare, no backpack, no PCB, no resistors, common cathode. Here’s what they look like…

7-segment display

7-segment display

7-segment display - rear

7-segment display – rear

No Datasheet? Google Is Your Friend.

There was no datasheet, so I had to dig around for information. I found two really useful pages which gave me all I needed to know. One was on the Parallax website, which gave me the pinouts, from which I’ve made my own pinout diagram showing the pin numbers and what they do…

Common cathode 4-digit 7-seg pinouts

Common cathode 4-digit 7-seg pinouts

How Does It Work?

If you connect pin 12 to GND, the first digit will activate (9 = second, 8 = third, 6 = fourth).

Bringing each of the other 8 pins HIGH activates a specific segment on all currently active digits.

So if we had 12, 9, 8 & 6 all connected to GND, and 7 & 4 HIGH, all four digits would display the number 1.

But How Can We Use That? It’s Impossible?

The way that you get each digit displaying something different is to switch them on and off again, in turn, faster than the eye can observe. Using the same circuitry to control more than one ‘thing’ is called multiplexing. We need some Python code to handle this for us, and we’ll do it using 12 of the Pi’s GPIO pins (4 to switch the digits and 8 to switch the segments).

We also need some current-limiting resistors. 330 Ohm works, but is a bit dim. I’ve opted for 100 Ohm, which gives the LEDs a little protection. In reality, we’re switching fast, so each segment should only be ON for a short time. But if you connect these segments directly to a 3V3 source off-Pi without current-limiting resistors, you will damage or kill the leds in the segments (yes of course I tried it).

OK Let’s Wire It Up!

Here are the connections you need to make…

Wiring connections for common cathode 7-segment display

Wiring connections for common cathode 7-segment display

Wiring Diagram for 7-segment display

Wiring Diagram for 7-segment display

This is what my finished setup looks like (not quite as pretty as the diagram)…

RasPiO 7-segments display clock

RasPiO 7-segments display clock

I used one of my RasPiO® Breakout boards and a 170 point mini-breadboard to wire up the 7-segment display. This means you can do all the wiring “off-Pi” and then attach the project all at once. For a 12-wire project, this is extremely useful. I wired it directly to the Pi the first time, but when I wanted to re-order the wiring, I found it much easier to use the RasPiO® Breakout. It’s also easy to detach from the Pi without undoing and messing up all the wiring.

What About The Code?

The other useful web page I found was a post in the Raspberry Pi Forums, where Bertwert had published a Python script to turn one of these displays into a clock. That looked like a fun way to test out the new toys, so I gave it a try. I very carefully wired everything up exactly according to the instructions, but only one digit was lit. I checked my wiring. It looked sound. I had another look and eventually realised that the code posted in the forum had messed up indents.

This is one of the hazards of cutting and pasting code, and particularly Python. What it meant was that only one digit was being processed, the others were being passed over. Adding a few well-placed indents helped this to work correctly. There was also a missing colon in the code that caused it to throw an error. As you do, I posted back my amended code for future followers of that thread.

I also tweaked it to eliminate a redundant line, converted it to use BCM GPIO numbers and changed the wiring to make it logical for my chosen layout. The code is posted below…

# code modified, tweaked and tailored from code by bertwert 
# on RPi forum thread topic 91796
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)

# GPIO ports for the 7seg pins
segments =  (11,4,23,8,7,10,18,25)
# 7seg_segment_pins (11,7,4,2,1,10,5,3) +  100R inline

for segment in segments:
    GPIO.setup(segment, GPIO.OUT)
    GPIO.output(segment, 0)

# GPIO ports for the digit 0-3 pins 
digits = (22,27,17,24)
# 7seg_digit_pins (12,9,8,6) digits 0-3 respectively

for digit in digits:
    GPIO.setup(digit, GPIO.OUT)
    GPIO.output(digit, 1)

num = {' ':(0,0,0,0,0,0,0),
    '0':(1,1,1,1,1,1,0),
    '1':(0,1,1,0,0,0,0),
    '2':(1,1,0,1,1,0,1),
    '3':(1,1,1,1,0,0,1),
    '4':(0,1,1,0,0,1,1),
    '5':(1,0,1,1,0,1,1),
    '6':(1,0,1,1,1,1,1),
    '7':(1,1,1,0,0,0,0),
    '8':(1,1,1,1,1,1,1),
    '9':(1,1,1,1,0,1,1)}

try:
    while True:
        n = time.ctime()[11:13]+time.ctime()[14:16]
        s = str(n).rjust(4)
        for digit in range(4):
            for loop in range(0,7):
                GPIO.output(segments[loop], num[s[digit]][loop])
                if (int(time.ctime()[18:19])%2 == 0) and (digit == 1):
                    GPIO.output(25, 1)
                else:
                    GPIO.output(25, 0)
            GPIO.output(digits[digit], 0)
            time.sleep(0.001)
            GPIO.output(digits[digit], 1)
finally:
    GPIO.cleanup()

There’s a full code walk-through in the comments below.

Want To Have A Go?

If you’d like to have a go at this project, I have a limited number of kits available for £12 including global shipping. Here’s what’s in the kit. Pick yours up today and start playing with 7-segment displays on your Pi…

RasPiO 7-segments display tinkering kit

RasPiO 7-segments display tinkering kit



RasPiO 7-segments kit including global shipping





The system accepts PayPal or any credit/debit card too. There are no extra hidden charges and you don’t need a PayPal account.

In the next article, we use this 7 segments kit to make a countdown ticker.

  45 Responses to “How to drive a 7 segment display directly on Raspberry Pi in Python”

  1. Hi Alex – I have ordered the kit and look forward to tinkering with it. In the meanwhile, is it possible to get a detailed explanation of what the code does? In particular, the time.ctime()[11:13] etc parts are beyond me.
    Many thanks and keep up the good work. KC

    • Hi Kieran.

      Good point. When I write my own code I usually do a full walk-through don’t I? ctime() is a new one on me also, but I’ll look it up. I didn’t tweak Bertwert’s code much, just mainly switched it from BOARD (which I don’t use) to BCM which I do and changed the wiring.

      Your kit is about to go in the post :)

    • Here’s a code walkthrough…
      lines 3-5 import required libraries and set BCM mode
      lines 8-13 define and set up the 8 ports for the LED segments
      lines 15-21 define and set up the 4 ports for digits
      lines 23-33 create a dictionary to hold the values for each segment to display each number 0-9 and null
      lines 35-50 are wrapped in a try: finally: block to catch any errors or exceptions and clean up the GPIO ports on exit
      lines 36-48 contain the main program loop which carries on until we terminate with CTRL+C or some error/exception occurs
      line 37 time.ctime() give us the current time in the form: ‘Mon Nov 16 14:11:05 2015’
      time.ctime()[11:13] gives us a ‘slice’ of this output starting at the 11th character and stopping at, but not including, the 13th. This gives us the hour.
      In the same way, time.ctime()[14:16] gives us the minute. Together, the whole expression n = time.ctime()[11:13]+time.ctime()[14:16] gives us a string variable, n containing the current hour and minute values.

      line 38 s = str(n).rjust(4) since the output of ctime() is a string, the str() is redundant (I didn’t spot that before). n is already a string variable. rjust(4), as you might guess from the name, right justifies our string, n and pads it with space characters as required (not in this case). So now we have a string variable, s, containing our four figure value of current time: 1411

      lines 39-48 iterate through each digit in turn, left to right.
      lines 40-45 determine which LED segments should be switched on, then 46-48 cause the current digit’s enable pin to be grounded for a millisecond. So each of the active segments will display on the current digit. Then the loop iterates round the other digits, before going back to the start of the main loop and checking the time again.

      lines 40-45 iterate through the segments to set up the ports to display each number.

      line 41 GPIO.output(segments[loop] sets the current segment’s port according to the value it finds in the dictionary we created earlier num[s[digit]][loop] looks horribly complex, but let’s break it down. For each port we want a 0 or a 1 to turn it on or off.

      We have all the correct values stored in our dictionary num. We have our four digits stored in variable s and our current loop counter digit tells us which of the four digits we want. so num[s[digit]] looks in our dictionary num for the nth figure in s, which will be a string value 0-9. With me so far?

      A Python dictionary works as a key:value pair. So, num['9'] will output the values corresponding to ‘9’. We don’t want them all though, so we add [loop] to cut it down to just the specific segment we want right now in this loop iteration.
      So the output from num[s[digit]][loop] will be a single integer value 0 or 1, which is used to switch the corresponding GPIO port for the current segment Off or On.

      lines 42-45 control the flashing ‘dot’ which remains on for even seconds and off for odd seconds, giving an indication of the passage of seconds.

      lines 46-48, as already mentioned, these cause the correct digit to be enabled for a millisecond so that its value can be displayed, before going onto the next digit.

      49-50 ensure a clean exit when the program terminates for any reason (in conjunction with line 35 try:)

    • time.ctime() returns a string, like this:

      ‘Mon Nov 16 22:08:00 2015′

      So time.ctime()[11:13] would the hour, i.e. ’22’
      and time.ctime()[14:16] would be the minute, i.e. ’08’

      All the Best
      Julian N.

  2. Nice article Alex. I’m sure I have one of these in my bits box somewhere. I was going to attempt to use it with a MAX7219 following a previous article you wrote, but this looks like a simpler way of doing things.

    • They’re lots of fun. I’m refactoring the code and am going to do something else with it soon :) I realised after David Meiklejohn tweeted at me this morning, that Bertwert’s code could be somewhat condensed, which also makes it easier to understand.

      You know what it’s like with your robot series. Once you get into something fun/interesting, you have to keep tinkering until you can make it dance how you want :)

  3. Got a number of suggestions I could make to the Python code here, but rather than wade in I’m going to wait until my 7-segments kit turns up so that I can check my improvements actually work on real hardware first ;-)

    For now, I’ll just suggest that the seconds-indicator-code
    if (int(time.ctime()[18:19])%2 == 0) and (digit == 1):
    GPIO.output(25, 1)
    else:
    GPIO.output(25, 0)

    could be placed above the
    for loop in range(0,7):
    line. No need to run the same thing 7 times!

    • Haha Andrew. I’ll be making some changes myself in tomorrow’s blog. I’ve made several tweaks. (Yours is in the post now so should be with you in a day or two.)

  4. Looks like what I did last year:
    http://www.instructables.com/id/Controlling-a-7-segment-4-digit-display-with-a-Ras/
    https://www.raspberrypi.org/forums/viewtopic.php?f=37&t=91796

    Great minds think alike, we both described the resistors with a chart: “Pin -> Resistor -> Pi”

    Great job!

  5. I got one and it worked first time – it’s painful connecting all the wires though! Great idea.

    Is it possible to,get a white display though instead of the red

  6. Hi Alex,
    Love the kit and I’ve placed an order for it. I’m a horticulture student and looking at raspberrys for temp/humidity/ EC sensors. I’m hoping I can tie in the display with a hygrometer sensor I have on its way to me. My idea is to have the sensor connected to a pi with a display to show current readings, but also have it internet connected so real time readings can be taken, also have alerts sent by email if certain parameters (e.g. soil gets to dry) are breached . My only problem is I have no clue when it comes to coding. Can you help or guide me at all?
    Regards,
    Rob.

    • I’ll offer my usual tips: start small, work on one small piece at a time, gradually work your way up; don’t dive in at the deep end and try to tackle everything at once.
      The old “learn to walk before you try running” ;-)

      IMHO the Raspberry Pi forums http://www.raspberrypi.org/forums/ are a much better place to ask for the kind of help you’re looking for.

  7. Hi,

    Would this kit work for the Raspberry pi 2?

    Best,

    Austin

  8. Hey, nice tutorial
    One question: What kind of resistors are you using (in terms of ohm)?

  9. Hello again,
    I’ve got some C code which provides me with a variable containing the room temperature (measured by a sensor connected to RPi). Now i want that value to be displayed on the 7 segment 4 digit display. Is there any possibilty to implement Python into C or to compile Python into C?

    • What sensor are you using? If it’s a common one, there’s a good chance there’s already been a Python module or sample code written to read it.

      Alternatively if your sensor-code is *only* available in C, what I’d do in your situation would be to write a small ‘wrapper’ C program (i.e. compile it to a standalone executable) which when called simply prints out the current sensor value. And then from within your python code, call the external executable using https://docs.python.org/2/library/subprocess.html and read its output.

      Or you could go the other way round, and use http://wiringpi.com/ to control the GPIOs driving the 7-segment display directly from your C code…

  10. Dear Alex,

    I recently bought from you the kit. Do you know if a can show a python string in the segments?, I have now something like this:

    myFile = 'youtubesubs.txt' # this calls the text file

    myFile = open(myFile, mode= 'r') # opens in readmode
    # read all file contents
    lastLine = myFile.readlines()[-1] # read the last line

    n = 6 # splits the string each 6 characters
    splitted = [lastLine[i:i+n] for i in range(0, len(lastLine), n)]
    print(splitted[0])

    That prints this string on the console:

    2.183

    Thank you!!

    • It should be possible if you feed your variable splitted[0] into variable n on line 37 instead of the time. But the decimal point might need some extra code to sort it out.

  11. Hi! do you know if I can add a ‘.’ in the dictionary to by able to show numbers like this?: 2.234. I received the kit today, all working perfectly, thank you :-)

  12. It’s fairly easy to convert this to a common anode display like the one I bought.

    Essentially, you put 1’s where all the 0’s are :-)

    My swapped version of the software is here: https://github.com/JulianNicholls/Raspberry-Pi-Misc/blob/master/python/gpio/4x7seg-ca.py

    If you have any questions or want other help, reply here.

  13. Here is mine finished!! Counting youtube subscribers. I’m looking for made another one but with 8 digits, any ideas how to start? I’m not sure if I have enough room in the gpio for another 4 digits :-S

    https://www.dropbox.com/s/5jibk65d2w4rosk/File%2002-03-16%2011%2027%2059.jpeg?dl=0

    • The way that multiplexing works, means that to add another 4 digits (to expand it from 4 digits to 8 digits) only needs another 4 GPIO lines :-)
      Using the pin-numbers from Alex’s photo above (and assuming your 4-digit 7-segment displays are identical) you’d simply connect each of the LED-pins 1,2,3,4,5,7,10,11 together in parallel, and then the LED-pins 6,8,9,12 from each display would connect separately to different GPIO pins on the Pi (using 8 + 4 + 4 = 16 GPIOs in total).
      And then you’d simply modify Alex’s code above to make the Pi think it’s talking to a single 8-digit 7-segment display.

  14. Is there a way to output a 12 hour as opposed to a 24 hour clock?

    • yes – without actually looking at the code (using my phone at the moment), find the bit which deals with hours and then do a simple if statement something like this…

      if hours > 12:
          hours = hours - 12

      (I’ve given a method here without spoon-feeding the code – having now looked at the code it is a bit more involved.)

      • Thanks. I’ll try my best to make it work. I’m building a controller for large 12v LED digits. Each one is in its own 18″x24″ frame and I’m using seconds also, for a total of 6 digits. So there will have to be a lot of modifying of this design. But I think it’ll work. My biggest concern is running the 12V LED’s from a second power source and with a common ground. I don’t think the raspberry pi can handle that much current on its own.

  15. Hi guys,

    I’m trying to follow your tutorial and i’m stuck at this point. It prints the last number sended on each digit. I can decide to print or not on each digit but i can’t control the displayed number.

    For example : string_display = “1234”;
    digit to prints = [0,2]
    Will display:

    | 4 | | 4 | |

    Any ideas ?

    • Without seeing your full code, it’s impossible to know what’s going wrong. But what you _could_ try is:

      string_display = '1234'
      digits_to_print = [0, 2]
      new_chars = [' '] * len(string_display)
      for d in digits_to_print:
          new_chars[d] = string_display[d]
      
      new_string = ''.join(new_chars)
      

      which would give you a new_string of ‘1 3 ‘ which you can then display using Alex’s code above.

  16. Hi AndrewS and thank you for your time ! :)

    I tried the python clock and the python ticker ( just inverting 0 and 1 in the library )

    As is, it will display numbers faster than my eyes can read it.
    So, i’ve just added a small sleep between each draw

    and in both cases, it displays always the same number on each digit.

    my 7segment ref is “3641BS” ( actually not the same as in the tutorial )

    Any ideas ?

    here’s my code (sorry for this, i didn’t reach the “code” button ) :

    # code modified, tweaked and tailored from code by bertwert
    # on RPi forum thread topic 91796
    import RPi.GPIO as GPIO
    import time
    GPIO.setmode(GPIO.BCM)

    # GPIO ports for the 7seg pins
    segments = (11,4,23,8,7,10,18,25)
    # 7seg_segment_pins (11,7,4,2,1,10,5,3) + 100R inline

    for segment in segments:
    GPIO.setup(segment, GPIO.OUT)
    GPIO.output(segment, 0)

    # GPIO ports for the digit 0-3 pins
    digits = (22,27,17,24)
    # 7seg_digit_pins (12,9,8,6) digits 0-3 respectively

    for digit in digits:
    GPIO.setup(digit, GPIO.OUT)
    GPIO.output(digit, 1)

    num = {‘ ‘:(1,1,1,1,1,1,1,1),
    ‘0’:(0,0,0,0,0,0,1,1),
    ‘1’:(1,0,0,1,1,1,1,1),
    ‘2’:(0,0,1,0,0,1,0,1),
    ‘3’:(0,0,0,0,1,1,0,1),
    ‘4’:(1,0,0,1,1,0,0,1),
    ‘5’:(0,1,0,0,1,0,0,1),
    ‘6’:(0,1,0,0,0,0,0,1),
    ‘7’:(0,0,0,1,1,1,1,1),
    ‘8’:(0,0,0,0,0,0,0,1),
    ‘9’:(0,0,0,0,1,0,0,1),
    ‘B’:(1,1,0,0,0,0,0,1),
    ‘y’:(1,0,0,0,1,0,0,1),
    ‘E’:(0,1,1,0,0,0,0,1),
    ‘1’:(0,0,0,1,0,0,0,1),
    ‘L’:(1,1,1,0,0,0,1,1),
    ‘X’:(1,0,0,1,0,0,0,1)}

    try:
    while True:
    n = time.ctime()[11:13]+time.ctime()[14:16]
    s = str(n).rjust(4)
    for digit in range(4):
    for loop in range(0,7):
    GPIO.output(segments[loop], num[s[digit]][loop])
    if (int(time.ctime()[18:19])%2 == 0) and (digit == 1):
    GPIO.output(25, 1)
    else:
    GPIO.output(25, 0)
    GPIO.output(digits[digit], 0)
    time.sleep(0.001)
    GPIO.output(digits[digit], 1)
    time.sleep(0.3)
    finally:
    GPIO.cleanup()

  17. Hi Alex

    For my own clock project, which I’ll document when it’s done, I’m using this display which has a colon (to flash the seconds). It has 14 pins – the two extra ones are for the colon and the other twelve match exactly the display you have above, which makes life easy.
    http://www.ebay.co.uk/itm/4-digit-7-segment-red-common-cathode-clock-display-0-56-/131308401635?hash=item1e929733e3

Leave a Reply