Monday, March 27, 2006

PIC: EXAMPLE 13

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".
Example 13 - Two-digit LED counter, multiplexing

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.