;****************************************************************** ; FRECUENCIOMETRO.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 imput 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 | ; ---------------- ------- ;******************************************************************* ; ; Equivalencia de segmentos respecto del harware ; creado. ; ; a=Rb7 pin 13 c=Rb1 pin 7 e=Rb2 pin 8 g=Rb4= pin10 ; b=Rb6 pin 12 d=Rb3 pin 9 f=Rb5 pin 11 LIST p=16C84 ; 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 0xEE ;to be ligthed for each digit retlw 0x42 retlw 0xDC retlw 0xDA retlw 0x72 retlw 0xBA retlw 0xBE retlw 0xC2 retlw 0xFE retlw 0xFA return ; ; ***************************** refresh subroutine: 250 mSec refresh movf unita,0 movwf cifra call segmenti movwf portb bsf porta,3 call ritardo bcf porta,3 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,0 call ritardo bcf porta,0 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 appcmnz 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 appdmn 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