Introduction: BloodBowl Turn Counter Using 7-segment LEDs

This project was for a BloodBowl game turn counter using six Charlieplexed 7-segment LEDs.

Step 1: Concept

A friend of mine asked me about ideas for building Bloodbowl Turn counter for his boardgame. Not knowing what this was, and what he wanted, it took awhile to decide on if and how I was going to do this.

I first had to have an idea of what he wanted, so I started with concept art (picture). The basic idea is to have 3 push buttons, controlling 3 LED's each and it would be placed inside a custom built tower.

The only big request was to have the top 4 displays count up from 0 to 8 and reset, and have the lower 2 displays count down from 8 to 0 and cycle back.

I would complete the circuit, and he would complete the tower.

Step 2: Design & Parts List

Since the concept called for 6 7-segment LED's, and I had some 8-bit Microchip PICs handy, I researched ways of using the PICs to control LEDs.

I found this link http://www.mikroe.com/en/books/picbook/7_08chapter.htm that states " Up to 6 displays can be accessed like this without the brightness of each display being affected." I considered this a challenge and something to investigate as part of my project.

The First thing I did, was grab some incandescent 7-segment displays from my box and see how they would work. Bad news. The particular parts I selected were not behaving like I wanted. The segment would light when needed, on the breadboard, but leakage current was distributed to the other 6 segments. I realized incandescent displays may not be the way to go, or I needed to use them in a different way. So for simplicity I verified the 7-segment LEDs I had on hand would work for breadboarding, and ordered some common anode displays.

The Second thing I needed to do was layout my design and start work on the code. Pictured is my circuit. Not much to it, as the code in the PIC takes care of the multiplexing...errr Charlieplexing. Note: ALL 6 displays have the SAME lines from the driver IC. The selector IC enables each display, 1 at a time, and the 7-segment lines are updated by the PIC accordingly. Very simple idea.

After that, code and hardware completion is all that was needed.

Parts List
After 3 small orders from Digi-Key while deciding on specific components, I had everything I needed (with some stuff on hand);
1 ~3"x4" PCB
6 small push button switches (N.O.)
1 74LS47 , 7-segment display IC
1 PIC16F627
1 CD4028 , 1 of 10 selector IC
6 10KOhm resistors
1 470Ohm resistor
1 spool of wire. I used various colors and guages, but that was just me.
1 78L05 5V regulator
1 9V battery clip
1 9V battery
1 small switch (for power on/off)

I consider this a moderately complex project, due to;
1) Microprocessor code required
2) Soldering and breadboarding
3) Design optimization.

None of these issues by themselves are overly complicated, but taking them all on without any experience can be abit much for the beginner. A hardware programmer is required to burn the device, soldering station, etc...

The FIRST thng someone might notice is that the 7-segment LED's DO NOT have series (current limiting) resistors! Let me address that quickly, by stating my original design had them in...but read the next step for explanation!

Step 3: Breadboarding & Micro Code

Breadboard was a must for this. Shown is my generic breadboard, but for the size of this project I actually used this one and a smaller breadboard, as there were many wires that needed to be spaced out.

First, I tested one single 7-segment LED using by initial code. This confirmed 3 things;
1) Wiring of the IC's was verified good!
2) Led me to optimize and finalize my code.
3) Made me realize I didn't need the current limiting resistors!

1 WIRING
As stated, my schematic design was found to work with my code, as the LED would cycle through numbers using one push-button switch, so that verified my code and layout. Not much was required but breadboarding confirmed I was in good shape.

2 CODE
I originally had my code set with a main routine to scan for buttons and the ISR (Interrupt Service Routine) display the numbers , . After breadboarding tests, I reversed the routines, so the majority of the time was constantly displaying numbers and the ISR to check for buttons. The reason I did this, was just to have a constant display, since the PIC is running with an internal 4Mhz clock, I am losing very little time scanning for buttons. No big deal...just depends on how you want to do the code and what makes the most sense for each application. For this, display is important, so I put that in the main routine.

When my first parts arrived (all 6 displays!), I completed the breadboard wiring and found another issue. When pushing the button my code had some sloppy registers that were not being cleared and the ISR was causing some minor display glitches.

;===============================================================================
;Turn Counter
;
; -----------
;Dsply3<---- A2 |1 18| A1 ----> Dsply2
;Dsply4<---- A3 |2 17| A0 ----> Dsply1
;Led1 <----- A4 |3 16| A7 ----> Led3
; A5 |4 15| A6 ----> Led2
; Vss |5 14| Vdd
;Button1 --> B0 |6 13| B7
; B1 |7 12| B6
; B2 |8 11| B5
; B3 |9 10| B4
; -----------
;
; LED1-3 ---> BCD-dec IC --->LEDSeg's1-6
; Dsply1-3 ---> BCD-7seg IC --->Dsply#1-9
;

;===============================================================================
; Revision History & Notes:
; V1.0 Initial Header, Code 3/30/09
;
;
;(C) 5/ 2009
;This code may be used for personal learning/application/modification.
;Any use of this code in commercial products violates this freeware release.
;For questions/comments, contact circuit dot mage at yahoo dot com .
;-------------------------------------------------------------------------------

#include P16F627A.INC

;===============================================================================
; Defines
;-------------------------------------------------------------------------------

;===============================================================================
; Data
;-------------------------------------------------------------------------------
; Time keeping variables

count1 equ 20
count2 equ 21
dis1 equ 22
dis2 equ 23
dis3 equ 24
dis4 equ 25
dis5 equ 26
dis6 equ 27
w_temp equ 28
status_temp equ 29
ISRCNTR equ 2A

;===============================================================================
; Reset Vectors
;
; CHECK CONFIG. BITS BEFORE BURNING!!!
; INTOSC
; MCLR: ENABLED
; PWRUP: ENABLED
; ALL OTHERS: DISABLE!!
;
;-------------------------------------------------------------------------------
RESET_ADDR EQU 0x00
ISR_ADDR EQU 0x04

org RESET_ADDR
goto start
;===============================================================================
; ISR
;
;-------------------------------------------------------------------------------
org ISR_ADDR
movwf w_temp
swapf STATUS, w
movwf status_temp;

; ISR HERE
; Check PB0-PB5 Switches

btfsc PORTB,0 ; Check SW1
call sw1debounce
btfsc PORTB,1 ; Check SW1
call sw2debounce
btfsc PORTB,2 ; Check SW1
call sw3debounce
btfsc PORTB,3 ; Check SW1
call sw4debounce
btfsc PORTB,4 ; Check SW1
call sw5debounce
btfsc PORTB,5 ; Check SW1
call sw6debounce

goto endisr

sw1debounce
call debounce ; Wait 0.2 sec
call debounce
incf dis1 ; Update counter
movf dis1,W ; Check for overflow
xorlw 0x1A ; 10 on 7-seg?
btfss STATUS,Z
return ; No, return to scan.
movlw h'10' ; Yes, reset display.
movwf dis1
return
sw2debounce
call debounce ; Wait 0.2 sec
call debounce
incf dis2 ; Update counter
movf dis2,W ; Check for overflow
xorlw 0x4A ; 10 on 7-seg?
btfss STATUS,Z
return ; No, return to scan.
movlw h'40' ; Yes, reset display.
movwf dis2
return
sw3debounce
call debounce ; Wait 0.2 sec
call debounce
incf dis3 ; Update counter
movf dis3,W ; Check for overflow
xorlw 0x5A ; 10 on 7-seg?
btfss STATUS,Z
return ; No, return to scan.
movlw h'50' ; Yes, reset display.
movwf dis3
return
sw4debounce
call debounce ; Wait 0.2 sec
call debounce
incf dis4 ; Update counter
movf dis4,W ; Check for overflow
xorlw 0x8A ; 10 on 7-seg?
btfss STATUS,Z
return ; No, return to scan.
movlw h'80' ; Yes, reset display.
movwf dis4
return
sw5debounce
call debounce ; Wait 0.2 sec
call debounce
incf dis5 ; Update counter
movf dis5,W ; Check for overflow
xorlw 0x9A ; 10 on 7-seg?
btfss STATUS,Z
return ; No, return to scan.
movlw h'90' ; Yes, reset display.
movwf dis5
return
sw6debounce
call debounce ; Wait 0.2 sec
call debounce
incf dis6 ; Update counter
movf dis6,W ; Check for overflow
xorlw 0xCA ; 10 on 7-seg?
btfss STATUS,Z
return ; No, return to scan.
movlw h'C0' ; Yes, reset display.
movwf dis6
return

endisr
bcf INTCON, T0IF
swapf status_temp,w
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie

;===============================================================================
; Start Here!
;-------------------------------------------------------------------------------
start
; Config I/O ports
clrf PORTA
movlw 0x07
movwf CMCON
bcf STATUS,RP1
bsf STATUS,RP0
movlw h'00' ;RA<0-7> Outputs, RA5 No output
movwf TRISA

bcf STATUS,RP0
clrf PORTB
bsf STATUS,RP0
movlw h'FF' ; RB<0-7> Inputs
movwf TRISB

; Set internal timer
bsf PCON,3 ; Set to 4Mhz.
movlw h'CF' ; Tmr0 Internal source, prescale TMR0 1:256
movwf OPTION_REG
movlw h'A0'
movwf INTCON ; Enable TMR0 interrupts,
bcf STATUS,RP0

; Initialize Registers
clrf PORTA ; Clear PortA
clrf PORTB ; Clear PortB outputs

clrf count1
clrf count2

movlw h'10'
movwf dis1
movlw h'40'
movwf dis2
movlw h'50'
movwf dis3
movlw h'80'
movwf dis4
movlw h'90'
movwf dis5
movlw h'C0'
movwf dis6

call debounce ; 0.2 sec

;test LEDs , display 8 ???

;===============================================================================
; Main
; Gets inputs from switches, debounces and incriments displays.
;
;This updates the displays, @4Mhz with TMR0 prescal 1:4, at a 1Khz rate.
;Display 0 is used to allocate to an unused display. Display 1-6 are wired.
;First, BCD-7Seg IC is loaded with display value, AND BCD-Dec IC is activated for
;display selection.
;Second, a delay of ms is held for display.
;Third, BCD-Dec IC is deactivated...display0 is selected to shut off display
;
;This is repeated for each of the 6 displays, and looped.
;ISR handles switch sensing at 15Hz rate.
;-------------------------------------------------------------------------------
main

;Disp1
movf dis1,0
movwf PORTA
call ledon

goto main

;===============================================================================
; Ledon
; Settling time for LED power on.
; 6 displays -> 1/6 duty cycle at 1Khz = 166 cycles
;-------------------------------------------------------------------------------
ledon

movlw .54
movwf count1
ledloop
decfsz count1,F
goto ledloop
return
;===============================================================================
; Debounce signal
; 4 cycles to load and call , 2 cycles to return.
; 4Mhz Tc :: count2=255 -> 0.2 sec
;-------------------------------------------------------------------------------
debounce

movlw .255 ; Delay for 1/5 second debounce.
movwf count2
call pon_wait
return
;-------------------------------------------------------------------------------
; count1=255d :: 775 cycles to 0, + 3 cycles to return.
;-------------------------------------------------------------------------------
pon_wait

big_loopS
movlw .255
movwf count1
short_loopS
decfsz count1,F
goto short_loopS
decfsz count2,F
goto big_loopS
return

end

3 CIRCUIT
I originally had 470Ohm resistors from each display driver line from the 74LS47 and CD4028 enable line. However, I tested my circuit's current draw and found it was only pulling ~31mA. And since the actual driver for the displays is directly from the 74LS47 and enable is from another IC, a quick run down of the average and peak requirements, and the respective datasheets.....I pulled the resistors off the breadboard and found a 1mA difference! It appears that directly driving the CA line from the 4028 while directly driving all the segments is OK! ...sort of. :)

I DID have a glitch in my code that did not clear my registers when a button was pressed, causing the last display to have 2 segments very brightly lit when a button was pressed. This was bad. However, clearing the register fixed this problem, and continuous power checks confirm it is constantly around 30mA draw. This should give me (based on previous experience with similar circuits) ~20 hrs of run time using 1 9V battery (500mAH/30mAH under 5V regulation)...I hope!

I decided to keep the LED's directly driven, but put them in sockets in case something happened, long term.

Step 4: PCB Soldering

Everytime I get to this point in my project I delay abit. At first I was going to wire wrap this thing, but quickly dropped that idea.

At first I think "A few wires to solder, no big deal"...then, by the time my project is ready to be soldered I am thinking, " I should have either sent out to have a proto board made, or etched my own board".

I am not into PCB etching (yet), and didn't want to pay $$ to have a board made, so....

Yeah.....I spent about 3 hrs soldering this thing. It's about 150 wires, so that's 300 solder points, plus touch-ups for solder bridges.

Anyway, here's the back side of the board pictured....yeah...abit of a mess, but when it was all done I only had 1 solder short. Took 20 mins of thinking since the display showed the wrong #'s being displayed in a logical pattern that I had to decipher. After that, I located the short, and bam! It worked perfectly.

Step 5: Conclusion

IT WORKED!

This project took about;
~2 weeks to think about and email fine points to requestor,
~3 hrs of code completion and debug,
~4 hrs of breadboarding and debug,
~3 hrs of soldering

Using just 3 IC's it is possible to Charlieplex 6 7-segment LEDs.
Power draw is at about 30mA with this design, which isn't bad if I do say so myself.

I suspect more 7-segment LED's could be used, but have not pushed the envelope.

This idea could be applied to almost ANY application using 7-segment LEDs; thermometer, clock, text display, etc. With some tricky code, you could have a moving display, or pictures...maybe even a base for a POV (persistence of vision) project.

The final implementation is left for my friend to build his Tower and place the board in, as he see's fit. If/When that is done, I will get a picture uploaded. But as for the circuit, this appears to be built to order!

Comments

author
pyttroll (author)2009-06-19

Your Blood Bowl project is awesome. Would it be possible to add a timer easily? (I'm thinking of a 4 minutes countdown)

author
circuitmage (author)pyttroll2009-06-19

Thanks! To answer your question, yes and no; I have almost maxed out the pinouts on this small micro, so for this paticular hardware, probably not...though there are different ways of adding a clock. Timers get into a whole other area of projects, BUT...I HAVE played with making my own timers from these controllers, and (if you are not really picky about them being accurate) you CAN use the internal clock to make a crude timer that will work under most conditions reasonably well! You may be off a few seconds per minute, but a 4 minute timer could be implimented exactly the same way , but with different code. Or, you could use a bigger controller (more I/O pins) and expand this same project to add the timer.

author
pyttroll (author)circuitmage2009-06-19

Cool, thanks for the info :)
Just to let you know, I posted a link to your project on talkbloodbowl.com
http://www.talkbloodbowl.com/phpBB2/viewtopic.php?t=27982&highlight=

author
circuitmage (author)pyttroll2009-06-19

Great! I think my friends idea originated on a discussion board, maybe that one. Hope it helps. If anyone needs help building this, my services are available. :)