;шъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъш
;ш CONTENTS : Simple low-cost 7-digit frequency meter using a PIC16F84    ш
;ш COPYRIGHT: Peter Halicky  OM3CPH                                       ш
;ш AUTHORS  : Peter Halicky OM3CPH & Peter Halicky Jr., OM2PH ex OM2APH   ш
;ш PCB      : Tibor Madarasz OM2ATM                                       ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш E-Mail: halicky@minv.sk     or om3cph@oe3xbs.aut.eu                    ш
;ш         peto-h@writeme.com  or om2ph@om0pbm.svk.eu                     ш
;ш                                                                        ш
;ш Bratislava, Slovakia, February, 1998, debugged & revised February, 2000ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш This is 7-digit frequency meter counting up to 35 MHz. The decimal     ш
;ш point is after MHz digit, but can be set at any position. Two dots can ш
;ш be set too (timing formula will change!).                              ш
;ш                                                                        ш
;ш Power consumption with calculator display: 2.5V/9mA, 3V/13mA, 5V/35mA. ш
;ш                                                                        ш
;ш Hardware is very simple:                                               ш
;ш                                                                        ш
;ш It contains     : PIC 16F84                                            ш
;ш                   4051 (BCD -> 1 of 8 decoder)                         ш
;ш                   8 NPN low power Si transistors,                      ш
;ш                   7-digit calculator display (common cathode),         ш
;ш                   some resistors, capacitors and 2 switching diodes    ш
;ш                                                                        ш
;ш Note:                                                                  ш
;ш "Calculator display" means (say) 7 digit LED multiplexed display.      ш
;ш Both common cathode and common anode can be used. Software is written  ш
;ш for both common cathode and common anode display. For common anode     ш
;ш displays it requires very slight software (uncomment what is commented ш
;ш and comment what isn't...;-) and hardware modification (switching      ш
;ш transistors are PNP instead NPN, ther emiters are connected with +5V   ш
;ш and also pin No.3 of 4051 should be grounded).                         ш
;ш                                                                        ш
;ш PIC is used as 3 byte counter. If it counts 0.1 s maximum measured     ш
;ш frequency is FF FF FF, e. g. 167.77215 MHz (theoretically).            ш
;ш                                                                        ш
;ш In reality the maximum measured frequency will not exceed 50 MHz       ш
;ш what is maximum input frequency of PIC precounter. But real one is     ш
;ш around 27 MHz and with 1/6 of 74HC14 (Schmitt trigger) up to 38 MHz.   ш
;ш                                                                        ш
;ш                      за©        за©                                    ш
;ш                      Ё Ё        Ё Ё                                    ш
;ш          Ё       470 Ё Ё    470 Ё Ё                                    ш
;ш          Ё           Ё Ё        Ё Ё                                    ш
;ш          Ё           юбы здддд© юбы                                    ш
;ш      RA4 ц© зддддддд© Ё  Ё    Ё  Ё                                     ш
;ш      RA3 цадЄ 470   цдадOЁ    цддад\                                   ш
;ш      RA2 Ё  юддддддды    Ё    Ё     \|___                              ш
;ш    дддддды               юдддды     /|                                 ш
;ш                                    V                                   ш
;ш                                    |                                   ш
;ш                                   ---                                  ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш                                                                        ш
;ш The scale uses internal prescaler of PIC as low byte of counter,       ш
;ш TMR0 as middle byte and some register as high byte of counter. The     ш
;ш software DOESN'T read anything from any input port. RA4 is used as     ш
;ш prescaler input.                                                       ш
;ш                                                                        ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш                                                                        ш
;ш Measuring period is 100 000 us.                                        ш
;ш Procesor cycle is T = 4/Fx us   [MHz], fx is Xtal frequency            ш
;ш                                                                        ш
;ш Number of procesor cycles per measuring period:                        ш
;ш                                                                        ш
;ш        N = 100 000/T procesor cycles                                   ш
;ш        N = Fx * 100 000/4 = 25 000 * Fx                                ш
;ш                                                                        ш
;ш The main steps of measuring period:                                    ш
;ш                                                                        ш
;ш        1. start measurement,                                           ш
;ш        2. precode decimal value of digit to segments,                  ш
;ш        3. if it's 5th digit set decimal point,                         ш
;ш        4. output to PortB,                                             ш
;ш        5. output digit number to PortA                                 ш
;ш           (numbers from left to right are 6543210),                    ш
;ш        6. test TMR0 overflow bite, if YES increase TimerH,             ш
;ш        7. leave digit to light,                                        ш
;ш        8. increase digit number,                                       ш
;ш        9. if <7 goto 2,                                                ш
;ш       10. else zero digit number, decrease counter and goto 2,         ш
;ш       11. stop measurement,                                            ш
;ш       12. shift out precounter content,                                ш
;ш       13. in case of digital scale add/substract RF,                   ш
;ш       14. precode 3-byte value into 7 decimal numbers,                 ш
;ш       15. goto 1                                                       ш
;ш                                                                        ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш                                                                        ш
;ш Total timing formula:                                                  ш
;ш                                                                        ш
;ш N = 25 000 * Fx = 60*[7*(37 + 3*T1) + 6 + 3*T2] + 6 + 9*T3 + Z         ш
;ш                                                                        ш
;ш where T1,T2,T3 are initial values of timing loops,                     ш
;ш       Z        are additional tunig NOPs,                              ш
;ш       Fx       Xtal frequency in MHz.                                  ш
;ш                                                                        ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш Some ideas were taken from "Simple low-cost digital frequency meter    ш
;ш                             using a PIC 16C54" (frqmeter.asm)          ш
;ш                             written by James Hutchby, MadLab Ltd. 1996 ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш                                                                        ш
;ш This software is free for private usage. It was created for HAM radio  ш
;ш community members. Commercial exploatation is allowed only with        ш
;ш permission of authors.                                                 ш
;ш                                                                        ш
;шээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээш

;       include <p16c84.inc>
       include <p16f84.inc>

;дддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд

Index       equ         0Ch         ; dummy register
Count       equ         0Dh         ; inkremental register
Help        equ         0Eh         ; dummy register

LED0        equ         0Fh
LED1        equ        010h
LED2        equ        011h
LED3        equ        012h
LED4        equ        013h
LED5        equ        014h
LED6        equ        015h
LED7        equ        016h

TimerH      equ        017h         ; higher byte of SW counter

LowB        equ        018h         ; low byte of resulted frequency
MidB        equ        019h         ; middle byte of resulted frequency
HigB        equ        01Ah         ; high byte of resulted frequency
Temp        equ        01Bh         ; temporary register
HIndex      equ        01Ch         ; index register
LEDIndex    equ        01Dh         ; LED pointer

;дддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд
                                    ; timing loop values
                                    ; must be from 1 to 255!!!
T1          equ        .185         ; 1st timer loop
T2          equ        .1           ; 2nd timer loop
T3          equ        .98          ; 3rd timer loop
                                    ; values for 10 MHz Xtal

;дддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд

            org        0

Start       clrf       Index
            clrf       LEDIndex

            clrf       LED0
            clrf       LED1
            clrf       LED2
            clrf       LED3
            clrf       LED4
            clrf       LED5
            clrf       LED6
            clrf       LED7

            clrf       LowB
            clrf       MidB
            clrf       HigB

            bsf        STATUS,RP0

            movlw      b'00010000' ; RA0..RA3 outputs
            movwf      TRISA       ; RA4 input

            movlw      b'00000000' ; RB0..RB7 outputs
            movwf      TRISB

            clrwdt                 ;
            movlw      b'00100111' ; Prescaler -> TMR0,
            movwf      OPTION_REG  ; 1:256, rising edge

            bcf        STATUS,RP0  ;

            goto       Go          ; line 370

;иммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм╩
;╨ The block of subroutines and constants tables                           ╨
;хммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм╪

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё 3 byte substraction of the constant from the table, it sets carry       Ё
;Ё if result is negative                                                   Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

Subc24      clrf       Temp        ; it will temporary save CF
            movf       Index,W     ; pointer to low byte of constant
            movwf      HIndex      ; W -> HIndex
            call       DecTable    ; W returned with low byte of constant
            bsf        STATUS,C    ; set CF
            subwf      LowB,F      ; LowB - W -> LowB
                                   ; if underflow -> C=0
            btfsc      STATUS,C
            goto       Step1
            bsf        STATUS,C
            movlw      1
            subwf      MidB,F      ; decrement MidB
                                   ; if underflow -> C=0
            btfsc      STATUS,C
            goto       Step1

            bsf        STATUS,C
            movlw      1
            subwf      HigB,F      ; decrement HigB
            btfsc      STATUS,C    ; if underflow -> C=0
            goto       Step1
            bsf        Temp,C      ; set C

Step1       decf       HIndex,F
            movf       HIndex,W    ; pointer to middle byte of const
            call       DecTable
            bsf        STATUS,C
            subwf      MidB,F      ; MidB - W -> MidB
            btfsc      STATUS,C    ; if underflow -> C=0
            goto       Step2
            bsf        STATUS,C
            movlw      1
            subwf      HigB,1      ; decrement HigB
            btfsc      STATUS,C    ; if underflow -> C=0
            goto       Step2
            bsf        Temp,C      ; set C

Step2       decf       HIndex,F
            movf       HIndex,W    ; pointer to middle byte of constatnt
            call       DecTable
            bsf        STATUS,C
            subwf      HigB,F      ; HigB - W -> HigB
            btfsc      STATUS,C    ; if underflow -> C=0
            goto       ClearCF
            bsf        STATUS,C
            goto       SubEnd
ClearCF     rrf        Temp,C      ; C -> STATUS
SubEnd      retlw      0

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё 3 byte addition of the constant from the table, it sets carry if        Ё
;Ё result overflows                                                        Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

Addc24      clrf       Temp        ; register for temporary storage of CF
            movf       Index,W     ; pointer to lower byte of const into W
            movwf      HIndex      ; save it into HIndex
            call       DecTable    ; W contains low byte of const
            bcf        STATUS,C    ; clear C
            addwf      LowB,1      ; W + LowB -> LowB
            btfss      STATUS,C    ; test overflow
            goto       Add2
            bcf        STATUS,C    ; clear C
            movlw      1
            addwf      MidB,F      ; increment MidB
            btfss      STATUS,C
            goto       Add2
            bcf        STATUS,C
            movlw      1
            addwf      HigB,F      ; increment HigB
            btfss      STATUS,C    ; test overflow
            goto       Add2
            bsf        Temp,C      ; store C

Add2        decf       HIndex,F    ; pointer to middle byte into W
            movf       HIndex,W
            call       DecTable
            bcf        STATUS,C
            addwf      MidB,1      ; W + MidB -> MidB
            btfss      STATUS,C
            goto       Add3
            bcf        STATUS,C    ; clear C
            movlw      1
            addwf      HigB,1      ; increment HigB
            btfss      STATUS,C
            goto       Add3
            bsf        Temp,C

Add3        decf       HIndex,F    ; pointer to higher byte into W
            movf       HIndex,W
            call       DecTable
            bsf        STATUS,C
            addwf      HigB,F      ; W + HigB -> HigB,
            btfss      STATUS,C
            goto       ClarCF
            bsf        STATUS,C
            goto       AddEnd
ClarCF      rrf        Temp,C      ; C -> STATUS

AddEnd      retlw      0

;здддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё Tables of 3-byte constants                                             Ё
;цддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддЄ
;Ё Table of decades                                                       Ё
;юдддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

DecTable    addwf      PCL,F       ; W + PCL -> PCL
            retlw      0           ; 10
            retlw      0           ;
            retlw      0Ah         ;

            retlw      0           ; 100
            retlw      0           ;
            retlw      064h        ;

            retlw      0           ; 1 000
            retlw      03h         ;
            retlw      0E8h        ;

            retlw      0           ; 10 000
            retlw      027h        ;
            retlw      010h        ;

            retlw      01h         ; 100 000
            retlw      086h        ;
            retlw      0A0h        ;

            retlw      0Fh         ; 1 000 000
            retlw      042h        ;
            retlw      040h        ;

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё Table for conversion BCD -> 7 segments                                Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

;LEDTable    addwf      PCL,F        ; W + PCL -> PCL
;            retlw      b'00111111' ; ..FEDCBA = '0'
;            retlw      b'00000110' ; .....CB. = '1'
;            retlw      b'01011011' ; .G.ED.BA = '2'
;            retlw      b'01001111' ; .G..DCBA = '3'
;            retlw      b'01100110' ; .GF..CB. = '4'
;            retlw      b'01101101' ; .GF.DC.A = '5'
;            retlw      b'01111101' ; .GFEDC.A = '6'
;            retlw      b'00000111' ; .....CBA = '7'
;            retlw      b'01111111' ; .GFEDCBA = '8'
;            retlw      b'01100111' ; .GF..CBA = '9'
;            retlw      b'10000000' ; H....... = '.'

;It follows COMMON ANODE data table

LEDTable    addwf      PCL,F        ; W + PCL -> PCL
            retlw      b'11000000' ; ..FEDCBA = '0'
            retlw      b'11111001' ; .....CB. = '1'
            retlw      b'10100100' ; .G.ED.BA = '2'
            retlw      b'10110000' ; .G..DCBA = '3'
            retlw      b'10011001' ; .GF..CB. = '4'
            retlw      b'10010010' ; .GF.DC.A = '5'
            retlw      b'10000010' ; .GFEDC.A = '6'
            retlw      b'11111000' ; .....CBA = '7'
            retlw      b'10000000' ; .GFEDCBA = '8'
            retlw      b'10011000' ; .GF..CBA = '9'
            retlw      b'01111111' ; H....... = '.'

;шъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъш
;ш The main cycle entry point                                             ш
;шддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддш
;ш Routine for conversion of 3-byte number into 7 digits                  ш
;шээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээш

Go          bsf        STATUS,RP0
            movlw      b'00000000'
            movwf      TRISB
            bcf        STATUS,RP0

            movlw      6*3-1       ; pointer to dec. table
            movwf      Index       ; 6*3-1 -> Index

            movlw      9           ; maximum of substractions
            movwf      Count       ; 9 -> Count

            clrf       Help

            movlw      6
            movwf      LEDIndex

Divide      call       Subc24      ; substract untill result is negative,
            btfsc      STATUS,C    ; add last substracted number
            goto       Add24       ; next digit
            incf       Help,F
            decf       Count,F
            btfss      STATUS,Z
            goto       Divide
            movlw      3
            subwf      Index,F
            goto       Next

Add24       call       Addc24
            movlw      3
            subwf      Index,F

Next        movlw      9
            movwf      Count
            movlw      LED1        ; LED1 -> W
            addwf      LEDIndex,W  ; LED1 + LEDIndex -> W
            movwf      Temp
            decf       Temp,F      ; LEDIndex+LED1-1 -> TEMP
            movf       Temp,W

            movwf      FSR         ; W -> FSR
            movf       Help,W      ; Help -> W
            clrf       Help        ; save result at LEDx
            movwf      INDF        ; W -> LED(6..1)
            decf       LEDIndex,F

            movlw      1
            addwf      Index,W
            btfss      STATUS,Z
            goto       Divide

            movf       LowB,W
            movwf      LED0        ; the rest -> LED0

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё Registers LED0..LED6 are filled with values                           Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

            clrf       TimerH

            clrf       TMR0
            nop
            nop

            clrf       LEDIndex

            movlw      .60         ; set initial counter value
            movwf      Index       ; 60 -> Index

            clrf       INTCON      ; global INT disable, TMR0 INT disable
                                   ; clear TMR0 overflow bite

;иммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм╩
;╨ Start of the measurement:  RA3 + RA4 set input                      ╨
;хммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм╪

            movlw      b'00010000' ; all ports set L, RA4 set H
            movwf      PORTA

            bsf        STATUS,RP0
            movlw      b'00011000' ; RA0..RA2 output, RA3, RA4 input
            movwf      TRISA
            bcf        STATUS,RP0

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё 7-step cycle of digits                                                Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

LEDCycle    movlw      LED0
            addwf      LEDIndex,W  ; LED1 + LEDIndex -> W

            movwf      FSR         ; W -> FSR
            movf       INDF,W      ; LED(0..6) -> W
            call       LEDTable    ; W contains segments

            movwf      Temp        ; test for decimal point
            movlw      5
            bsf        STATUS,Z
            subwf      LEDIndex,W
            btfss      STATUS,Z
            goto       NoDot
;            bsf        Temp,7      ; common cathode....
            bcf        Temp,7      ; common anode....

NoDot       movf       Temp,W
            movwf      PORTB       ; segments -> PORTB

            movf       LEDIndex,W  ; LEDIndex -> W
            nop
            movwf      PORTA       ; digit number -> PORTA

;ддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд

            btfss      INTCON,2    ; Test for TMR0 overflow
            goto       DoNothing
            incf       TimerH,F    ; YES! Increment SW counter
            bcf        INTCON,2    ; clear overflow bite
            goto       O_K

DoNothing   nop
            nop
            nop

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё The first timing loop 2+3*T1 procesor cycles                          Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

O_K         movlw      T1
            movwf      Temp

Pause       decfsz     Temp,F
            goto       Pause
            nop

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё The end of one digit processing                                       Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

            incf       LEDIndex,F
            movlw      7           ; is 7th?
            bcf        STATUS,Z
            subwf      LEDIndex,W
            btfss      STATUS,Z
            goto       LEDCycle    ; next digit
            nop

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё The second timing loop 2+3*T2 procesor cycles                         Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

            movlw      T2
            movwf      Temp

Again       decfsz     Temp,F
            goto       Again
            nop

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё The end of one 7-digits processing                                    Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

            clrf       LEDIndex
            decfsz     Index,F
            goto       LEDCycle    ; next 7 * LED
            nop

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё The third timing loop 2+9*T3+Z procesor cycles                        Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

            movlw      T3
            movwf      Temp

EndPause    btfss      INTCON,2    ; Final test for TMR0 overflow
            goto       Nothing2Do
            incf       TimerH,F
            bcf        INTCON,2
            goto       Nx

Nothing2Do  nop
            nop
            nop

Nx          decfsz     Temp,F
            goto       EndPause
            nop

            nop                    ; Z times NOP  (0..8)
;           nop
;           nop
;           nop

;иммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм╩
;╨ Stop of the measurement:  RA3 set output RA4 set input              ╨
;хммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм╪

;            clrw                   ; For common cathode
           movlw      b'11111111' ; For common anode

            movwf      PORTB
            movlw      b'00010000' ; RA0..RA3 = 0
            movwf      PORTA       ; W -> PORTA

            bsf        STATUS,RP0
            movlw      b'00010000' ; RA0..RA3 output
            movwf      TRISA       ; RA4 input
            bcf        STATUS,RP0

            btfsc      INTCON,2    ; really final check
            incf       TimerH,F
            bcf        INTCON,2

;зддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд©
;Ё Analyse precounter and store counted value in registers               Ё
;юддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддды

            movf       TMR0,W
            movwf      MidB        ; TMR0 -> MidB

            movf       TimerH,W
            movwf      HigB        ; TimerH -> HigB

            clrf       Temp

CountIt     incf       Temp,F
            bsf        PORTA,3     ; _| false impulz
            bcf        PORTA,3     ;    |_

            bcf        INTCON,2
            movf       TMR0,W      ; actual TMR0 -> W
            bcf        STATUS,Z
            subwf      MidB,W
            btfsc      STATUS,Z
            goto       CountIt
            incf       Temp,F
            comf       Temp,F
            incf       Temp,F
            incf       Temp,W

            movwf      LowB

;дддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд

            goto       Go

;шъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъъш
;ш The main cycle end                                                     ш
;шээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээээш

            end

