PIC 16F84A elapsed time counter on 4, 7 segment LED's

Note: The comments in this code are written in Slovinian. The host of this web site does not have an "English version" and has no way to provide it. Repeatedly asking is not going to help. If you know of someone who could translate it, please consider getting it done and posting the result here.

BENEDICIC SAMO [samo.benedicic at HIT.SI] says:

Hi!

I made this to monitor working hours of an oil burner. Clock works only when
RA4 is low. Elapsed time is displayed on four common cathode 7 segment LED
displays, so the clock counts to 9999 hours. It's easy to change it so that
it counts seconds or minutes. Displays are connected like this: RA0-RA3 are
going on bases of four 2N2222 transistors, emitors on GND and collectors on
cathodes of displays. RA2-thousands, RA3-hundreds, RA1-tens, RA0-ones ( I
ones connected them like that and then changed the code to display numbers
right ). Anodes are connected A = RB0  to G=RB6. RA4 has a 10k pullup
resistor connected to +5V and a switch to ground. Code is partially taken
from Microchip AN557, so is the schematics. If you have any questions about
the code, don't hesitate to ask. I would appreciate any comments and
suggestions. If anybody needs english comments on the code, I can translate
it in, like, 10 minutes. Attached is an txt file, you just copy and paste it
to MPLAB. Regards, Samo


;**********************************************************************
;                                                                     *
;    Filename:          gorilec.asm                                   *
;    Date:              20.12.2000                                    *
;    File Version:      1                                             *
;                                                                     *
;    Author:            Benedièiè  Samo                               *
;    Company:           Hit                                           *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes: This is a clock, used to measure the time that oil burner *                                                       *
; is on                                                               *
;                                                                     *
;**********************************************************************


        list      p=16F84A             ; list directive to define processor
        #include <p16F84A.inc>         ; processor specific variable definitions

        __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.



;**************************************************************************************
;
; definition of some shit ( used for easier remembering )                             *
;
;**************************************************************************************

        w       equ     0       ;direction for byte oriented instructions
        f       equ     1
        Z       equ     2       ;zero flag

;**************************************************************************************
;
;definition of some registers I'll use
;
;**************************************************************************************

        CBLOCK  0Ch             ;it's way easier to define registers this way

        COUNTER1
        COUNTER2
        SECONDS
        MINUTES
        MSD
        LSD
        OSVEZI
        SINK
        RES_STEVEC1
        RES_STEVEC2
        RES_STEVEC3
        A_TEMP
        UGASNJENO

        ENDC
	
	
	

        	

	
;**************************************************************************************
;
;and some useful macros
;
;**************************************************************************************


BANK0   macro
        bcf     STATUS, RP0     ;switch to bank0
        endm

BANK1   macro
        bsf     STATUS, RP0     ;bank1
        endm	


;**************************************************************************************
;
        ORG     0               ;main program location
        goto    START
;
;
;
        ORG     4               ;interrupt vector
        goto    SERVICE_INTERRUPT	
;
;
;
START
;
;
        call    INIT_COUNTERS   ;clear counters 
        call    INIT_PORTS      ;inicializiraj porte
        call    INIT_TIMER      ;start tmr0



;
;	
MAIN
;       clrf    PORTA
        goto    MAIN            ;37 ciklov do zanke
;
;
;
INIT_COUNTERS
;
        clrf    COUNTER1
        clrf    COUNTER2
        clrf    SECONDS
        clrf    MINUTES
        clrf    MSD
        clrf    LSD
        clrf    OSVEZI
        clrf    RES_STEVEC1
        clrf    RES_STEVEC2
        clrf    RES_STEVEC3
        clrf    UGASNJENO
        return
;
INIT_PORTS
        BANK1
        clrf    TRISA
        bsf     TRISA, 4        ;èetrti pin PORTA je vhod, ostalo izhodi
        clrf    TRISB           ;portb so izhodi
;
        BANK0
        clrf    PORTA
        clrf    PORTB
        bsf     PORTA, 3        ;omogoèi ponor za najbolj levi display
        return
;
INIT_TIMER

        BANK1
        movlw   b'00001000'     ;prescaler 1:1
        movwf   OPTION_REG
;
        movlw   b'10100000'     ;enable TMR0 interrupt
        movwf   INTCON
;
        BANK0                   ;we aim to have interrupt every 250 microsec,so we 
        movlw   .8              ;write (256-250+2)=8 to TMR0, because

;       movlw   .230            ;TEST!!!!


        movwf   TMR0            ;two clock cycles go by before 
                                ;TMR0 is incremented for the first time	
        return
;	
;


;*************************************************************************
;
;       All our work will be done here
;
;*************************************************************************

SERVICE_INTERRUPT


        BANK0                   ;I need 3 cycles to write new
        movlw   .13             ;value to TMR0+2 cycles to start counting again

;       movlw   .220            ;TEST!!!!!


        movwf   TMR0
        bcf INTCON, 2           ;clear interrupt flag
;
;****************************************************************************
;
;       Vsakih 99 TMR0 interruptov (cca. 40 x na sekundo ) osvežim display.
;       99 je izbrana zato, da se èimmanjkrat primeri, da gre tok 
;       programa skozi vse rutine, torej, da se ne izvajajo hkrati
;       rutine osveževanja displaya in inkrementiranja vseh števcev.
;
;****************************************************************************
;
;
	


        call    OSVEZI_DISPLAY  ;ja, osveži display

;
;
;***************************************************************************
;
;       Preverim tudi stanje reset tipke, ki je povezana na RB0 preko šibkega
;       pull-up upora 10k proti masi.	
;
;***************************************************************************
;
        movf    PORTA, w
        movwf   A_TEMP          ;shrani vrednost PORTA
;
        clrf    PORTA           ;poèisti PORTA
        BANK1
        movlw   b'00000001'
        movwf   TRISB           ;RB0 je vhod
        bcf     OPTION_REG, 7   ;omogoèi pull-up upore
        BANK0
        btfss   PORTB, 0
        call    RESET           ;iz reseta se vrnem Z RB0 kot vhodom
;
        BANK1
        clrf    TRISB
        BANK0
;
        movf    A_TEMP, w
        movwf   PORTA           ;povrni stanje PORTA
;
;
;***************************************************************************	
;
;       Pred poveèanjem števcev preverim, èe je gorilec  prižgan
;
;***************************************************************************
;
        btfsc   PORTA, 4        ;ali je gorilec prižgan?  NI DEBOUNCA
        retfie                  ;ne, odpujsaj nazaj
;
;
        incf    COUNTER1        ; nadaljuj kot da ni niè	
        movf    COUNTER1, w
        xorlw   .200            ;ali je 200 (50 ms)?

;       xorlw   .2              ;TEST!!!!



        btfss   STATUS, Z       ;da, poveèaj naslednjega
        retfie                  ;no, I'm done here

        clrf    COUNTER1
        incf    COUNTER2        ;inc next one
        movf    COUNTER2, w
        xorlw   .20             ;is it one second yet
;       xorlw   .2              ; test to make it faster
        btfss   STATUS, Z	
        retfie                  ;no, exit
;
;
        clrf    COUNTER2        ;yes, clear counter
        incf    SECONDS         ;and increment seconds
        movf    SECONDS, w

        xorlw   .60             ;is it one minute yet?
;       xorlw   .2              ;test
        btfss   STATUS, Z
        retfie                  ;no, get out
;
        clrf    SECONDS         ;clear seconds
        incf    MINUTES         ;and inc minutes
        movf    MINUTES, w
        xorlw   .60             ;is it an hour?
;       xorlw   .2              ;test
        btfss   STATUS, Z       ;ja, pojdi poservisirat
        retfie                  ;no, go away
;
;**********************************************************************
;
;       Vrednost, katero hoèemo imeti na displayu, je shranjena v registrih ZGORNJI
;       in VISOKI v obliki štirih BCD vrednosti. Vsakemu displayu pripadajo po 
;       štirje biti v registru. Tukaj inkrementiram te BCD cifre.
;
;************************************************************************


        	
        clrf    COUNTER2        ;TEST!!!!!!!!!!!!!!!!!!!!
        clrf    MINUTES         ;pobriši minute
        incf    MSD, w          ;poveèaj v w
        andlw   b'00001111'     ;maskiraj LSD nibble
        xorlw   .10             ;=10?
        btfsc   STATUS, Z       ;ne, pojdi na naslednjega
        goto    POVECAJ_DRUGEGA
        incf    MSD, f          ;ja, inkrementiraj prvega
        retfie                  ;in pojdi nazaj
;
;
POVECAJ_DRUGEGA
;
        swapf   MSD, w          ;zamenjaj nibble v w
        andlw   b'00001111'     ;maskiraj visoki nibble
        addlw   .1              ;poveèaj
        movwf   MSD
        swapf   MSD, f          ;vzpostavi pravo stanje
        xorlw   .10             ;=10?
        btfsc   STATUS, Z
        goto    NIZKI           ;ja,poveèaj drugi register
        retfie
;
NIZKI
        clrf    MSD             ;poèisti LSD(vse 0)
;
        incf    LSD, w          ;poveèaj
        andlw   b'00001111'     ;maskiraj visoki nibble
        xorlw   .10             ;=10?
        btfsc   STATUS, Z
        goto    POVECAJ_ZADNJEGA;ja, pobriši in pojdi na èetrti display
        incf    LSD, f          ;ne, poveèaj tega in pojdi nazaj
        retfie
;
;
POVECAJ_ZADNJEGA
;
        swapf   LSD, w          ;zamenjaj nibble
        andlw   b'00001111'     ;maskiraj visoke bite
        addlw   .1              ;poveèaj
        movwf   LSD
        swapf   LSD, f  ;=10?
        xorlw   .10
        btfss   STATUS, Z
        retfie                  ;ne, pojdi nazaj
;
        clrf    LSD             ;ja, ponovi celo vajo
        clrf    MSD
;
        retfie

;****************************************************************************
;
;       Rutina osveževanja displaya, pobrana iz Mchipovega
;       AN557
;
;****************************************************************************
;
OSVEZI_DISPLAY                  ;30 ciklov
;
;

        movf    PORTA, w        ;preberi, kateri digit sink je omogoèen
        clrf    PORTA           ;na vhode ta ukaz ne vpliva, ker procesor prebere dejansko stanje
        andlw   b'00001111'     ;obdrži samo pomembne štiri bite
        movwf   SINK            ;in shrani to vrednost
        bsf     SINK, 4         ;pripravi vrednost za levi display
        rrf     SINK, f         ;ugotovi, kateri display je za osvežit
        btfss   STATUS, C       ;c=1?
        bcf     SINK, 3
        btfsc   SINK, 0
        goto    OSVEZI_CETRTEGA
        btfsc   SINK, 1
        goto    OSVEZI_TRETJEGA
        btfsc   SINK, 2
        goto    OSVEZI_DRUGEGA
;
OSVEZI_PRVEGA
        movf    LSD, w
        andlw   b'00001111'
        goto    DISPLAY_OUT
;
OSVEZI_DRUGEGA
;
        swapf   LSD, w  ;obrni bite
        andlw   b'00001111'     ;maskiraj nepotrebne
        goto    DISPLAY_OUT
;
OSVEZI_CETRTEGA
;
        movf    MSD, w
        andlw   b'00001111'     ;maskiraj višje bite
        goto    DISPLAY_OUT
;
OSVEZI_TRETJEGA
;
        swapf   MSD, w
        andlw   b'00001111'
;
DISPLAY_OUT
;
        call    LED_TABELA      ;rezultat bo maska za doloèeno številko
        movwf   PORTB           ;pošlji na izhod
        movf    SINK, w         ;poišèi sink vrednost
        movwf   PORTA           ;in jo pošlji na izhod
        return
;
LED_TABELA
;
        addwf   PCL, f
        retlw   b'00111111'     ;led drive za 0
        retlw   b'00000110'     ;1
        retlw   b'01011011'     ;2
        retlw   b'01001111'     ;3
        retlw   b'01100110'     ;4
        retlw   b'01101101'     ;5
        retlw   b'01111101'     ;6
        retlw   b'00000111'     ;7
        retlw   b'01111111'     ;8
        retlw   b'01100111'     ;9
;       	
        return




	

        end

Questions:

Comments:

Seealso: