2012-07-21

Raspberry Pi 7 segment displays

This post shows how to drive two 7 segment displays from 6 gpio pins on the Raspberry Pi without a continual refresh loop. The software is simple with very low cpu usage - only processing when you want to change the displayed numbers. The electronics are pretty easy too (I'm a novice myself!) It's also a fun way to learn about BCD (Binary-coded decimal) and latches.

Hardware

To put this together I've used:
Basically you take 6 gpio pins through current limiting resistors and then on to the second breadboard. You'll see from the picture below that I have added an LED as a confidence indicator for each gpio pin. I've labelled these in the picture for the latches and data lines that then need to be wired up to the HEF4543Bs:
If you look at the data sheet for the HEF4543B you'll see that the labels I've put on this picture match. These  labels are also used in the software later.
  • LD = Latch disable (for first digit)
  • DD = 8 (BCD bit)
  • DC = 4 (BCD bit)
  • DB = 2 (BCD bit)
  • DA = 1 (BCD bit)
  • LD2 = Latch disable (for second digit)
The gpio pins for the latches are then connected directly to the two ICs, The data pins are connected in parallel to both ICs:
Now follow the data-sheets for the ICs and the displays to connect the IC output pins to the 7 segment displays. The phase input (PH) and the blanking input (BI) should both be connected to ground. I left a longer loop of wire on the blanking input as I was considering using it to blank the display but this would have used another gpio pin. Instead, if you check the data-sheet, you'll find that if you set the data to a decimal number higher than 9 it will blank the display anyway.
Note, this is all 3.3v and I've used another couple of 220ohm resistors to limit the current into the ICs.

Software

To set a number on the display you follow this sequence:
  1. Keep what's on the display now - latch disable = off
  2. Set the data pins for the required number
  3. Disable the latch to take the value to the display - latch disable = on
  4. For timing purposes wait for a short period
  5. Keep what's on the display now - latch disable = off
The Python below counts from 0 to 99 in a continuous loop as seen in the video above.
'''
Created on 7 Jul 2012

@author: Jeremy

numdisplay - counts from 0 to 99 in a loop using two 7 segment displays

Read the blog entry at http://jeremyblythe.blogspot.com for more information
'''
import time
import RPi.GPIO as GPIO


LD = 13
DD = 12
DC = 11
DB = 15
DA = 16
LD2 = 18


GPIO.setup(LD, GPIO.OUT)
GPIO.setup(DD, GPIO.OUT)
GPIO.setup(DC, GPIO.OUT)
GPIO.setup(DB, GPIO.OUT)
GPIO.setup(DA, GPIO.OUT)
GPIO.setup(LD2, GPIO.OUT)

def write_gpo(pin,state):
    GPIO.output(pin,state)

last_tens = None
    
def write(tens,units):
    global last_tens
    if last_tens != tens:
        #tens
        #keep what's on the display now - latch
        write_gpo(LD,False)
        write_digit(tens) 
        #disable the latch to take the value to the display
        write_gpo(LD,True)
        time.sleep(0.1)
        #keep what's on the display now - latch
        write_gpo(LD,False)
        last_tens = tens

    #units
    #keep what's on the display now - latch
    write_gpo(LD2,False)
    write_digit(units) 
    #disable the latch to take the value to the display
    write_gpo(LD2,True)
    time.sleep(0.1)
    #keep what's on the display now - latch
    write_gpo(LD2,False)
         
    
def write_digit(digit):    
        if digit == None:
            #blank
            write_gpo(DD,True)
            write_gpo(DB,True)
        else:
            if digit & 8 > 0:
                write_gpo(DD,True)
            else:
                write_gpo(DD,False)
            
            if digit & 4 > 0:
                write_gpo(DC,True)
            else:
                write_gpo(DC,False)
            
            if digit & 2 > 0:
                write_gpo(DB,True)
            else:
                write_gpo(DB,False)
                
            if digit & 1 > 0:
                write_gpo(DA,True)
            else:
                write_gpo(DA,False)

if __name__ == '__main__':
    t = 0
    u = 0
    while True:
        u=u+1
        if u > 9:
            t=t+1
            u = 0
        if t > 9:
            t = 0
        write(t,u)

        
On my live site (http://jerbly.uk.to/picam) you can enter a number that you want to send to the display. Here's the code to achieve that using the Flask web framework:

'''
Created on 8 Jul 2012

@author: Jeremy

numweb - writes the incoming 2 digit number to a pair of 7 segment displays

Read the blog entry at http://jeremyblythe.blogspot.com for more information
'''
import numdisplay
from datetime import datetime

from flask import Flask
app = Flask(__name__)

@app.route("/num/")
def num(number=None):
    if number == None:
        numdisplay.write(None, None)
    else:
        n = number % 100
        u = n % 10
        t = (n-u) / 10
    numdisplay.write(t, u)
    log(number)
    return "OK"

def log(number):
    with open('/tmp/numweb.log','a') as f:
        f.write('%s - %s\n' % (str(datetime.now()),number))

if __name__ == "__main__":
    app.run('0.0.0.0',8092)

This uses numdisplay.py and adds a very simple web interface. Run this up and go to http://{ip address}:8092/num/{number}. e.g. http://192.168.0.2:8092/num/12 to display 12.

Kits

I'm considering putting some kits together with the resistors, ICs and displays for people to buy if there's enough interest. It may turn out to be more cost effective if I buy some in bulk and then sell on to you. Let me know if you would be interested by leaving a comment below. Thanks.

21 comments:

Mr Routledge said...

Loving the tutorial. Getting back into electronics after a Loooong break. Had one or two issues. But your ideas are inspiring me!!! Line 43 in your first section of code is redundant, infact if you leave it the same as line 54 and set the both to 1 sec (for testing purposes) you'll see it count to 9,19,10 or 19,29,20. I just removed the line and the count works fine. I would have bought a kit if one available, would have saved me 3(!!!) trips to Maplins! Keep up the tutorials I'm off to try some of your others!!!!

Mr Routledge said...

Trying out the second tutorial. Got all the code inserted etc. (I know nothing about FLASK) but installed it via 'aptitude', when I run the script it error on app.run(host='0,0,0,0',8092)

The pointer indicated it's not happy about the bit any suggestions?

Mr Routledge said...

Dammit, that just stripped the <> but out of that... I think that's the error.

Mr Routledge said...

/int:number

jerbly said...

Maybe you've got a really old version of flask installed via apt. I use pip to install all python packages. Basically what it's doing is ensuring that the last part of the url is an integer so the <int:number> will take what you've put in the url and put the integer at the end into the variable called 'number'.

Anonymous said...

Would you know how to do this WITHOUT the BCDs??? Love it great!

Mr Routledge said...

Jeremy despite my best efforts I have not found a decent guide on using PIP, everything mentions using virtual installer. I dabbled with this, but did not get very far. Which distro were you using, Debian Squeeze or Wheezy (Raspbian). You help is greatly appreciated.

jerbly said...

I'm lucky enough to have two raspberry pis. I'm running Arch on the main one (for this experiment) and the latest Raspbian on the other one. Under Raspbian just type: pip install flask. Help is available through: pip -h

Mr Routledge said...

Jeremy, I too have 2 Pi's and hoping to get 5 more for school (secondary). If I try 'pip install flask' (which I had tried) in Raspian from the LXTerminal it just tells me that 'bash: pip: command not found'.

Do I have to install something first? Maybe update my sources or something. I'm a bit rusty on the programming front and haven't tried anything electronic (on protoboard) since AS Level Electronics (back in '95!)! Thanks for the inspiration and support. I may be brave and give ArchLinux a go. Raspian seems grumpy about booting with the GPIOs connect anyway!

jerbly said...

You'll have to install pip first. Use apt-get on Raspbian or pacman on Arch. The package will most likely be called pip or python-pip. On Arch the default is python 3 so to get the version 2 pip it's simply pip2.

Mr Routledge said...

Jeremy, THANKS!!! I finally got it working. As you suggested I got PIP installed and then went from there. (can't remember whether I used GPIO 3 or version 2) However in your code at the end (line 33) on the second section I had to omit the 'int:number' as this generated errors. I also found through a long process of testing (using humble PRINT statements etc) that you must turn number into and 'int(number)', it was calling the numbdisplay but failing on the write routine (working out tens and units). I rewrote my code a little to just make it pass a single integer, the numdisplay then works out the tens and units!!! Thanks for all your help and maybe these comments will help someone else trying your test. P.S. Once I'd sorted out my router I got my friend to change the digits... a very big bang moment!!!

jerbly said...

Glad you got it working. The int:number in the @app.route recorator is causing confusion here mostly because it's being stripped out or fiddled with by various bits of JavaScript on this blog. When I get a moment I'll put this on git so it can be downloaded raw. If you have int:number it will convert to an int for you so you don't need to code that. It will also reject non integer URL requests. So it is very useful to have there.

crease said...

This is a great tutorial and just what I need to progress. I think I have worked out the circuit but there are a few connections I would like to check before wiring up just in case it goes kaboom. Just wondered if you could post your wiring diagram?

Also, I read all about protecting the pi from overload, I couldnt see any on your circuit - am I missing it??

Mr Routledge said...

Crease is this any use to you.

https://docs.google.com/open?id=0BxzgirLSsCj7bm1YSmhIT0VhRUk


The 3.3v you're using will not harm the Pi you'll be fine just follow the tutorial. Works like a charm.

crease said...

Perfect, thanks.

Unknown said...

Jeremy, first of all, Thank you very much for sharing this with us all. This is GREAT!

Question: Since pin #3 and #8 on the Digital Display are a common cathode and they are connected internally, it would not be necessary to connect each one to the ground as you have done correct? Or am I wrong. I'm just trying to figure this stuff out since I'm a noob.

Unknown said...

What are the two switches used for in the video?

jerbly said...

@Tim Gaines - I expect you're right about the common cathode. I just connected it all up. In the video the two buttons are from another project and not used here.

GeekTeacher said...

I'd be interested in a kit if you can buy in bulk and make it cheaper for the parts. Thanks, Martyn
martyn dot jones at yahoo dot com

Ronie said...

Any schematic for this please

Ronie said...

I am using 4 inches 12V driven common cathode 7 seg displays. Any points to remember ?