Friday, 17 May 2013

Messing about with 7 segment displays and a PIC 16F628a

I scored a load of cheap 4-way 7-segment displays off eBay the other day. They worked out at about 30p each so I got 20 and stuffed them in a drawer. Then I thought that perhaps it'd be nice to get one working, just so that we know what to do with them in future projects (one already springs to mind).


So here's a simple 4-way 7-segment LCD display hooked up to a PIC 16F628a microcontroller. We're running the PIC off it's own internal oscillator (there's nothing time critical going on here) and will use a simple direct drive method to make them light up.



Basically this means we'll light one digit it a time - lighting the appropriate segments of each character in a 4-digit number and waiting a few milliseconds before moving on to the next. Persistence of vision will give the illusion that all characters are illuminated at the same time.

These particular 7-segment displays have  a common anode - each digit shares the same "power" supply and we need to pull different pins to ground to get the different segments to light up. The display also includes decimal point characters and a double-dot (colon) character for use with digital clocks and so on.






While you can use a driver chip (like a MAX7219) or even a shift register or two to display the digits on these, it's easy enough to drive them directly from the i/o pins. Eight segments and 4 characters means 12 pins are needed to display all four characters at a time.

As ever, we're using Oshonsoft PIC Simulator to write the code in BASIC and using the keyword SYMBOL to assign a descriptive word to an i/o pin. This is really handy because when it comes to laying out your circuits on a PCB, sometimes you need to flip pins around to simplify the layout. Instead of going through all your code and changing every reference to PORTB.0, for example, you simply change which pin the symbol points to.

Here's the code. It's just a counter, but demonstrates how to display all 4 digits at the same time:

Define CONF_WORD = 0x3f18
Define CLOCK_FREQUENCY = 4

AllDigital

Config PORTA = Output
Config PORTB = Output

Dim i(4) As Byte
Dim tmp As Byte
Dim j As Byte
Dim k As Byte

Symbol pin_a = PORTB.3
Symbol pin_b = PORTB.0
Symbol pin_c = PORTB.7
Symbol pin_d = PORTB.5
Symbol pin_e = PORTB.4
Symbol pin_f = PORTB.6
Symbol pin_g = PORTB.1


init:
     'rather than a single variable counting 0-9999
     'we'll keep track of the tens, hundreds, thousands
     'and units separately to make displaying them easier
     i(0) = 0
     i(1) = 0
     i(2) = 0
     i(3) = 0


loop:

     For k = 1 To 100
     
          'activate all four characters, one after the other,
          'but really quickly in succession
          
          For j = 0 To 3

          tmp = i(j)
          'turn off all characters
          PORTA = 0x00
          PORTB = 0xff

          'pull the appropriate segments in each character
          'low in order to light them up
          
          Select Case tmp
          Case 0
          'a,b,c,d,e,f=low g=high
          Low pin_a
          Low pin_b
          Low pin_c
          Low pin_d
          Low pin_e
          Low pin_f
          High pin_g

          Case 1
          'b,c=low
          High pin_a
          Low pin_b
          Low pin_c
          High pin_d
          High pin_e
          High pin_f
          High pin_g

          Case 2
          'a,b,d,e,g=low
          Low pin_a
          Low pin_b
          High pin_c
          Low pin_d
          Low pin_e
          High pin_f
          Low pin_g

          Case 3
          'a,b,c,d,g=low
          Low pin_a
          Low pin_b
          Low pin_c
          Low pin_d
          High pin_e
          High pin_f
          Low pin_g

          Case 4
          'b,c,f,g=low
          High pin_a
          Low pin_b
          Low pin_c
          High pin_d
          High pin_e
          Low pin_f
          Low pin_g

          Case 5
          'a,c,d,f,g=low
          Low pin_a
          High pin_b
          Low pin_c
          Low pin_d
          High pin_e
          Low pin_f
          Low pin_g

          Case 6
          'a,c,d,e,f,g=low
          Low pin_a
          High pin_b
          Low pin_c
          Low pin_d
          Low pin_e
          Low pin_f
          Low pin_g

          Case 7
          'a,b,c=low
          Low pin_a
          Low pin_b
          Low pin_c
          High pin_d
          High pin_e
          High pin_f
          High pin_g

          Case 8
          'a,b,c,d,e,f,g=low
          Low pin_a
          Low pin_b
          Low pin_c
          Low pin_d
          Low pin_e
          Low pin_f
          Low pin_g

          Case 9
          'a,b,c,d,f,g=low
          Low pin_a
          Low pin_b
          Low pin_c
          Low pin_d
          High pin_e
          Low pin_f
          Low pin_g

          Case Else
          High pin_a
          High pin_b
          High pin_c
          High pin_d
          High pin_e
          High pin_f
          Low pin_g

          EndSelect

          'activate the appropriate digit
          'by giving it power
          
          Select Case j
          Case 0
          High PORTA.1

          Case 1
          High PORTA.2
          Case 2
          High PORTA.6

          Case 3
          High PORTA.3
          EndSelect


          'wait a little while for the LED to appear lit
          '(thanks to persistence of vision it will appear lit
          'all the time when actually it's really flickering)
          WaitMs 2

          Next j
     Next k

     'increase the units variable
     i(0) = i(0) + 1
     
     'if we've rolled over to 10, increase the tens
     'by one and set units back to zero
     If i(0) >= 10 Then
          i(0) = 0
          i(1) = i(1) + 1
     Endif
     
     'if we've rolled over to 100, increase the
     'hundreds by one and set tens back to zero
     If i(1) >= 10 Then
          i(1) = 0
          i(2) = i(2) + 1
     Endif
     
     'if we've rolled over to 1000, increase the
     'thousands by one and set the hundreds back to zero
     If i(2) >= 10 Then
          i(2) = 0
          i(3) = i(3) + 1
     Endif

Goto loop
End



And here's a video showing the counter in action: