Figure7-3showsourtestcircuit.It’safamiliarmixofhigh-sideandlow-sidedriversasdiscussedinChap-ter3.Let’slookatitindetail.
PinsA0…A3areconnectedto2N4403PNPtransistorssetupashigh-sidedigitswitches.WhenA0…A3go
low,Q1…Q4areforwardbiased,and+5V,lessVSAT,appearsonthecommonanodesofDigits3…0.We’ve
selectedR8…R11(2.2Kohm)tolimitthebasecurrentdrivetoaround2.5mA.
EachdigithasitscathodesegmentsA…Gconnectedinparallel,witheachsegmentgoingtoanoutputpin
ofaULN2003ANPNDarlingtonarray.ThecorrespondinginputsoftheULN2003Aareconnectedtopins
B0…B6.(Thedecimalpointisn’tconnected,asitisn’tneededinourapplication.But,don’tworry;we’llsee
aseven-segmentdisplaywithautomaticdecimalpointsettinginChapter11.)
WhenanypinB0…B6goeshigh,theattachedDarlingtonissaturatedandthuscompletesthecircuit.
Thus,toturnonSegment(i)ofDigit(j),theassociatedB0…B6pinmustbehighandtheassociateddigit
selectionpinA0…A3mustbelow.Thispermitsustoindividuallycontroleachsegmentofeachdigit.To
givetheappearanceofsimultaneousoperation,wecyclethroughallfourdigitsquickerthanourpersistence
ofvisionrecognizesflicker.
EachsegmentofaHDSP-5721isratedfor60mApeakcurrent,and20mAcontinuouscurrent.Sincewe
aremultiplexingfourdigits,we’llbelimitedbythepeakcurrentrating.TheHDSP-5721’sforwardvoltage
isspecifiedas2.1Vtypical.Aswe’llseebelow,wemayexpectaround1.0VdropacrosstheULN2003A
driver.FromChapter3,weknowthe2N4403’sVSATisaround0.4V.Hence,thevoltageacrossthelimiting
Figure7-3:Four-digitLED
displaysetup.
Figure7-4:TypicalULN2003Adriver.
resistoris(5.0–2.1–1.0–0.4)Vor1.5V.Toachieve60mA,thecurrentlimitingresistorwouldbe(1.5
V/0.060A),or25ohms.Ifound60mAresultedinabrighterdisplaythanIwanted,sobyexperimentationI
foundthedesiredbrightnessrequired68ohms.Theresultantpeakcurrentisapproximately25mA.
TheULN2003Aisaninterestingandusefuldevice;solet’stake
aquicklookatwhat’sinside.ItconsistsofsevenidenticalNPN
Darlingtontransistordrivers,andassociatedsnubbingdiodes
ina16-pinDIPpackage.EachDarlingtonisratedat500mA
current,and50Voutputvoltage.(Youcan’trunallsevendrivers
eachsinking500mAwithoutgrossly
exceedingtheULN2003A’spower
ratings,ofcourse.)Atypicaldriverap-pearsinFigure7-4.Again,thisshould
befamiliarfromChapter3.Thedriver
transistorhasabuilt-inbaseresistor,
sowemaydirectlyconnectittoaPIC
outputpin.LikeallDarlingtons,it
suffersinVSATcomparedwithasingle
transistor,beingratedataround1.0V
for100mAcollectorcurrent,com-paredwiththe0.4Vorsowefindfora
2N4401.Eachdriverhasanassociatedclampdiodetopreventdamagewhendrivinginductiveloads.We’ve
connectedittoVDD,althoughthisconnectioncouldbeomitted,ifdesired,sincethere’snoinductivespike
whendrivinganLED.We’llusethischipforlaterprojects,suchasdrivingsmallsteppermotors,whereit’s
importanttoconnecttheclamptoVDD.
We’reusingaULN2003Ainsteadofsevenseparate2N4401sor2N7000spurelyasamatterofwiring
convenience.So,ifyoudon’thaveaULN2003A,wireupthecircuitwithseven2N7000s,or2N4401swith
2.2Kbaseresistors.Itisn’tnecessarytouseaDarlingtonconfigurationatthecurrentlevelsnecessaryto
drivesmallLEDdisplays.IfyourLEDdisplayprovidesadequatebrightnesswith25mAorlesscurrent,
omitanyexternalsegmentdriverandconnectthecurrentlimitingresistordirectlytopinsB0…B6.Inthis
case,youwillneedtorecalculatethedroppingresistor,andinvertthesenseoftheB0…B6pins.(Withan
externaldriver,ahighonB0…B6activatesasegment,butwithadirectconnectionalowonB0…B6is
required.Thecurrentlimitingresistorshouldbearound100ohms.) IdevelopedthecircuitofFigure7-3aspartofalargerproject,
andFigure7-5showstheresultingprototypePCB.Thedevice
thatlookslikeanintegratedcircuitabovethedisplaysare68-ohm
currentlimitingresistorsintheformofaBournes4116R-1-680
resistornetwork.Separateresistorswouldworkjustaswell.Of
course,youdon’tneedtodesignandbuildaPCBtoexperiment
withthiscircuit;asolderlessplugboardworksperfectlywell.You
can’tsqueezeallthepartsontothesmall2840developmentboard’s
plugboard,however,soasecond,larger,plugboardisrequired.
TestProgram
Nowthatyou’vewiredupthecircuitofFigure7-3,let’stestit.
Figure7-5:Completed4-digitLEDdisplay.
Program7-1
;Programtodemonstrate4digit7-segmentLEDdisplay
;Sequentiallyshoweachsegmentandeachdigit
i Var Byte
j Var Byte
Fori=B0toB6
Outputi
Lowi Next
Fori=A0toA3
Outputi
Highi Next
Main
Fori=A0toA3
Lowi
Forj=B0toB6
Highj
GoToMain
Program7-1exerciseseachsegmentandeachdigit.Thesegmentsilluminate,oneatatimeinorderA…G
for250mseach,startingwithDigit0(rightmost)andmovingleft.
Thecodeitselfrequireslittleanalysis;aftersettingB0…B6andA0…A3foroutput,wesequentiallyscanthe
digitsandsegments.Theouterloop,i,stepsthroughthedigits.Foreachdigit,theinnerjloopscansthe
segments.Recallthatinordertobeilluminated,asegmentrequiresitsdigitline(A0…A3)tobelow(applies
+5Vtothedisplaycommon)anditssegmentpin(B0…B6)tobehigh(saturatestheULN2003Darlington).
Hence,theiloopsetsoneofA0…A3lowandthejloopsetsoneofB0…B6high.Toturnoffunwanteddigits,
allotherA0…A3pinsaresethighandtoturnoffunwantedsegments,allotherB0…B6pinsaresetlow.
Now,let’slookatdisplayingactualdigits,0…9.Program7-2continuouslycyclestherightmostdigitfrom
0…9,displayingeachdigitforonesecond.
Program7-2
;Showsdigits0...9inlastplace
;LEDdisplayiscommmonanode
;cathodesthroughULN2003Aarray
;Variables
;---i Var Byte
Decode Var Byte(11) ;holdssegmentpattern
;Digitvalues[D3][D2][D1][D0]
;Initialization
;--- Clear
DeCode(0)=%00111111holdssegments
DeCode(1)=%00000110 +---A---+
DeCode(2)=%01011011 ||
DeCode(3)=%01001111 FB
DeCode(4)=%01100110 ||
DeCode(5)=%01101101 +---G---+
DeCode(6)=%01111100 ||
DeCode(7)=%00000111 EC
DeCode(8)=%01111111 ||
DeCode(9)=%01100111 +---D---+
DeCode(10)=%00000000;allblank XGFEDCBAisbitorder
TRISB=$00
TRISA=$F0
PortA.LowNib=%1111 Main
LowA0
Fori=0to9
PortB=DeCode(i)
Pause1000
Next
GoToMain
End
ThemajoradditiontothisprogramisthearrayDeCodetomapthedesireddigitstothesegmentsthatmust
beilluminatedtodisplaythatparticulardigit.
We’veconnectedthesegmentsintheorderofsegmentAtoB0…segmentGtoB6.Hence,toilluminateseg-mentA,wemustwrite%00000001toPortB.ToilluminatesegmentB,wewrite%00000010toPortB,and
soforth.Ifwewishtodisplaythecharacter“0”,forexample,wemustwrite%00111111toPortB,thereby
illuminatingallsegmentsexceptG.(IfwedirectlyconnectthedisplaycathodestopinsB0…B6,wemust
invertthismapping,forexample,todisplaythecharacter“0”wewouldwrite%11000000toPortB.) Anotherchangewe’vemadeistoinitializePortAandPortBthroughTRISAandTRISBstatements,as
outlinedinChapter2.ThischangeillustratesthatMBasicoftengivesusseveralwaysofaccomplishing
thesametask.(WecouldomittheTRISAstatement,astheLowandHighstatementsautomaticallychange
thepintooutput,butit’scleanertoinitializeourinputandoutputpinsdirectly.)Wealsosetalldigitstooff
throughPortA.LowNib=%1111.
Main
LowA0
Fori=0to9
PortB=DeCode(i)
Pause1000
Next
GoToMain
ThemainloopfirstactivatesDigit0bydroppingA0low.Then,we
loopthroughthedigits0…9.Eachdigitisdisplayedthroughthe
assignmentPortB=DeCode(i).
Nowthatwe’veverifiedthatallsegmentsilluminateandthatthe
digits0…9canbedisplayed,let’sdosomethingmoreusefulwith
ourdisplay.Program7-3readsthreemomentarycontactswitches;
oneincrementsthecount,onedecrementsthecountandonewill
clearthecounttozero.Makingitabitfancier,we’llblankleading
zeros.We’lldebouncetheswitchesandsetupthereadloopsothat
thecounteronlyincrementsonceforeachclosure.
First,asshowninFigure7-6addthreemomentarycontact,normal-lyopenswitchesandpull-upresistorstothecircuitofFigure7-3. Figure7-6:Addedswitches.
Program7-3
;Programtodemonstrate4digit7-segmentLEDdisplay
;Countsup/downon4-digitLEDDisplay
;LEDdisplayiscommmonanode
;cathodesthroughULN2003Aarray
;Constants
DelayCount Con 3
;Variables
;---i Var Byte
j Var Byte
Decode Var Byte(11) ;holdssegmentpattern Digit Var Nib(4) ;holdsdigitvalues
Counter Var Word ;valuetodisply
TempWord Var Word
ArmUp Var Nib
ArmDown Var Nib
;Digitvalues[D3][D2][D1][D0]
;Initialization
;--- Clear
DeCode(0)=%00111111holdssegments
DeCode(1)=%00000110 +---A---+
DeCode(2)=%01011011 ||
DeCode(3)=%01001111 FB
DeCode(4)=%01100110 ||
DeCode(5)=%01101101 +---G---+
DeCode(6)=%01111100 ||
DeCode(7)=%00000111 EC
DeCode(8)=%01111111 ||
DeCode(9)=%01100111 +---D---+
DeCode(10)=%00000000 ;allblank XGFEDCBAisbitorder
TRISB=$00 ;segmentsonPortB
TRISA=$F0 ;DigitdriveonPortA
TRISC=%00000111 ;SwitchesonPortC
PortA.LowNib=0
PortB=DeCode(8)
Pause1000
PortB=DeCode(10)
Pause250
;blankleading0s
Digit(3)=10
Digit(2)=10
Digit(1)=10 Main
;multiplexrighttoleft
Fori=A0toA3
;orderisimportanttovoidghosting
PortB=DeCode(Digit(i-A0))
Lowi
;GetDigitsispartofthedelay
GoSubGetDigits
Pause1
Highi
Next
GoToMain
GetDigits
;Checktheupcountswitch
If(PortC.Bit0=0)AND(ArmUp=0)Then
Counter=Counter+1
ArmUp=1
EndIf
;Isitoff?Ifsodelay
If(ArmUp>0)AND(PortC.Bit0=1)Then
ArmUp=ArmUp+1
IfArmUp=DelayCountThen
ArmUp=0
EndIf
EndIf
;Checkthedowncountswitch
If(PortC.Bit1=0)AND(ArmDown=0)Then
Counter=Counter-1
ArmDown=1
EndIf
;Ifswitchoff?Ifsodelay
If(ArmDown>0)AND(PortC.Bit1=1)Then
ArmDown=ArmDown+1
IfArmDown=DelayCountThen
ArmDown=0
EndIf
EndIf
IfPortC.Bit2=0Then
Counter=0
EndIf
;Avoidrollover
IfCounter>9999Then
Counter=0
EndIf
;DigitsareindividualBCD
TempWord=Bin2BCDCounter
Digit(0)=TempWord.Nib0
Digit(1)=TempWord.Nib1
Digit(2)=TempWord.Nib2
Digit(3)=TempWord.Nib3
;Followingisforblankingleading0s
IfCounter<1000Then
Digit(3)=10
EndIf
IfCounter<100Then
Digit(2)=10
EndIf
IfCounter<10Then
Digit(1)=10
EndIf
Return End
We’vedeclaredseveralnewvariables,including:
Digit Var Nib(4)
Counter Var Word
Counteristhevaluethatweincrement,decrementorzerowiththeaddedswitches.Sincewehavefourdisplay
digits,Countermayrunfrom0…9999.Weaccordinglystoreitinawordlengthvariable.ThearrayDigitholds
thevalueoftheindividualdigitstobedisplayed.IfCounteris1234,forexample,Digit(0)=4,Digit(1)
=3,Digit(2)=2andDigit(3)=1.(Thedigitsarenumberedwith0attherightmostposition.)
PortA.LowNib=0
PortB=DeCode(8)
Pause1000
PortB=DeCode(10)
Pause250
;blankleading0s
Digit(3)=10
Digit(2)=10
Digit(1)=10
Aspartofinitialization,weilluminateallsegmentsbydisplaying“8888”for250ms,followedbyblanking
theleftmostthreedigits.(DeCode(10) isablank.)Brieflyilluminatingallsegmentsisacommoninitial-izationfeature,asitpermitstheusertodetectfailedsegments.Wedon’thavetoworryaboutoperatingall
segmentssimultaneouslyasweuserobustdrivers.IfyoursegmentsaredirectlyconnectedtopinsB0…B6,
simultaneouslyoperatingallsegmentsandalldigitsmayoverstressthePIC’sabilitytosinkcurrent,in
whichcasemodifyyourcodetosequencethedigits.
Main
;multiplexrighttoleft
Fori=A0toA3
;orderisimportanttovoidghosting
PortB=DeCode(Digit(i-A0))
Lowi
;GetDigitsispartofthedelay
GoSubGetDigits
Pause1
Highi
Next
GoToMain
Themainloopsequentiallystepsthroughthedigits,fromrighttoleft,withtheFori…Next loopandil-luminatesthesegmentsrequiredtodisplaytheassociatedvalueheldinDigit(i).We’llassumeforthe
momentthatDigit(i)holdsthecorrectvalue(0…9)foreachofthefourdisplayeddigits.AfterPortB
issettotheproperbitsequencetodisplaythecorrectdigit,executionbranchestosubroutineGetDigits,
followingwhichanextra1mspauseisexecuted.(Aswe’llseeshortly,subroutineGetDigitsfillsDigit() withthecorrectvalues.)
Severalpointsareworthmentioningifyoumodifythiscodeforotherprograms.First,inordertoavoid
flicker,theloopmustexecuterelativelyfast.Aswritten,eachdigitisilluminatedforabout4ms,soallfour
digitsareupdatedabout60timespersecond.Ifthisupdateratesignificantlyslows,duetoaddedcode,the
displaywillstarttoflicker.Differentpeopleperceiveflickerdifferently,butIfindflickerobjectionableifthe
updateratefallsbelow40persecond.Second,it’simportanttoswitchbetweendigitsasfastaspossibleto
avoid“ghosting”wherefalsesegmentsarebrieflyilluminated.Toavoidghostingwefirstwritethesegment
informationtoPortBandthentaketheassociatedApinlowtoactivatethedigit.Reversingthisordercauses
objectionableghosting.Finally,there’satrade-offbetweenthedigit-ontimeandperceivedbrightness,of
course,sosometinkeringwiththecurrentlimitingresistormaybenecessaryafteryourcodeisfinished.
Let’slookatGetDigits.Thissubroutineiscalledevery4msorso.
If(PortC.Bit0=0)AND(ArmUp=0)Then
Counter=Counter+1
ArmUp=1 EndIf
;Isitoff?Ifsodelay
If(ArmUp>0)AND(PortC.Bit0=1)Then
ArmUp=ArmUp+1
IfArmUp=DelayCountThen
ArmUp=0
EndIf
EndIf
Allswitchesarewiredwiththenormal(unpressed)positionopen,sothata0representsswitchpressedand1
isswitchun-activated.Wehavetwoalmostidenticalroutinestohandletheupanddownswitchinputs.We’ll
onlylookatthe“up”switchcode.
AssumeforthemomentthatArmUp=0(it’sinitializedthatway)andthatthe“up”switchispressed.The
conditionalIf(PortC.Bit0=0)AND(ArmUp=0)thusevaluatesastrue,Counterisincremented
andArmUpisassignedas1.
Aslongasthe“up”switchcontinuestobepressedthesecondconditionalIf(ArmUp>0)AND
(PortC.Bit0=1)fails,asPortC.Bit0=0.ArmUp thuscontinuestoequal1andtheearliercondi-tionalwillfail,thuspreventingCounterfrombeingupdatedduetocontinuedswitchactivation.
Whenthe“up”switchisreleased,thesecondconditionalIf(ArmUp>0)AND(PortC.Bit0=1) evaluatestrue,soArmUpisincremented.Iftheswitchbounces,it’spossiblethatthefirstconditionalmay
evaluatePortC.Bit0=0astrue.However,ArmUpcontinuestobegreaterthan0,sotheArmUp=0part
ofthefirstconditionalfailsandCounterisnotincremented.Eventually,however,assumingthe“up”switch
isnotpressed,ArmUpreachesDelayCountatwhichtimeitisresetto0andwearereadyforanotherpress
ofthe“up”switch.DelayCountisaconstantthatI’vesetat3,thusrepresentingtwopassesofGetDigits,
orabout8ms.YoumayneedtovaryDelayCount,dependingonthebounceperformanceofyourswitches,
but3isagoodstartingpoint.
IfPortC.Bit2=0Then
Counter=0 EndIf
WeneednotcomplicatereadingtheresetswitchconnectedtopinC2;itdoesn’tmatterifbouncecausestwo
orthreeconsecutiveresets.
;Avoidrollover IfCounter>9999Then
Counter=0 EndIf
Sinceourfour-digitdisplayonlyshows0…9999,werestrictCountertothosevaluesthatarecapableof
beingdisplayed.
TempWord=Bin2BCDCounter Digit(0)=TempWord.Nib0 Digit(1)=TempWord.Nib1 Digit(2)=TempWord.Nib2 Digit(3)=TempWord.Nib3
Let’slookathowwegettheindividualdigitvaluesoutofCounterandintotheDigitarray.Itturnsout
thatthisisarathercommonactivityandMBasicincludesafunction,Bin2BCDtoperformitforus.(There’s
anerrorinsomeeditionsoftheUser’sGuidewherethisfunctionisincorrectlyidentifiedasDec2BCD.)Let’s
lookat“binarycodeddecimal”abitmoreclosely.
SupposeCounterholds1234.Thevalue1234(decimal)isheldinMBasicashex$4D2.Ifwewantedour
displaytoshowhexadecimal(assumingwedefinedDeCode($A)…DeCode($F)),wecouldveryeasilyfind
ourdigits.We’vedeclaredCounterasawordlengthvariable,soithasfournibbles:
WordValue Nibble3 Nibble2 Nibble1 Nibble0
$4D2 $0 $4 $D $2
Hence,Digit(0)=Counter.Nib0,etc.But,yousay,wewantadecimaldisplay,notahexadecimalone.
Fairenough.First,however,whatis1234?It’s1×1000+2×100+3×10+4.Withthisunderstanding,we
candeviseanalgorithmtofillDigit():
Digit(3)=Counter/1000 Remainder=Counter//1000
Digit(2)=Remainder/100 Remainder=Counter//100 Digit(1)=Remainder/10 Digit(0)=Remainder//10
InMBasic“/”isintegerdivisionand“// ”istheremainder,ormodulus,function.Let’sseehowthisalgo-rithmworksifCounteris1234.
1234/1000=1 ->Digit(3) 1234//1000=234
234/100=2 ->Digit(2) 234//100=34
34/10=3 ->Digit(1) 34//10=4 ->Digit(0)
But,there’safasterwaytoaccomplishthisconversionthaninvokingsixintegerdivisionandremainderop-erationsinMBasic.First,adefinition:binarycodeddecimal,orBCD,usesfourbits(onenibble)torepresent
eachdecimaldigit.Sinceawordis16bitslong,wecan“pack”fourBCDdigits,eachfourbitslong,into
eachword.Thisarrangement,oftencalled“packedBCD,”isshownbelow,supposing,somehow,weareable
togeteachnibbletoholdthedesireddigits.
WordValue Nibble3 Nibble2 Nibble1 Nibble0 4660
$1234 1 2 3 4
Thedecimalvalueof$1234is4660,butlookingateachnibbleindividuallyweimmediatelyseewhatweare
lookingfor,[1][2][3][4].
MBasic’sBin2BCDfunctionconvertsabinaryvariabletopackedBCD.Hence,fillingDigit()issimplya
matterofassigningeachnibbletoitsDigit() counterpartthefollowingtheBCDconversion.Weaccom-plishthiswiththefollowingcodesnippet:
TempWord=Bin2BCDCounter Digit(0)=TempWord.Nib0 Digit(1)=TempWord.Nib1 Digit(2)=TempWord.Nib2 Digit(3)=TempWord.Nib3
Finally,foraestheticreasonsweblankleadingzeros.
;Followingisforblankingleading0s IfCounter<1000Then
Digit(3)=10 EndIf
IfCounter<100Then
Digit(2)=10 EndIf
IfCounter<10Then
Digit(1)=10 EndIf
We’vedefinedDeCode(10)asablankdigit(allsegmentsoff),sotoblankadigitwesetDigit()as10.
ThistaskiseasilyaccomplishedbycheckingthevalueofCounter.IfCounterisunder1000,weknow
thatatleasttheleftmostdigitmustbe0,andaccordingassignDigit(3)asablank.Werepeatthistestand
assignmentprocesswith100and10forDigit(2)andDigit(1).
Afterblankingleadingzeros,thesubroutineisfinishedandprogramexecutionreturnstoMain.
Wecannowtesttheprogram.Everytimethe“up”buttonisoperated,thedisplayedcountwillincreaseby
one.Everytimethe“down”buttonisoperated,thedisplayedcountwilldecreasebyone,withaminimumof
zero.Pressingthe“clear”buttonresetsthedisplaytozero.
Program7-3callsthesubroutineonceevery3.8msaswritten.Theanti-bouncedelaylimitsthespeedwith
whichthecounterwillincrementanddecrementtoabout20to30operationspersecond,morethanfast
enoughforhand-operatedswitches.
IdeasforModificationstoProgramandCircuits
• Addsegmentdefinitionsfor“a”,”b”,”c”,“d”,“E”and“F”toDeCode().RemovetheTempWord=
Bin2BCDCounterstatementanddisplaythecountinhexadecimal.
• HowdoesflickerchangeasyoumodifythePause1statement?(IfoundthatifIchangedthepause
timeto5,flickerisquiteobjectionable,andwith4,flickerisbarelynoticeable.Icouldnotdetectany
flickerforapausetimeof3orbelow.Ifyouwishtodisablethepause,commentitoutordeletethe
statement.Pause0actuallyexecutesPause255.)
• Howdoesperceivedbrightnesschangeasyoumodify
thePause1statement?Whatistheratioofdigit-onto
digit-offtime?Iftheoverheadiszero,eachdigitshould
beon25%ofthetime.(AsFigure7-7shows,withthe
Pause1statementoperational,eachdigitisilluminated
22.1%ofthetime.Theoverheadisthus11.6%.)
• Insteadoftriggeringup/downcountswithmechanical
switches,substituteafunctiongenerator’ssquarewave
output.Howfastcanyouupdatethecounterbefore
itmissesinputpulses?Itispossibletoincreasethe
responsespeed?(Youdon’tneedtodebounceafunction
generator’sinput,sotheinputsoftwarecanbesimpli-fied.)IsitpossibletoreplacethePause1statement
withrepeatedsubroutinecallstoGetDigits?
withrepeatedsubroutinecallstoGetDigits?