;*******************************************************************
; FMETER.ASM
; 4 digits auto-ranging frequency-meter
; made by Simone Benvenuti & Andrea Geniola
; e-mail:
simone.benvenuti@studenti.ing.unipi.it;
andrea.geniola@studenti.ing.unipi.it;*******************************************************************
;
; A frequency counter which can read frequencies from 0Hz to 50MHz is
; here implemented using a PIC microcontroller. The basic hardware for
; the measurement circuit is shown below: the measure result can be read
; on 4 seven-segments displays in the engeneering notation (A.BC * 10^D).
; The displays are driven using only 11 output pins and 4 transistors;
; during a refresh cycle each digit is turned on for 62.5 usec
; The input frequency is "gated" for a precise duration of time. The gate
; is implemented in software as an accurate delay. In order to minimize
; the error the gate is 1msec wide if the frequency is above 256KHz,
; otherwise is 1msec wide. If the frequency is below 128Hz the digits
; blink to warn that the error can be greater than the device resolution.
; To minimize the energy consumption the PIC turns in sleep mode if no
; input signal is detected for 10sec (this period is software tunable),
; but it wake-up itself immediately when the input is stimulated.
; The program is written for the PIC16C84 but cheaper PICs (as PIC16C61)
; can be used.
;
; ________________
; cents gnd -| RA2 RA1 |- tenths gnd
; esp gnd -| RA3 RA0 |- units gnd
; input -////--+-----| RA4/TOCKI |- ___a___
; 470ohm | -| |- 4 MHz cristal | |
; | gnd-| |- VDD 3..5 Volt f| |b
; input control +-----| RB0 Rb7 |- "g" segment | g |
; "a" segment -| RB1 RB6 |- "f" segment |-----|
; "b" segment -| RB2 RB5 |- "e" segment e| |c
; "c" segment -| RB3 RB4 |- "d" segment | d |
; ---------------- -------
;*******************************************************************
;
LIST p=16C84, wdte=0 ; PIC16C84 is the target processor
;
;status registers:
pc equ 02 ;program counter
porta equ 05 ;I/O register
portb equ 06 ;I/O register
status equ 03 ;status register
tmr equ 01 ;8 bits counter
trisa equ 0x5 ;port "a" direction register
trisb equ 0x6 ;port "b" direction register
intcon equ 0x0B ;interrupt control register
;
;general registers:
unita equ 0x0C ;display units
decimi equ 0x1D ;display tenths
cents equ 0x1E ;display cents
esp equ 0x1F ;display exponent
H_byte equ 0x10 ;high_byte of the read number (N)
L_byte equ 0x11 ;low_byte of the read number (N)
conta_r equ 0x12 ;refresh counter
cifra equ 0x13 ;parameter
U equ 0x14 ;units
D equ 0x15 ;tens
H equ 0x16 ;hundreds
M equ 0x17 ;thousands
DM equ 0x18 ;tens of thousands
CM equ 0x19 ;hundreds of thousands
conta1 equ 0x1A :first counter register
conta2 equ 0x1B ;second counter register
N equ 0x1C ;general register
zeri equ 0x20 ;number of cycles without signal
;
;*************************** MAIN PROGRAM
org 0
start
movlw 0x27
option ;load 00100111 in option register
movlw 0x10
movwf intcon ;enable interrupts
movlw .20
movwf zeri
clrf porta
clrf portb
bsf status,5
movlw 0x10
movwf trisa ;porta<0_3>=output, porta<4>=input
clrf trisb ;potrb<0_7>=output
bcf status,5
movlw 0x08 ;all the segments are switched on
movwf unita ;to test the displays
movwf decimi
movwf cents
movwf esp
movlw .20 ;test refresh (0.5sec wide)
movwf conta_r
loop1 call refresh ;Refresh of the displays
decfsz conta_r
goto loop1
loop5 clrf tmr
bsf status,5
movlw 0x01
movwf trisb ;-
bcf status,5 ; |
movlw .99 ; |
movwf conta1 ; |
un_ms nop ; |
nop ; |
nop ; |
nop ; |
nop ; |
nop ; |- 1msec delay
nop ; |
decfsz conta1 ; |
goto un_ms ; |
nop ; |
nop ; |
nop ; |
nop ; |
nop ; |
bsf status,5 ; |
clrf trisb ;-
bcf status,5
call prescaler ;put the counted number into H_byte-L_byte
movf H_byte
btfss status,2 ;test: H_byte=0
goto cal1_ms ;no
btfsc L_byte,7 ;yes, then test if L_byte<=128
goto cal1_ms ;no
clrf tmr ;yes
bsf status,5
movlw 0x01
movwf trisb ;-
bcf status,5 ; |
movlw .20 ; |
movwf conta_r ; |
loopr call refresh ; |
decfsz conta_r ; |
goto loopr ; |
movlw .4 ; |- 0.5 sec delay ("refresh" is called
movwf N ; | 20 times)
wait decfsz N ; |
goto wait ; |
nop ; |
nop ; |
bsf status,5 ; |
clrf trisb ;-
bcf status,5 ;
call prescaler ;put the counted number into H_byte-L_byte
movf H_byte ;
btfss status,2 ;test if H_byte=0
goto cal05 ;NO
btfsc L_byte,7 ;yes, then test if L_byte<=127
goto cal05 ;NO
movf L_byte
btfss status,2
goto lamp
clrf esp ;no input signal is detected
clrf unita ;clear all the displays and show
clrf decimi ;zero without blinking for "zeri" times
clrf cents
decfsz zeri
goto loop5
bcf intcon,1
sleep
goto loop1
lamp movlw 0x14 ;blinking mode
movwf N
giro call ritardo
decfsz N
goto giro
goto cal05
;
cal1_ms clrf U ;put the right values into the 4 displays
clrf D ;registers and add 3 to the exponent
clrf H ;to multiply by one thousand
clrf M
clrf DM
clrf CM
movlw 0x03
movwf esp
call calcolo
movlw .20
movwf conta_r
goto loop1
;
cal05 clrf U ;multiply the number by 2 and put the
clrf D ;right values into the 4 displays regs
clrf H
clrf M
clrf DM
clrf CM
btfsc H_byte,7
call sessant
bcf status,0
rlf L_byte
rlf H_byte
clrf esp
call calcolo
goto loop5
;
;
; ***************************** Delay subroutine
ritardo movlw .8 ; -
movwf conta1 ; |
nop ; |
beta movlw .0 ; |
movwf conta2 ; |_ 62.5 microsec delay
alfa decfsz conta2 ; |
goto alfa ; |
nop ; |
decfsz conta1 ; |
goto beta ; |
movlw .14 ; |
movwf conta2 ; |
gamma decfsz conta2 ; |
goto gamma ; |
nop ; |
nop ; |
return ; -
; ***************************** choice of the right segments
segmenti nop
movf cifra,0
addwf pc ;return into W the right set of segments
retlw 0x7E ;to be ligthed for each digit
retlw 0x0C
retlw 0xB6
retlw 0x9E
retlw 0xCC
retlw 0xDA
retlw 0xFA
retlw 0x0E
retlw 0xFE
retlw 0xDE
;
; ***************************** refresh subroutine: 250 mSec
refresh movf unita,0
movwf cifra
call segmenti
movwf portb
bsf porta,0
call ritardo
bcf porta,0
movf decimi,0
movwf cifra
call segmenti
movwf portb
bsf porta,1
call ritardo
bcf porta,1
movf cents,0
movwf cifra
call segmenti
movwf portb
bsf porta,2
call ritardo
bcf porta,2
movf esp,0
movwf cifra
call segmenti
movwf portb
bsf porta,3
call ritardo
bcf porta,3
return
; ************** subroutine to extract the value contained in prescaler
prescaler movf tmr,0
movwf H_byte ;make a copy of the counter into H_byte
clrf N
ciclo bcf portb,0
bsf portb,0
bcf portb,0 ;give un edge to the input controller
incf N
movf H_byte,0 ;make a copy of H_byte into W
xorwf tmr,0 ;control if tmr is changed (tmr=H_byte)
btfsc status,2
goto ciclo
movlw 0xFF
movwf L_byte
movf N,0
subwf L_byte ;-|__ L_byte=256-N
incf L_byte ;-|
return
; ****************************** frequency calculation subroutine
calcolo movlw .20
movwf zeri
rlf H_byte
btfss status,0 ;check bit7 of H_byte
goto c_2
movlw 0x03
addwf DM
movlw 0x02
addwf M
movlw 0x07
addwf H
movlw 0x06
addwf D
movlw 0x08
addwf U ;if bit7=1 then add 32768
c_2 rlf H_byte
btfss status,0 ;check bit6 of H_byte
goto c_3
movlw 0x01
addwf DM
movlw 0x06
addwf M
movlw 0x03
addwf H
movlw 0x08
addwf D
movlw 0x04
addwf U ;if bit6=1 then add 16384
c_3 rlf H_byte
btfss status,0 ;check bit5 of H_byte
goto c_4
movlw 0x08
addwf M
movlw 0x01
addwf H
movlw 0x09
addwf D
movlw 0x02
addwf U ;if bit5=1 then add 8192
c_4 rlf H_byte
btfss status,0 ;check bit4 of H_byte
goto c_5
movlw 0x04
addwf M
movlw 0x09
addwf D
movlw 0x06
addwf U ;if bit4=1 then add 4096
c_5 rlf H_byte
btfss status,0 ;check bit3 of H_byte
goto c_6
movlw 0x02
addwf M
movlw 0x04
addwf D
movlw 0x08
addwf U ;if bit3=1 then add 2048
c_6 rlf H_byte
btfss status,0 ;check bit2 of H_byte
goto c_7
movlw 0x01
addwf M
movlw 0x02
addwf D
movlw 0x04
addwf U ;if bit2=1 then add 1024
c_7 rlf H_byte
btfss status,0 ;check bit1 of H_byte
goto c_8
movlw 0x05
addwf H
movlw 0x01
addwf D
movlw 0x02
addwf U ;if bit1=1 then add 512
c_8 rlf H_byte
btfss status,0 ;check bit0 of H_byte
goto c_9
movlw 0x02
addwf H
movlw 0x05
addwf D
movlw 0x06
addwf U ;if bit0=1 then add 256
c_9 rlf L_byte
btfss status,0 ;check bit7 of L_byte
goto c_10
movlw 0x01
addwf H
movlw 0x02
addwf D
movlw 0x08
addwf U ;if bit7=1 then add 128
c_10 rlf L_byte
btfss status,0 ;check bit6 of L_byte
goto c_11
movlw 0x06
addwf D
movlw 0x04
addwf U ;if bit6=1 then add 64
c_11 rlf L_byte
btfss status,0 ;check bit5 of L_byte
goto c_12
movlw 0x03
addwf D
movlw 0x02
addwf U ;if bit5=1 then add 32
c_12 rlf L_byte
btfss status,0 ;check bit4 of L_byte
goto c_13
movlw 0x01
addwf D
movlw 0x06
addwf U ;if bit4=1 then add 16
c_13 rlf L_byte
btfss status,0 ;check bit3 of L_byte
goto c_14
movlw 0x08
addwf U ;if bit3=1 then add 8
c_14 rlf L_byte
btfss status,0 ;check bit2 of L_byte
goto c_15
movlw 0x04
addwf U ;if bit2=1 then add 4
c_15 rlf L_byte
btfss status,0 ;check bit1 of L_byte
goto c_16
movlw 0x02
addwf U ;if bit1=1 then add 2
c_16 rlf L_byte
btfss status,0 ;check bit0 of L_byte
goto c_17
movlw 0x01
addwf U ;if bit0=1 then add 1
c_17 call riporti
movf CM,0 ;the 1st significant digit (MSD) is searched
btfss status,2 ;and a 4th significant digit approximation
goto appcmnz ;is made
movf DM,0
btfss status,2
goto appdmnz
movf M,0
btfsc status,2
goto fuori
movf U,0
movwf N
movlw 0x05
subwf N
btfss status,0
goto fuori
incf D
goto fuori
appdmnz movf D,0 ; DM is the MSD
movwf N
movlw 0x05
subwf N
btfss status,0
goto fuori
incf H
goto fuori
appcmnz movf H,0 ;CM is the MSD
movwf N
movlw 0x05
subwf N
btfss status,0
goto fuori
incf M
fuori call riporti
movf CM,0 ;put the 4th significant digit into
btfss status,2 ;the 4 display registers
goto cmnz ;and put into esp the rigth value
movf DM,0
btfss status,2
goto dmnz
movf M,0
btfss status,2
goto mnz
movlw 0x02 ;U is the MSD
addwf esp
movf H,0
movwf unita
movf D,0
movwf decimi
movf U,0
movwf cents
goto esci
mnz movlw 0x03 ;M is the MSD
addwf esp
movf M,0
movwf unita
movf H,0
movwf decimi
movf D,0
movwf cents
goto esci
dmnz movlw 0x04 ;DM is the MSD
addwf esp
movf DM,0
movwf unita
movf M,0
movwf decimi
movf H,0
movwf cents
goto esci
cmnz movlw 0x05 ;CM is the MSD
addwf esp
movf CM,0
movwf unita
movf DM,0
movwf decimi
movf M,0
movwf cents
esci return
; ****************************** carry subroutine
riporti movf U,0
movwf N
ripu movf N,0 ;check if units>10
movwf U
incf D
movlw 0x0A
subwf N
btfsc status,0
goto ripu
decf D
movf D,0
movwf N
ripd movf N,0 ;check if tens>10
movwf D
incf H
movlw 0x0A
subwf N
btfsc status,0
goto ripd
decf H
movf H,0
movwf N
ripc movf N,0 ;check if hundreds>10
movwf H
incf M
movlw 0x0A
subwf N
btfsc status,0
goto ripc
decf M
movf M,0
movwf N
ripm movf N,0 ;check if thousands>10
movwf M
incf DM
movlw 0x0A
subwf N
btfsc status,0
goto ripm
decf DM
movf DM,0
movwf N
ripdm movf N,0 ;check if tens of thousands>10
movwf DM
incf CM
movlw 0x0A
subwf N
btfsc status,0
goto ripdm
decf CM
return
; ****************************** subroutine to add 64K
sessant movlw 0x06
addwf DM
movlw 0x05
addwf M
movlw 0x05
addwf H
movlw 0x03
addwf D
movlw 0x06
addwf U ;add 65536
return
END
;----------------