EXAMPLE 13
Two-digit LED counter, multiplexing
In this example, the microcontroller operates as a two-digit counter.
Concretely, the variable Dval is decremented (slow enough to be
visible) and its value is displayed on twodigit LED display (99-0). The
challenge is to enable binary number to be converted in decimal one and
split it in two digits (tens and ones). Besides, since the LED display
segments are connected in parallel, it is necessary to ensure that they
change fast in order to make impression of simultaneous light emission
(time-division multiplexing). Remember that in electronics, multiplexing
allows several analog signals to be processed by one analog-todigital
converter (ADC). In this very case, time-division multiplexing is
performed by the timer TMR0, while binary to decimal number conversion
is performed in macro "digbyte". Counter may be reset to its starting
value (99) at any moment by pressing the pushbutton "COUNTER RESET".
Source Code
;************************* Header *******************************************
;****************************************************************************
; DEFINING VARIABLES IN PROGRAM
w_temp EQU 0x7D ; Variable for saving W register
status_temp EQU 0x7E ; Variable for saving STATUS register
pclath_temp EQU 0x7F ; Variable for saving PCLATH register
CBLOCK 0x20 ; Block of variables starts at address 20h
Digtemp
Dig0 ; Variables for displaying digits - LSB
Dig1
Dig2
Dig3 ; Variables for displaying digits - MSB
Dval ; Counter value
One ; Auxiliary variable which determines which
; display is to be switched on
ENDC ; End of block of variables
poc_vr EQU .99 ; Initial counter value is 99
include "Digbyte.inc"
;****************************************************************************
ORG 0x0000 ; First instruction address
goto main ; Jump to label "main"
;****************************************************************************
ORG 0x0004 ; Interrupt vector address
movwf w_temp ; Move w register to w_temp register
movf STATUS,w ; Move STATUS register to status_temp
movwf status_temp ; register
movf PCLATH,w ; Move PCLATH register to pclath_temp
movwf pclath_temp ; register
; Start of interrupt routine...
BANKSEL TMR0
movlw .100
movwf TMR0
bcf INTCON, T0IF
bcf PORTA, 0
bcf PORTA, 1
btfsc One, 0
goto Lsdon
goto Msdon
Lsdon
incf One, f
movlw HIGH (Bcdto7seg)
movwf PCLATH
digbyte Dval
movf Dig1, w
call Bcdto7seg ; Place L1 mask on the PORTD
movwf PORTD
bsf PORTA, 1
goto ISR_end
Msdon
incf One, f
movlw HIGH (Bcdto7seg)
movwf PCLATH
digbyte Dval
movf Dig0, w
call Bcdto7seg ; Place LO mask on the PORTD
movwf PORTD
bsf PORTA, 0
goto ISR_end
; End of interrupt routine...
ISR_end
movf pclath_temp,w ; PCLATH register is given its original
movwf PCLATH ; state
movf status_temp,w ; STATUS register is given its original
movwf STATUS ; state
swapf w_temp,f ; W register is given its original
; state
swapf w_temp,w
retfie ; Return from interrupt routine
main
banksel ANSEL ; Selects bank containing ANSEL
clrf ANSEL ; All pins are digital
clrf ANSELH
BANKSEL TRISA
movlw b'11111100' ; RA0 and RA1 are configured as outputs and
; used for 7-segment display multiplexing
; RA2 is input push-button for initializa
; tion
movwf TRISA
clrf TRISD
BANKSEL OPTION_REG
movlw b'10000110' ; TMR0 is incremented each 32us (Fclk=8MHz)
movwf OPTION_REG
BANKSEL PORTA
movlw poc_vr
movwf Dval ; Dval contains counter value
movlw b'00000001' ; Initializes variable specifying display
movwf One ; to switch on
movwf PORTA
movlw .100
movwf TMR0 ; TMR0 interrupt appr.every 10ms
bsf INTCON, GIE ; Global interrupt enabled
bsf INTCON, T0IE ; Timer TMR0 interrupt enabled
bcf INTCON, T0IF
Loop
btfss One, 3 ; Falling edge encountered?
goto Dec ; Yes! Go to Dec
btfss PORTA, 2 ; Counter reset button pressed?
goto Reset ; Yes! Go to Reset
goto Loop
; Decrement Dval counter by 1
Dec
btfss One, 3
goto Dec
movf Dval, f
btfsc STATUS, Z ; Is Dval equal to 0?
goto Loop ; If it is, go to loop and wait for T2
decf Dval, f ; If Dval not equal to 0, decrement it by 1
goto Loop
Reset
btfss PORTA, 2 ; Wait for rising edge
goto Reset
movlw poc_vr
movwf Dval ; Write initial value to counter
goto Loop
;****************************************************************************
ORG 0x0300 ; Lookup table is at the top of third page, but
; can be placed at some other place, it is impor
; tant to have it all on one page
Bcdto7seg
addwf PCL, f
DT 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f
;****************************************************************************
END ; End of program
Macro "digbyte":
digbyte MACRO arg0
LOCAL Exit0
LOCAL Exit1
LOCAL Exit2
clrf Dig0
clrf Dig1
clrf Dig2
clrf Dig3
movf arg0, w
movwf Digtemp
movlw .100
Exit2
incf Dig2, f
subwf Digtemp, f
btfsc STATUS, C
goto Exit2
decf Dig2, f
addwf Digtemp, f
Exit1
movlw .10
incf Dig1, f
subwf Digtemp, f
btfsc STATUS, C
goto Exit1
decf Dig1, f
addwf Digtemp, f
Exit0
movf Digtemp, w
movwf Dig0
ENDM
Macro digbyte is used to convert the number from digital to decimal
format. Besides, digits of such decimal number are stored into special
registers in order to enable them to be displayed on LED displays.